0030507: Visualization - introduce AIS_ViewController
[occt.git] / src / ViewerTest / ViewerTest_ViewerCommands.cxx
1 // Created on: 1998-09-01
2 // Created by: Robert COUBLANC
3 // Copyright (c) 1998-1999 Matra Datavision
4 // Copyright (c) 1999-2014 OPEN CASCADE SAS
5 //
6 // This file is part of Open CASCADE Technology software library.
7 //
8 // This library is free software; you can redistribute it and/or modify it under
9 // the terms of the GNU Lesser General Public License version 2.1 as published
10 // by the Free Software Foundation, with special exception defined in the file
11 // OCCT_LGPL_EXCEPTION.txt. Consult the file LICENSE_LGPL_21.txt included in OCCT
12 // distribution for complete text of the license and disclaimer of any warranty.
13 //
14 // Alternatively, this file may be used under the terms of Open CASCADE
15 // commercial license or contractual agreement.
16
17 #include <OpenGl_GlCore20.hxx>
18 #include <ViewerTest.hxx>
19
20 #include <AIS_AnimationCamera.hxx>
21 #include <AIS_AnimationObject.hxx>
22 #include <AIS_CameraFrustum.hxx>
23 #include <AIS_ColorScale.hxx>
24 #include <AIS_InteractiveContext.hxx>
25 #include <AIS_ListOfInteractive.hxx>
26 #include <AIS_ListIteratorOfListOfInteractive.hxx>
27 #include <AIS_Manipulator.hxx>
28 #include <AIS_Shape.hxx>
29 #include <Aspect_DisplayConnection.hxx>
30 #include <Aspect_Grid.hxx>
31 #include <Aspect_TypeOfLine.hxx>
32 #include <Draw.hxx>
33 #include <Draw_Appli.hxx>
34 #include <Draw_Interpretor.hxx>
35 #include <Draw_ProgressIndicator.hxx>
36 #include <gp_Dir.hxx>
37 #include <gp_Pln.hxx>
38 #include <gp_Pnt.hxx>
39 #include <Graphic3d_ArrayOfPolylines.hxx>
40 #include <Graphic3d_AspectFillArea3d.hxx>
41 #include <Graphic3d_AspectMarker3d.hxx>
42 #include <Graphic3d_ClipPlane.hxx>
43 #include <Graphic3d_GraduatedTrihedron.hxx>
44 #include <Graphic3d_NameOfTextureEnv.hxx>
45 #include <Graphic3d_Texture2Dmanual.hxx>
46 #include <Graphic3d_TextureEnv.hxx>
47 #include <Graphic3d_TextureParams.hxx>
48 #include <Graphic3d_TypeOfTextureFilter.hxx>
49 #include <Image_AlienPixMap.hxx>
50 #include <Image_Diff.hxx>
51 #include <Image_VideoRecorder.hxx>
52 #include <Message_ProgressSentry.hxx>
53 #include <NCollection_DataMap.hxx>
54 #include <NCollection_List.hxx>
55 #include <NCollection_Vector.hxx>
56 #include <OSD.hxx>
57 #include <OSD_Timer.hxx>
58 #include <OpenGl_GraphicDriver.hxx>
59 #include <Prs3d_ShadingAspect.hxx>
60 #include <Prs3d_Drawer.hxx>
61 #include <Prs3d_LineAspect.hxx>
62 #include <Prs3d_Root.hxx>
63 #include <Prs3d_Text.hxx>
64 #include <Select3D_SensitivePrimitiveArray.hxx>
65 #include <TColStd_HSequenceOfAsciiString.hxx>
66 #include <TColStd_SequenceOfInteger.hxx>
67 #include <TColStd_HSequenceOfReal.hxx>
68 #include <TColgp_Array1OfPnt2d.hxx>
69 #include <TColStd_MapOfAsciiString.hxx>
70 #include <ViewerTest_AutoUpdater.hxx>
71 #include <ViewerTest_EventManager.hxx>
72 #include <ViewerTest_DoubleMapOfInteractiveAndName.hxx>
73 #include <ViewerTest_DoubleMapIteratorOfDoubleMapOfInteractiveAndName.hxx>
74 #include <ViewerTest_CmdParser.hxx>
75 #include <ViewerTest_V3dView.hxx>
76 #include <V3d_AmbientLight.hxx>
77 #include <V3d_DirectionalLight.hxx>
78 #include <V3d_PositionalLight.hxx>
79 #include <V3d_SpotLight.hxx>
80
81 #include <tcl.h>
82
83 #include <cstdlib>
84
85 #if defined(_WIN32)
86   #include <WNT_WClass.hxx>
87   #include <WNT_Window.hxx>
88 #elif defined(__APPLE__) && !defined(MACOSX_USE_GLX)
89   #include <Cocoa_Window.hxx>
90 #else
91   #include <Xw_Window.hxx>
92   #include <X11/Xlib.h> /* contains some dangerous #defines such as Status, True etc. */
93   #include <X11/Xutil.h>
94   #include <tk.h>
95 #endif
96
97 //==============================================================================
98 //  VIEWER GLOBAL VARIABLES
99 //==============================================================================
100
101 Standard_IMPORT Standard_Boolean Draw_VirtualWindows;
102 Standard_IMPORT Standard_Boolean Draw_Interprete (const char* theCommand);
103
104 Standard_EXPORT int ViewerMainLoop(Standard_Integer , const char** argv);
105 extern ViewerTest_DoubleMapOfInteractiveAndName& GetMapOfAIS();
106
107 #if defined(_WIN32)
108 static Handle(WNT_Window)& VT_GetWindow() {
109   static Handle(WNT_Window) WNTWin;
110   return WNTWin;
111 }
112 #elif defined(__APPLE__) && !defined(MACOSX_USE_GLX)
113 static Handle(Cocoa_Window)& VT_GetWindow()
114 {
115   static Handle(Cocoa_Window) aWindow;
116   return aWindow;
117 }
118 extern void ViewerTest_SetCocoaEventManagerView (const Handle(Cocoa_Window)& theWindow);
119 extern void GetCocoaScreenResolution (Standard_Integer& theWidth, Standard_Integer& theHeight);
120
121 #else
122 static Handle(Xw_Window)& VT_GetWindow(){
123   static Handle(Xw_Window) XWWin;
124   return XWWin;
125 }
126
127 static void VProcessEvents(ClientData,int);
128 #endif
129
130 static Handle(Aspect_DisplayConnection)& GetDisplayConnection()
131 {
132   static Handle(Aspect_DisplayConnection) aDisplayConnection;
133   return aDisplayConnection;
134 }
135
136 static void SetDisplayConnection (const Handle(Aspect_DisplayConnection)& theDisplayConnection)
137 {
138   GetDisplayConnection() = theDisplayConnection;
139 }
140
141 NCollection_DoubleMap <TCollection_AsciiString, Handle(V3d_View)> ViewerTest_myViews;
142 static NCollection_DoubleMap <TCollection_AsciiString, Handle(AIS_InteractiveContext)>  ViewerTest_myContexts;
143 static NCollection_DoubleMap <TCollection_AsciiString, Handle(Graphic3d_GraphicDriver)> ViewerTest_myDrivers;
144 static OpenGl_Caps ViewerTest_myDefaultCaps;
145
146 static void OSWindowSetup();
147
148 static struct
149 {
150   Quantity_Color FlatColor;
151   Quantity_Color GradientColor1;
152   Quantity_Color GradientColor2;
153   Aspect_GradientFillMethod FillMethod;
154 } ViewerTest_DefaultBackground = { Quantity_NOC_BLACK, Quantity_NOC_BLACK, Quantity_NOC_BLACK, Aspect_GFM_NONE };
155
156 //==============================================================================
157 //  EVENT GLOBAL VARIABLES
158 //==============================================================================
159
160 Standard_Boolean TheIsAnimating = Standard_False;
161
162 namespace
163 {
164
165   //! Checks if some set is a subset of other set
166   //! @tparam TheSuperSet the type of the superset
167   //! @tparam TheSubSet the type of the subset
168   //! @param theSuperSet the superset
169   //! @param theSubSet the subset to be checked
170   //! @return true if the superset includes subset, or false otherwise
171   template <typename TheSuperSet, typename TheSubSet>
172   static bool includes (const TheSuperSet& theSuperSet, const TheSubSet& theSubSet)
173   {
174     return std::includes (theSuperSet.begin(), theSuperSet.end(), theSubSet.begin(), theSubSet.end());
175   }
176
177   //! A variable set of keys for command-line options.
178   //! It includes a set of mandatory keys and a set of all possible keys.
179   class CommandOptionKeyVariableSet
180   {
181   public:
182     //! Default constructor
183     CommandOptionKeyVariableSet()
184     {
185     }
186
187     //! Constructor
188     //! @param theMandatoryKeySet the set of the mandatory option keys
189     //! @param theAdditionalKeySet the set of additional options that could be omitted
190     CommandOptionKeyVariableSet (
191       const ViewerTest_CommandOptionKeySet& theMandatoryKeySet,
192       const ViewerTest_CommandOptionKeySet& theAdditionalKeySet = ViewerTest_CommandOptionKeySet())
193     : myMandatoryKeySet (theMandatoryKeySet)
194     {
195       std::set_union (theMandatoryKeySet.begin(),
196                       theMandatoryKeySet.end(),
197                       theAdditionalKeySet.begin(),
198                       theAdditionalKeySet.end(),
199                       std::inserter (myFullKeySet, myFullKeySet.begin()));
200     }
201
202     //! Checks if the set of option keys fits to the current variable set (it must contain all mandatory keys
203     //! and be contained in the full key set)
204     //! @param theCheckedKeySet the set of option keys to be checked
205     bool IsInSet (const ViewerTest_CommandOptionKeySet& theCheckedKeySet) const
206     {
207       return includes (theCheckedKeySet, myMandatoryKeySet) && includes (myFullKeySet, theCheckedKeySet);
208     }
209
210   private:
211     //! A set of mandatory command-line option keys
212     ViewerTest_CommandOptionKeySet myMandatoryKeySet;
213
214     //! A full set of command-line option keys (includes mandatory and additional option keys)
215     ViewerTest_CommandOptionKeySet myFullKeySet;
216   };
217
218   //! Gets some code by its name
219   //! @tparam TheCode the type of a code to be found
220   //! @param theCodeNameMap the map from code names to codes
221   //! @param theCodeName the name of a code to be found
222   //! @param theCode the code to be found
223   //! @return true if a code is found, or false otherwise
224   template <typename TheCode>
225   static bool getSomeCodeByName (const std::map<TCollection_AsciiString, TheCode>& theCodeNameMap,
226                                  TCollection_AsciiString                           theCodeName,
227                                  TheCode&                                          theCode)
228   {
229     theCodeName.LowerCase();
230     const typename std::map<TCollection_AsciiString, TheCode>::const_iterator aCodeIterator = theCodeNameMap.find (
231       theCodeName);
232     if (aCodeIterator == theCodeNameMap.end())
233     {
234       return false;
235     }
236     theCode = aCodeIterator->second;
237     return true;
238   }
239
240   // Defines possible commands related to background changing
241   enum BackgroundCommand
242   {
243     BackgroundCommand_Main,         //!< The main command that manages other commands through options
244     BackgroundCommand_Image,        //!< Sets an image as a background
245     BackgroundCommand_ImageMode,    //!< Changes a background image mode
246     BackgroundCommand_Gradient,     //!< Sets a gradient as a background
247     BackgroundCommand_GradientMode, //!< Changes a background gradient mode
248     BackgroundCommand_Color,        //!< Fills background with a specified color
249     BackgroundCommand_Default       //!< Sets the background default color or gradient
250   };
251
252   //! Map from background command names to its codes
253   typedef std::map<TCollection_AsciiString, BackgroundCommand> BackgroundCommandNameMap;
254
255   //! Creates a map from background command names to its codes
256   //! @return a map from background command names to its codes
257   static BackgroundCommandNameMap createBackgroundCommandNameMap()
258   {
259     BackgroundCommandNameMap aBackgroundCommandNameMap;
260     aBackgroundCommandNameMap["vbackground"]    = BackgroundCommand_Main;
261     aBackgroundCommandNameMap["vsetbg"]         = BackgroundCommand_Image;
262     aBackgroundCommandNameMap["vsetbgmode"]     = BackgroundCommand_ImageMode;
263     aBackgroundCommandNameMap["vsetgradientbg"] = BackgroundCommand_Gradient;
264     aBackgroundCommandNameMap["vsetgrbgmode"]   = BackgroundCommand_GradientMode;
265     aBackgroundCommandNameMap["vsetcolorbg"]    = BackgroundCommand_Color;
266     aBackgroundCommandNameMap["vsetdefaultbg"]  = BackgroundCommand_Default;
267     return aBackgroundCommandNameMap;
268   }
269
270   //! Gets a background command by its name
271   //! @param theBackgroundCommandName the name of the background command
272   //! @param theBackgroundCommand the background command to be found
273   //! @return true if a background command is found, or false otherwise
274   static bool getBackgroundCommandByName (const TCollection_AsciiString& theBackgroundCommandName,
275                                           BackgroundCommand&             theBackgroundCommand)
276   {
277     static const BackgroundCommandNameMap THE_BACKGROUND_COMMAND_NAME_MAP = createBackgroundCommandNameMap();
278     return getSomeCodeByName (THE_BACKGROUND_COMMAND_NAME_MAP, theBackgroundCommandName, theBackgroundCommand);
279   }
280
281   //! Map from background image fill method names to its codes
282   typedef std::map<TCollection_AsciiString, Aspect_FillMethod> BackgroundImageFillMethodNameMap;
283
284   //! Creates a map from background image fill method names to its codes
285   //! @return a map from background image fill method names to its codes
286   static BackgroundImageFillMethodNameMap createBackgroundImageFillMethodNameMap()
287   {
288     BackgroundImageFillMethodNameMap aBackgroundImageFillMethodNameMap;
289     aBackgroundImageFillMethodNameMap["none"]     = Aspect_FM_NONE;
290     aBackgroundImageFillMethodNameMap["centered"] = Aspect_FM_CENTERED;
291     aBackgroundImageFillMethodNameMap["tiled"]    = Aspect_FM_TILED;
292     aBackgroundImageFillMethodNameMap["stretch"]  = Aspect_FM_STRETCH;
293     return aBackgroundImageFillMethodNameMap;
294   }
295
296   //! Gets a background image fill method by its name
297   //! @param theBackgroundImageFillMethodName the name of the background image fill method
298   //! @param theBackgroundImageFillMethod the background image fill method to be found
299   //! @return true if a background image fill method is found, or false otherwise
300   static bool getBackgroundImageFillMethodByName (const TCollection_AsciiString& theBackgroundImageFillMethodName,
301                                                   Aspect_FillMethod&             theBackgroundImageFillMethod)
302   {
303     static const BackgroundImageFillMethodNameMap THE_BACKGROUND_IMAGE_FILL_METHOD_NAME_MAP =
304       createBackgroundImageFillMethodNameMap();
305     return getSomeCodeByName (THE_BACKGROUND_IMAGE_FILL_METHOD_NAME_MAP,
306                               theBackgroundImageFillMethodName,
307                               theBackgroundImageFillMethod);
308   }
309
310   //! Map from background gradient fill method names to its codes
311   typedef std::map<TCollection_AsciiString, Aspect_GradientFillMethod> BackgroundGradientFillMethodNameMap;
312
313   //! Creates a map from background gradient fill method names to its codes
314   //! @return a map from background gradient fill method names to its codes
315   static BackgroundGradientFillMethodNameMap createBackgroundGradientFillMethodNameMap()
316   {
317     BackgroundGradientFillMethodNameMap aBackgroundGradientFillMethodNameMap;
318     aBackgroundGradientFillMethodNameMap["none"]       = Aspect_GFM_NONE;
319     aBackgroundGradientFillMethodNameMap["hor"]        = Aspect_GFM_HOR;
320     aBackgroundGradientFillMethodNameMap["horizontal"] = Aspect_GFM_HOR;
321     aBackgroundGradientFillMethodNameMap["ver"]        = Aspect_GFM_VER;
322     aBackgroundGradientFillMethodNameMap["vertical"]   = Aspect_GFM_VER;
323     aBackgroundGradientFillMethodNameMap["diag1"]      = Aspect_GFM_DIAG1;
324     aBackgroundGradientFillMethodNameMap["diagonal1"]  = Aspect_GFM_DIAG1;
325     aBackgroundGradientFillMethodNameMap["diag2"]      = Aspect_GFM_DIAG2;
326     aBackgroundGradientFillMethodNameMap["diagonal2"]  = Aspect_GFM_DIAG2;
327     aBackgroundGradientFillMethodNameMap["corner1"]    = Aspect_GFM_CORNER1;
328     aBackgroundGradientFillMethodNameMap["corner2"]    = Aspect_GFM_CORNER2;
329     aBackgroundGradientFillMethodNameMap["corner3"]    = Aspect_GFM_CORNER3;
330     aBackgroundGradientFillMethodNameMap["corner4"]    = Aspect_GFM_CORNER4;
331     return aBackgroundGradientFillMethodNameMap;
332   }
333
334   //! Gets a gradient fill method by its name
335   //! @param theBackgroundGradientFillMethodName the name of the gradient fill method
336   //! @param theBackgroundGradientFillMethod the gradient fill method to be found
337   //! @return true if a gradient fill method is found, or false otherwise
338   static bool getBackgroundGradientFillMethodByName (const TCollection_AsciiString& theBackgroundGradientFillMethodName,
339                                                      Aspect_GradientFillMethod&     theBackgroundGradientFillMethod)
340   {
341     static const BackgroundGradientFillMethodNameMap THE_BACKGROUND_GRADIENT_FILL_METHOD_NAME_MAP =
342       createBackgroundGradientFillMethodNameMap();
343     return getSomeCodeByName (THE_BACKGROUND_GRADIENT_FILL_METHOD_NAME_MAP,
344                               theBackgroundGradientFillMethodName,
345                               theBackgroundGradientFillMethod);
346   }
347
348   //! Changes the background in accordance with passed command line options
349   class BackgroundChanger
350   {
351   public:
352     //! Constructor. Prepares the command parser
353     BackgroundChanger()
354     {
355       prepareCommandParser();
356     }
357
358     //! Processes the command line and changes the background
359     //! @param theDrawInterpretor the interpreter of the Draw Harness application
360     //! @param theNumberOfCommandLineArguments the number of passed command line arguments
361     //! @param theCommandLineArguments the array of command line arguments
362     bool ProcessCommandLine (Draw_Interpretor&        theDrawInterpretor,
363                              const Standard_Integer   theNumberOfCommandLineArguments,
364                              const char* const* const theCommandLineArguments)
365     {
366       const char* const aBackgroundCommandName = theCommandLineArguments[0];
367       BackgroundCommand aBackgroundCommand = BackgroundCommand_Main;
368       if (!getBackgroundCommandByName (aBackgroundCommandName, aBackgroundCommand))
369       {
370         return false;
371       }
372       addCommandDescription (aBackgroundCommand);
373       myCommandParser.Parse (theNumberOfCommandLineArguments, theCommandLineArguments);
374       return processCommandOptions (aBackgroundCommandName, aBackgroundCommand, theDrawInterpretor);
375     }
376
377   private:
378     //! The type of functions that are able to set gradient background filling
379     typedef void SetGradientFunction (const Quantity_Color& /* theColor1 */,
380                                       const Quantity_Color& /* theColor2 */,
381                                       const Aspect_GradientFillMethod /* theGradientMode */);
382
383     //! The type of functions that are able to fill a background with a specific color
384     typedef void SetColorFunction (const Quantity_Color& /* theColor */);
385
386     //! the command parser used to parse command line options and its arguments
387     ViewerTest_CmdParser myCommandParser;
388
389     //! the option key for the command that sets an image as a background
390     ViewerTest_CommandOptionKey myImageOptionKey;
391
392     //! the option key for the command that sets a background image fill type
393     ViewerTest_CommandOptionKey myImageModeOptionKey;
394
395     //! the option key for the command that sets a gradient filling for the background
396     ViewerTest_CommandOptionKey myGradientOptionKey;
397
398     //! the option key for the command that sets a background gradient filling method
399     ViewerTest_CommandOptionKey myGradientModeOptionKey;
400
401     //! the option key for the command that fills background with a specific color
402     ViewerTest_CommandOptionKey myColorOptionKey;
403
404     //! the option key for the command that sets default background gradient or color
405     ViewerTest_CommandOptionKey myDefaultOptionKey;
406
407     //! the variable set of options that are allowed for the old scenario (without any option passed)
408     CommandOptionKeyVariableSet myUnnamedOptionVariableSet;
409
410     //! the variable set of options that are allowed for setting an image as a background
411     CommandOptionKeyVariableSet myImageOptionVariableSet;
412
413     //! the variable set of options that are allowed for setting a background image fill type
414     CommandOptionKeyVariableSet myImageModeOptionVariableSet;
415
416     //! the variable set of options that are allowed for setting a gradient filling for the background
417     CommandOptionKeyVariableSet myGradientOptionVariableSet;
418
419     //! the variable set of options that are allowed for setting a background gradient filling method
420     CommandOptionKeyVariableSet myGradientModeOptionVariableSet;
421
422     //! the variable set of options that are allowed for filling a background with a specific color
423     CommandOptionKeyVariableSet myColorOptionVariableSet;
424
425     //! the variable set of options that are allowed for setting a default background gradient
426     CommandOptionKeyVariableSet myDefaultGradientOptionVariableSet;
427
428     //! the variable set of options that are allowed for setting a default background color
429     CommandOptionKeyVariableSet myDefaultColorOptionVariableSet;
430
431     //! the variable set of options that are allowed for printing help
432     CommandOptionKeyVariableSet myHelpOptionVariableSet;
433
434     //! Adds options to command parser
435     void addOptionsToCommandParser()
436     {
437       myImageOptionKey     = myCommandParser.AddOption ("imageFile|image|imgFile|img",
438                                                     "filename of image used as background");
439       myImageModeOptionKey = myCommandParser.AddOption (
440         "imageMode|imgMode", "image fill type, should be one of CENTERED, TILED, STRETCH, NONE");
441       myGradientOptionKey = myCommandParser.AddOption ("gradient|grad|gr",
442                                                        "sets background gradient starting and ending colors");
443       myGradientModeOptionKey =
444         myCommandParser.AddOption ("gradientMode|gradMode|gradMd|grMode|grMd",
445                                    "gradient fill method, should be one of NONE, HOR[IZONTAL], VER[TICAL], "
446                                    "DIAG[ONAL]1, DIAG[ONAL]2, CORNER1, CORNER2, CORNER3, CORNER4");
447       myColorOptionKey   = myCommandParser.AddOption ("color|col", "background color");
448       myDefaultOptionKey = myCommandParser.AddOption ("default|def", "sets background default gradient or color");
449     }
450
451     //! Creates option sets used to determine if a passed option set is valid or not
452     void createOptionSets()
453     {
454       ViewerTest_CommandOptionKeySet anUnnamedOptionSet;
455       anUnnamedOptionSet.insert (ViewerTest_CmdParser::THE_UNNAMED_COMMAND_OPTION_KEY);
456       myUnnamedOptionVariableSet = CommandOptionKeyVariableSet (anUnnamedOptionSet);
457
458       ViewerTest_CommandOptionKeySet anImageOptionSet;
459       anImageOptionSet.insert (myImageOptionKey);
460       ViewerTest_CommandOptionKeySet anImageModeOptionSet;
461       anImageModeOptionSet.insert (myImageModeOptionKey);
462       myImageOptionVariableSet     = CommandOptionKeyVariableSet (anImageOptionSet, anImageModeOptionSet);
463       myImageModeOptionVariableSet = CommandOptionKeyVariableSet (anImageModeOptionSet);
464
465       ViewerTest_CommandOptionKeySet aGradientOptionSet;
466       aGradientOptionSet.insert (myGradientOptionKey);
467       ViewerTest_CommandOptionKeySet aGradientModeOptionSet;
468       aGradientModeOptionSet.insert (myGradientModeOptionKey);
469       myGradientOptionVariableSet     = CommandOptionKeyVariableSet (aGradientOptionSet, aGradientModeOptionSet);
470       myGradientModeOptionVariableSet = CommandOptionKeyVariableSet (aGradientModeOptionSet);
471
472       ViewerTest_CommandOptionKeySet aColorOptionSet;
473       aColorOptionSet.insert (myColorOptionKey);
474       myColorOptionVariableSet = CommandOptionKeyVariableSet (aColorOptionSet);
475
476       aGradientOptionSet.insert (myDefaultOptionKey);
477       myDefaultGradientOptionVariableSet = CommandOptionKeyVariableSet (aGradientOptionSet, aGradientModeOptionSet);
478       aColorOptionSet.insert (myDefaultOptionKey);
479       myDefaultColorOptionVariableSet = CommandOptionKeyVariableSet (aColorOptionSet);
480
481       ViewerTest_CommandOptionKeySet aHelpOptionSet;
482       aHelpOptionSet.insert (ViewerTest_CmdParser::THE_HELP_COMMAND_OPTION_KEY);
483       myHelpOptionVariableSet = CommandOptionKeyVariableSet (aHelpOptionSet);
484     }
485
486     //! Prepares the command parser. Adds options and creates option sets used to determine
487     //! if a passed option set is valid or not
488     void prepareCommandParser()
489     {
490       addOptionsToCommandParser();
491       createOptionSets();
492     }
493
494     //! Adds a command description to the command parser
495     //! @param theBackgroundCommand the key of the command which description is added to the command parser
496     void addCommandDescription (const BackgroundCommand theBackgroundCommand)
497     {
498       std::string aDescription;
499       bool        isMainCommand = false;
500       switch (theBackgroundCommand)
501       {
502         case BackgroundCommand_Main:
503           aDescription  = "Command: vbackground (changes background or some background settings)";
504           isMainCommand = true;
505           break;
506         case BackgroundCommand_Image:
507           aDescription = "Command: vsetbg (loads image as a background)";
508           break;
509         case BackgroundCommand_ImageMode:
510           aDescription = "Command: vsetbgmode (changes background fill type)";
511           break;
512         case BackgroundCommand_Gradient:
513           aDescription = "Command: vsetgradientbg (mounts gradient background)";
514           break;
515         case BackgroundCommand_GradientMode:
516           aDescription = "Command: vsetgradientbgmode (changes gradient background fill method)";
517           break;
518         case BackgroundCommand_Color:
519           aDescription = "Command: vsetcolorbg (sets color background)";
520           break;
521         case BackgroundCommand_Default:
522           aDescription = "Command: vsetdefaultbg (sets default viewer background gradient or fill color)";
523           break;
524         default:
525           return;
526       }
527       if (!isMainCommand)
528       {
529         aDescription += "\nThis command is obsolete. Use vbackground instead.";
530       }
531       myCommandParser.SetDescription (aDescription);
532     }
533
534     //! Check if a viewer is needed to be initialized
535     //! @param theBackgroundCommand the key of the command that changes the background
536     //! @return true if processing was successful, or false otherwise
537     bool checkViewerIsNeeded (const BackgroundCommand theBackgroundCommand) const
538     {
539       const bool                           isMain             = (theBackgroundCommand == BackgroundCommand_Main);
540       const ViewerTest_CommandOptionKeySet aUsedOptions       = myCommandParser.GetUsedOptions();
541       const bool                           aViewerIsNotNeeded =
542         (theBackgroundCommand == BackgroundCommand_Default)
543         || (myDefaultGradientOptionVariableSet.IsInSet (aUsedOptions) && isMain)
544         || (myDefaultColorOptionVariableSet.IsInSet (aUsedOptions) && isMain)
545         || myHelpOptionVariableSet.IsInSet (aUsedOptions);
546       return !aViewerIsNotNeeded;
547     }
548
549     //! Check if a viewer is initialized
550     //! @param theBackgroundCommandName the name of the command that changes the background
551     //! @param theDrawInterpretor the interpreter of the Draw Harness application
552     //! @return true if a viewer is initialized, or false otherwise
553     static bool checkViewerIsInitialized (const char* const theBackgroundCommandName,
554                                           Draw_Interpretor& theDrawInterpretor)
555     {
556       const Handle (AIS_InteractiveContext)& anAISContext = ViewerTest::GetAISContext();
557       if (anAISContext.IsNull())
558       {
559         theDrawInterpretor << "Use 'vinit' command before executing '" << theBackgroundCommandName << "' command.\n";
560         return false;
561       }
562       return true;
563     }
564
565     //! Processes command options
566     //! @param theBackgroundCommandName the name of the command that changes the background
567     //! @param theBackgroundCommand the key of the command that changes the background
568     //! @param theDrawInterpretor the interpreter of the Draw Harness application
569     //! @return true if processing was successful, or false otherwise
570     bool processCommandOptions (const char* const       theBackgroundCommandName,
571                                 const BackgroundCommand theBackgroundCommand,
572                                 Draw_Interpretor&       theDrawInterpretor) const
573     {
574       if (myCommandParser.HasNoOption())
575       {
576         return printHelp (theBackgroundCommandName, theDrawInterpretor);
577       }
578       if (checkViewerIsNeeded (theBackgroundCommand)
579           && !checkViewerIsInitialized (theBackgroundCommandName, theDrawInterpretor))
580       {
581         return false;
582       }
583       if (myCommandParser.HasOnlyUnnamedOption())
584       {
585         return processUnnamedOption (theBackgroundCommand);
586       }
587       return processNamedOptions (theBackgroundCommandName, theBackgroundCommand, theDrawInterpretor);
588     }
589
590     //! Processes the unnamed option
591     //! @param theBackgroundCommand the key of the command that changes the background
592     //! @return true if processing was successful, or false otherwise
593     bool processUnnamedOption (const BackgroundCommand theBackgroundCommand) const
594     {
595       switch (theBackgroundCommand)
596       {
597         case BackgroundCommand_Main:
598           return false;
599         case BackgroundCommand_Image:
600           return processImageUnnamedOption();
601         case BackgroundCommand_ImageMode:
602           return processImageModeUnnamedOption();
603         case BackgroundCommand_Gradient:
604           return processGradientUnnamedOption();
605         case BackgroundCommand_GradientMode:
606           return processGradientModeUnnamedOption();
607         case BackgroundCommand_Color:
608           return processColorUnnamedOption();
609         case BackgroundCommand_Default:
610           return processDefaultUnnamedOption();
611         default:
612           return false;
613       }
614     }
615
616     //! Processes the image unnamed option
617     //! @return true if processing was successful, or false otherwise
618     bool processImageUnnamedOption() const
619     {
620       const std::size_t aNumberOfImageUnnamedOptionArguments = myCommandParser.GetNumberOfOptionArguments (
621         ViewerTest_CmdParser::THE_UNNAMED_COMMAND_OPTION_KEY);
622       if ((aNumberOfImageUnnamedOptionArguments != 1) && (aNumberOfImageUnnamedOptionArguments != 2))
623       {
624         return false;
625       }
626       std::string anImageFileName;
627       if (!myCommandParser.Arg (ViewerTest_CmdParser::THE_UNNAMED_COMMAND_OPTION_KEY, 0, anImageFileName))
628       {
629         return false;
630       }
631       Aspect_FillMethod anImageMode = Aspect_FM_CENTERED;
632       if (aNumberOfImageUnnamedOptionArguments == 2)
633       {
634         std::string anImageModeString;
635         if (!myCommandParser.Arg (ViewerTest_CmdParser::THE_UNNAMED_COMMAND_OPTION_KEY, 1, anImageModeString))
636         {
637           return false;
638         }
639         if (!getBackgroundImageFillMethodByName (anImageModeString.c_str(), anImageMode))
640         {
641           return false;
642         }
643       }
644       setImage (anImageFileName.c_str(), anImageMode);
645       return true;
646     }
647
648     //! Processes the image mode unnamed option
649     //! @return true if processing was successful, or false otherwise
650     bool processImageModeUnnamedOption() const
651     {
652       return processImageModeOptionSet (ViewerTest_CmdParser::THE_UNNAMED_COMMAND_OPTION_KEY);
653     }
654
655     //! Processes the gradient unnamed option
656     //! @param theSetGradient the function used to set a background gradient filling
657     //! @return true if processing was successful, or false otherwise
658     bool processGradientUnnamedOption (SetGradientFunction* const theSetGradient = setGradient) const
659     {
660       const Standard_Integer aNumberOfGradientUnnamedOptionArguments = myCommandParser.GetNumberOfOptionArguments (
661         ViewerTest_CmdParser::THE_UNNAMED_COMMAND_OPTION_KEY);
662       if (aNumberOfGradientUnnamedOptionArguments < 2)
663       {
664         return false;
665       }
666
667       Standard_Integer anArgumentIndex = 0;
668       Quantity_Color   aColor1;
669       if (!myCommandParser.ArgColor (ViewerTest_CmdParser::THE_UNNAMED_COMMAND_OPTION_KEY, anArgumentIndex, aColor1))
670       {
671         return false;
672       }
673       if (anArgumentIndex >= aNumberOfGradientUnnamedOptionArguments)
674       {
675         return false;
676       }
677
678       Quantity_Color aColor2;
679       if (!myCommandParser.ArgColor (ViewerTest_CmdParser::THE_UNNAMED_COMMAND_OPTION_KEY, anArgumentIndex, aColor2))
680       {
681         return false;
682       }
683       if (anArgumentIndex > aNumberOfGradientUnnamedOptionArguments)
684       {
685         return false;
686       }
687
688       Aspect_GradientFillMethod aGradientMode = Aspect_GFM_HOR;
689       if (anArgumentIndex == aNumberOfGradientUnnamedOptionArguments - 1)
690       {
691         std::string anGradientModeString;
692
693         if (!myCommandParser.Arg (ViewerTest_CmdParser::THE_UNNAMED_COMMAND_OPTION_KEY,
694                                   anArgumentIndex,
695                                   anGradientModeString))
696         {
697           return false;
698         }
699         if (!getBackgroundGradientFillMethodByName (anGradientModeString.c_str(), aGradientMode))
700         {
701           return false;
702         }
703         ++anArgumentIndex;
704       }
705       if (anArgumentIndex != aNumberOfGradientUnnamedOptionArguments)
706       {
707         return false;
708       }
709       theSetGradient (aColor1, aColor2, aGradientMode);
710       return true;
711     }
712
713     //! Processes the gradient mode unnamed option
714     //! @return true if processing was successful, or false otherwise
715     bool processGradientModeUnnamedOption() const
716     {
717       return processGradientModeOptionSet (ViewerTest_CmdParser::THE_UNNAMED_COMMAND_OPTION_KEY);
718     }
719
720     //! Processes the color unnamed option
721     //! @param theSetColor the function used to set a background color
722     //! @return true if processing was successful, or false otherwise
723     bool processColorUnnamedOption (SetColorFunction* const theSetColor = setColor) const
724     {
725       return processColorOptionSet (ViewerTest_CmdParser::THE_UNNAMED_COMMAND_OPTION_KEY, theSetColor);
726     }
727
728     //! Processes the default back unnamed option
729     //! @return true if processing was successful, or false otherwise
730     bool processDefaultUnnamedOption() const
731     {
732       if (processGradientUnnamedOption (setDefaultGradient))
733       {
734         return true;
735       }
736       return processColorUnnamedOption (setDefaultColor);
737     }
738
739     //! Processes named options
740     //! @param theBackgroundCommandName the name of the command that changes the background
741     //! @param theBackgroundCommand the key of the command that changes the background
742     //! @param theDrawInterpretor the interpreter of the Draw Harness application
743     //! @return true if processing was successful, or false otherwise
744     bool processNamedOptions (const char* const       theBackgroundCommandName,
745                               const BackgroundCommand theBackgroundCommand,
746                               Draw_Interpretor&       theDrawInterpretor) const
747     {
748       const bool                           isMain       = (theBackgroundCommand == BackgroundCommand_Main);
749       const ViewerTest_CommandOptionKeySet aUsedOptions = myCommandParser.GetUsedOptions();
750       if (myImageOptionVariableSet.IsInSet (aUsedOptions)
751           && (isMain || (theBackgroundCommand == BackgroundCommand_Image)))
752       {
753         return processImageOptionSet();
754       }
755       if (myImageModeOptionVariableSet.IsInSet (aUsedOptions)
756           && (isMain || (theBackgroundCommand == BackgroundCommand_ImageMode)))
757       {
758         return processImageModeOptionSet();
759       }
760       if (myGradientOptionVariableSet.IsInSet (aUsedOptions)
761           && (isMain || (theBackgroundCommand == BackgroundCommand_Gradient)))
762       {
763         return processGradientOptionSet();
764       }
765       if (myGradientModeOptionVariableSet.IsInSet (aUsedOptions)
766           && (isMain || (theBackgroundCommand == BackgroundCommand_GradientMode)))
767       {
768         return processGradientModeOptionSet();
769       }
770       if (myColorOptionVariableSet.IsInSet (aUsedOptions)
771           && (isMain || (theBackgroundCommand == BackgroundCommand_Color)))
772       {
773         return processColorOptionSet();
774       }
775       if ((myDefaultGradientOptionVariableSet.IsInSet (aUsedOptions) && isMain)
776           || (myGradientOptionVariableSet.IsInSet (aUsedOptions)
777               && (theBackgroundCommand == BackgroundCommand_Default)))
778       {
779         return processDefaultGradientOptionSet();
780       }
781       if ((myDefaultColorOptionVariableSet.IsInSet (aUsedOptions) && isMain)
782           || (myColorOptionVariableSet.IsInSet (aUsedOptions) && (theBackgroundCommand == BackgroundCommand_Default)))
783       {
784         return processDefaultColorOptionSet();
785       }
786       if (myHelpOptionVariableSet.IsInSet (aUsedOptions))
787       {
788         return processHelpOptionSet (theBackgroundCommandName, theDrawInterpretor);
789       }
790       return false;
791     }
792
793     //! Processes the image option set
794     //! @return true if processing was successful, or false otherwise
795     bool processImageOptionSet() const
796     {
797       std::string anImageFileName;
798       if (!processImageOption (anImageFileName))
799       {
800         return false;
801       }
802       Aspect_FillMethod anImageMode = Aspect_FM_CENTERED;
803       if (myCommandParser.HasOption (myImageModeOptionKey) && !processImageModeOption (anImageMode))
804       {
805         return false;
806       }
807       setImage (anImageFileName.c_str(), anImageMode);
808       return true;
809     }
810
811     //! Processes the image mode option set
812     //! @return true if processing was successful, or false otherwise
813     bool processImageModeOptionSet() const
814     {
815       return processImageModeOptionSet (myImageModeOptionKey);
816     }
817
818     //! Processes the image mode option set
819     //! @param theImageModeOptionKey the key of the option that is interpreted as an image mode option
820     //! @return true if processing was successful, or false otherwise
821     bool processImageModeOptionSet (const ViewerTest_CommandOptionKey theImageModeOptionKey) const
822     {
823       Aspect_FillMethod anImageMode = Aspect_FM_NONE;
824       if (!processImageModeOption (theImageModeOptionKey, anImageMode))
825       {
826         return false;
827       }
828       setImageMode (anImageMode);
829       return true;
830     }
831
832     //! Processes the gradient option set
833     //! @param theSetGradient the function used to set a background gradient filling
834     //! @return true if processing was successful, or false otherwise
835     bool processGradientOptionSet (SetGradientFunction* const theSetGradient = setGradient) const
836     {
837       Quantity_Color aColor1;
838       Quantity_Color aColor2;
839       if (!processGradientOption (aColor1, aColor2))
840       {
841         return false;
842       }
843       Aspect_GradientFillMethod aGradientMode = Aspect_GFM_HOR;
844       if (myCommandParser.HasOption (myGradientModeOptionKey) && !processGradientModeOption (aGradientMode))
845       {
846         return false;
847       }
848       theSetGradient (aColor1, aColor2, aGradientMode);
849       return true;
850     }
851
852     //! Processes the gradient mode option set
853     //! @return true if processing was successful, or false otherwise
854     bool processGradientModeOptionSet() const
855     {
856       return processGradientModeOptionSet (myGradientModeOptionKey);
857     }
858
859     //! Processes the gradient mode option set
860     //! @param theGradientModeOptionKey the key of the option that is interpreted as a gradient mode option
861     //! @return true if processing was successful, or false otherwise
862     bool processGradientModeOptionSet (const ViewerTest_CommandOptionKey theGradientModeOptionKey) const
863     {
864       Aspect_GradientFillMethod aGradientMode = Aspect_GFM_NONE;
865       if (!processGradientModeOption (theGradientModeOptionKey, aGradientMode))
866       {
867         return false;
868       }
869       setGradientMode (aGradientMode);
870       return true;
871     }
872
873     //! Processes the color option set
874     //! @param theSetColor the function used to set a background color
875     //! @return true if processing was successful, or false otherwise
876     bool processColorOptionSet (SetColorFunction* const theSetColor = setColor) const
877     {
878       return processColorOptionSet (myColorOptionKey, theSetColor);
879     }
880
881     //! Processes the default color option set
882     //! @return true if processing was successful, or false otherwise
883     bool processDefaultGradientOptionSet() const
884     {
885       return processGradientOptionSet (setDefaultGradient);
886     }
887
888     //! Processes the default gradient option set
889     //! @return true if processing was successful, or false otherwise
890     bool processDefaultColorOptionSet() const
891     {
892       return processColorOptionSet (setDefaultColor);
893     }
894
895     //! Processes the color option set
896     //! @param theColorOptionKey the key of the option that is interpreted as a color option
897     //! @param theSetColor the function used to set a background color
898     //! @return true if processing was successful, or false otherwise
899     bool processColorOptionSet (const ViewerTest_CommandOptionKey theColorOptionKey,
900                                 SetColorFunction* const           theSetColor = setColor) const
901     {
902       Quantity_Color aColor;
903       if (!processColorOption (theColorOptionKey, aColor))
904       {
905         return false;
906       }
907       theSetColor (aColor);
908       return true;
909     }
910
911     //! Processes the help option set
912     //! @param theBackgroundCommandName the name of the command that changes the background
913     //! @param theDrawInterpretor the interpreter of the Draw Harness application
914     //! @return true if processing was successful, or false otherwise
915     bool processHelpOptionSet (const char* const theBackgroundCommandName, Draw_Interpretor& theDrawInterpretor) const
916     {
917       const Standard_Integer aNumberOfHelpOptionArguments = myCommandParser.GetNumberOfOptionArguments (
918         ViewerTest_CmdParser::THE_HELP_COMMAND_OPTION_KEY);
919       if (aNumberOfHelpOptionArguments != 0)
920       {
921         return false;
922       }
923       return printHelp (theBackgroundCommandName, theDrawInterpretor);
924     }
925
926     //! Processes the image option
927     //! @param theImageFileName the filename of the image to be used as a background
928     //! @return true if processing was successful, or false otherwise
929     bool processImageOption (std::string& theImageFileName) const
930     {
931       const Standard_Integer aNumberOfImageOptionArguments = myCommandParser.GetNumberOfOptionArguments (
932         myImageOptionKey);
933       if (aNumberOfImageOptionArguments != 1)
934       {
935         return false;
936       }
937       std::string anImageFileName;
938       if (!myCommandParser.Arg (myImageOptionKey, 0, anImageFileName))
939       {
940         return false;
941       }
942       theImageFileName = anImageFileName;
943       return true;
944     }
945
946     //! Processes the image mode option
947     //! @param theImageMode the fill type used for a background image
948     //! @return true if processing was successful, or false otherwise
949     bool processImageModeOption (Aspect_FillMethod& theImageMode) const
950     {
951       return processImageModeOption (myImageModeOptionKey, theImageMode);
952     }
953
954     //! Processes the image mode option
955     //! @param theImageModeOptionKey the key of the option that is interpreted as an image mode option
956     //! @param theImageMode the fill type used for a background image
957     //! @return true if processing was successful, or false otherwise
958     bool processImageModeOption (const ViewerTest_CommandOptionKey theImageModeOptionKey,
959                                  Aspect_FillMethod&                theImageMode) const
960     {
961       return processModeOption (theImageModeOptionKey, getBackgroundImageFillMethodByName, theImageMode);
962     }
963
964     //! Processes the gradient option
965     //! @param theColor1 the gradient starting color
966     //! @param theColor2 the gradient ending color
967     //! @return true if processing was successful, or false otherwise
968     bool processGradientOption (Quantity_Color& theColor1, Quantity_Color& theColor2) const
969     {
970       Standard_Integer anArgumentIndex = 0;
971       Quantity_Color   aColor1;
972       if (!myCommandParser.ArgColor (myGradientOptionKey, anArgumentIndex, aColor1))
973       {
974         return false;
975       }
976       Quantity_Color aColor2;
977       if (!myCommandParser.ArgColor (myGradientOptionKey, anArgumentIndex, aColor2))
978       {
979         return false;
980       }
981       const Standard_Integer aNumberOfGradientOptionArguments = myCommandParser.GetNumberOfOptionArguments (
982         myGradientOptionKey);
983       if (anArgumentIndex != aNumberOfGradientOptionArguments)
984       {
985         return false;
986       }
987       theColor1 = aColor1;
988       theColor2 = aColor2;
989       return true;
990     }
991
992     //! Processes the gradient mode option
993     //! @param theGradientMode the fill method used for a background gradient filling
994     //! @return true if processing was successful, or false otherwise
995     bool processGradientModeOption (Aspect_GradientFillMethod& theGradientMode) const
996     {
997       return processGradientModeOption (myGradientModeOptionKey, theGradientMode);
998     }
999
1000     //! Processes the gradient mode option
1001     //! @param theGradientModeOptionKey the key of the option that is interpreted as a gradient mode option
1002     //! @param theGradientMode the fill method used for a background gradient filling
1003     //! @return true if processing was successful, or false otherwise
1004     bool processGradientModeOption (const ViewerTest_CommandOptionKey theGradientModeOptionKey,
1005                                     Aspect_GradientFillMethod&        theGradientMode) const
1006     {
1007       return processModeOption (theGradientModeOptionKey, getBackgroundGradientFillMethodByName, theGradientMode);
1008     }
1009
1010     //! Processes some mode option
1011     //! @tparam TheMode the type of a mode to be processed
1012     //! @param theModeOptionKey the key of the option that is interpreted as a mode option
1013     //! @param theMode a mode to be processed
1014     //! @return true if processing was successful, or false otherwise
1015     template <typename TheMode>
1016     bool processModeOption (const ViewerTest_CommandOptionKey theModeOptionKey,
1017                             bool (*const theGetModeByName) (const TCollection_AsciiString& /* theModeName */,
1018                                                             TheMode& /* theMode */),
1019                             TheMode& theMode) const
1020     {
1021       const Standard_Integer aNumberOfModeOptionArguments = myCommandParser.GetNumberOfOptionArguments (
1022         theModeOptionKey);
1023       if (aNumberOfModeOptionArguments != 1)
1024       {
1025         return false;
1026       }
1027       std::string aModeString;
1028       if (!myCommandParser.Arg (theModeOptionKey, 0, aModeString))
1029       {
1030         return false;
1031       }
1032       TheMode aMode = TheMode();
1033       if (!theGetModeByName (aModeString.c_str(), aMode))
1034       {
1035         return false;
1036       }
1037       theMode = aMode;
1038       return true;
1039     }
1040
1041     //! Processes the color option
1042     //! @param theColor a color used for filling a background
1043     //! @return true if processing was successful, or false otherwise
1044     bool processColorOption (Quantity_Color& theColor) const
1045     {
1046       return processColorOption (myColorOptionKey, theColor);
1047     }
1048
1049     //! Processes the color option
1050     //! @param theColorOptionKey the key of the option that is interpreted as a color option
1051     //! @param theColor a color used for filling a background
1052     //! @return true if processing was successful, or false otherwise
1053     bool processColorOption (const ViewerTest_CommandOptionKey theColorOptionKey, Quantity_Color& theColor) const
1054     {
1055       Standard_Integer anArgumentIndex = 0;
1056       Quantity_Color   aColor;
1057       if (!myCommandParser.ArgColor (theColorOptionKey, anArgumentIndex, aColor))
1058       {
1059         return false;
1060       }
1061       const Standard_Integer aNumberOfColorOptionArguments = myCommandParser.GetNumberOfOptionArguments (
1062         theColorOptionKey);
1063       if (anArgumentIndex != aNumberOfColorOptionArguments)
1064       {
1065         return false;
1066       }
1067       theColor = aColor;
1068       return true;
1069     }
1070
1071     //! Prints helping message
1072     //! @param theBackgroundCommandName the name of the command that changes the background
1073     //! @param theDrawInterpretor the interpreter of the Draw Harness application
1074     //! @return true if printing was successful, or false otherwise
1075     static bool printHelp (const char* const theBackgroundCommandName, Draw_Interpretor& theDrawInterpretor)
1076     {
1077       return theDrawInterpretor.PrintHelp (theBackgroundCommandName) == TCL_OK;
1078     }
1079
1080     //! Sets the image as a background
1081     //! @param theImageFileName the filename of the image to be used as a background
1082     //! @param theImageMode the fill type used for a background image
1083     static void setImage (const Standard_CString theImageFileName, const Aspect_FillMethod theImageMode)
1084     {
1085       const Handle (V3d_View)& aCurrentView = ViewerTest::CurrentView();
1086       aCurrentView->SetBackgroundImage (theImageFileName, theImageMode, Standard_True);
1087     }
1088
1089     //! Sets the fill type used for a background image
1090     //! @param theImageMode the fill type used for a background image
1091     static void setImageMode (const Aspect_FillMethod theImageMode)
1092     {
1093       const Handle (V3d_View)& aCurrentView = ViewerTest::CurrentView();
1094       aCurrentView->SetBgImageStyle (theImageMode, Standard_True);
1095     }
1096
1097     //! Sets the gradient filling for a background
1098     //! @param theColor1 the gradient starting color
1099     //! @param theColor2 the gradient ending color
1100     //! @param theGradientMode the fill method used for a background gradient filling
1101     static void setGradient (const Quantity_Color&           theColor1,
1102                              const Quantity_Color&           theColor2,
1103                              const Aspect_GradientFillMethod theGradientMode)
1104     {
1105       const Handle (V3d_View)& aCurrentView = ViewerTest::CurrentView();
1106       aCurrentView->SetBgGradientColors (theColor1, theColor2, theGradientMode, Standard_True);
1107     }
1108
1109     //! Sets the fill method used for a background gradient filling
1110     //! @param theGradientMode the fill method used for a background gradient filling
1111     static void setGradientMode (const Aspect_GradientFillMethod theGradientMode)
1112     {
1113       const Handle (V3d_View)& aCurrentView = ViewerTest::CurrentView();
1114       aCurrentView->SetBgGradientStyle (theGradientMode, Standard_True);
1115     }
1116
1117     //! Sets the color used for filling a background
1118     //! @param theColor the color used for filling a background
1119     static void setColor (const Quantity_Color& theColor)
1120     {
1121       const Handle (V3d_View)& aCurrentView = ViewerTest::CurrentView();
1122       aCurrentView->SetBgGradientStyle (Aspect_GFM_NONE);
1123       aCurrentView->SetBackgroundColor (theColor);
1124       aCurrentView->Update();
1125     }
1126
1127     //! Sets the gradient filling for a background in a default viewer
1128     //! @param theColor1 the gradient starting color
1129     //! @param theColor2 the gradient ending color
1130     //! @param theGradientMode the fill method used for a background gradient filling
1131     static void setDefaultGradient (const Quantity_Color&           theColor1,
1132                                     const Quantity_Color&           theColor2,
1133                                     const Aspect_GradientFillMethod theGradientMode)
1134     {
1135       ViewerTest_DefaultBackground.GradientColor1 = theColor1;
1136       ViewerTest_DefaultBackground.GradientColor2 = theColor2;
1137       ViewerTest_DefaultBackground.FillMethod     = theGradientMode;
1138       setDefaultGradient();
1139     }
1140
1141     //! Sets the color used for filling a background in a default viewer
1142     //! @param theColor the color used for filling a background
1143     static void setDefaultColor (const Quantity_Color& theColor)
1144     {
1145       ViewerTest_DefaultBackground.GradientColor1 = Quantity_Color();
1146       ViewerTest_DefaultBackground.GradientColor2 = Quantity_Color();
1147       ViewerTest_DefaultBackground.FillMethod     = Aspect_GFM_NONE;
1148       ViewerTest_DefaultBackground.FlatColor      = theColor;
1149       setDefaultGradient();
1150       setDefaultColor();
1151     }
1152
1153     //! Sets the gradient filling for a background in a default viewer.
1154     //! Gradient settings are taken from ViewerTest_DefaultBackground structure
1155     static void setDefaultGradient()
1156     {
1157       for (NCollection_DoubleMap<TCollection_AsciiString, Handle (AIS_InteractiveContext)>::Iterator
1158              anInteractiveContextIterator (ViewerTest_myContexts);
1159            anInteractiveContextIterator.More();
1160            anInteractiveContextIterator.Next())
1161       {
1162         const Handle (V3d_Viewer)& aViewer = anInteractiveContextIterator.Value()->CurrentViewer();
1163         aViewer->SetDefaultBgGradientColors (ViewerTest_DefaultBackground.GradientColor1,
1164                                              ViewerTest_DefaultBackground.GradientColor2,
1165                                              ViewerTest_DefaultBackground.FillMethod);
1166       }
1167     }
1168
1169     //! Sets the color used for filling a background in a default viewer.
1170     //! The color value is taken from ViewerTest_DefaultBackground structure
1171     static void setDefaultColor()
1172     {
1173       for (NCollection_DoubleMap<TCollection_AsciiString, Handle (AIS_InteractiveContext)>::Iterator
1174              anInteractiveContextIterator (ViewerTest_myContexts);
1175            anInteractiveContextIterator.More();
1176            anInteractiveContextIterator.Next())
1177       {
1178         const Handle (V3d_Viewer)& aViewer = anInteractiveContextIterator.Value()->CurrentViewer();
1179         aViewer->SetDefaultBackgroundColor (ViewerTest_DefaultBackground.FlatColor);
1180       }
1181     }
1182   };
1183
1184 } // namespace
1185
1186 typedef NCollection_Map<AIS_Manipulator*> ViewerTest_MapOfAISManipulators;
1187
1188 Standard_EXPORT ViewerTest_MapOfAISManipulators& GetMapOfAISManipulators()
1189 {
1190   static ViewerTest_MapOfAISManipulators aMap;
1191   return aMap;
1192 }
1193
1194 Standard_EXPORT Handle(AIS_Manipulator) GetActiveAISManipulator()
1195 {
1196   ViewerTest_MapOfAISManipulators::Iterator anIt (GetMapOfAISManipulators());
1197   for (; anIt.More(); anIt.Next())
1198   {
1199     if (anIt.Value()->HasActiveMode())
1200     {
1201       return anIt.Value();
1202     }
1203   }
1204   return NULL;
1205 }
1206
1207 //==============================================================================
1208
1209 #ifdef _WIN32
1210 static LRESULT WINAPI ViewerWindowProc(
1211                                        HWND hwnd,
1212                                        UINT uMsg,
1213                                        WPARAM wParam,
1214                                        LPARAM lParam );
1215 static LRESULT WINAPI AdvViewerWindowProc(
1216   HWND hwnd,
1217   UINT uMsg,
1218   WPARAM wParam,
1219   LPARAM lParam );
1220 #endif
1221
1222
1223 //==============================================================================
1224 //function : WClass
1225 //purpose  :
1226 //==============================================================================
1227
1228 const Handle(Standard_Transient)& ViewerTest::WClass()
1229 {
1230   static Handle(Standard_Transient) theWClass;
1231 #if defined(_WIN32)
1232   if (theWClass.IsNull())
1233   {
1234     theWClass = new WNT_WClass ("GW3D_Class", (Standard_Address )AdvViewerWindowProc,
1235                                 CS_VREDRAW | CS_HREDRAW, 0, 0,
1236                                 ::LoadCursor (NULL, IDC_ARROW));
1237   }
1238 #endif
1239   return theWClass;
1240 }
1241
1242 //==============================================================================
1243 //function : CreateName
1244 //purpose  : Create numerical name for new object in theMap
1245 //==============================================================================
1246 template <typename ObjectType>
1247 TCollection_AsciiString CreateName (const NCollection_DoubleMap <TCollection_AsciiString, ObjectType>& theObjectMap,
1248                                     const TCollection_AsciiString& theDefaultString)
1249 {
1250   if (theObjectMap.IsEmpty())
1251     return theDefaultString + TCollection_AsciiString(1);
1252
1253   Standard_Integer aNextKey = 1;
1254   Standard_Boolean isFound = Standard_False;
1255   while (!isFound)
1256   {
1257     TCollection_AsciiString aStringKey = theDefaultString + TCollection_AsciiString(aNextKey);
1258     // Look for objects with default names
1259     if (theObjectMap.IsBound1(aStringKey))
1260     {
1261       aNextKey++;
1262     }
1263     else
1264       isFound = Standard_True;
1265   }
1266
1267   return theDefaultString + TCollection_AsciiString(aNextKey);
1268 }
1269
1270 //==============================================================================
1271 //structure : ViewerTest_Names
1272 //purpose   : Allow to operate with full view name: driverName/viewerName/viewName
1273 //==============================================================================
1274 struct ViewerTest_Names
1275 {
1276 private:
1277   TCollection_AsciiString myDriverName;
1278   TCollection_AsciiString myViewerName;
1279   TCollection_AsciiString myViewName;
1280
1281 public:
1282
1283   const TCollection_AsciiString& GetDriverName () const
1284   {
1285     return myDriverName;
1286   }
1287   void SetDriverName (const TCollection_AsciiString& theDriverName)
1288   {
1289     myDriverName = theDriverName;
1290   }
1291   const TCollection_AsciiString& GetViewerName () const
1292   {
1293     return myViewerName;
1294   }
1295   void SetViewerName (const TCollection_AsciiString& theViewerName)
1296   {
1297     myViewerName = theViewerName;
1298   }
1299   const TCollection_AsciiString& GetViewName () const
1300   {
1301     return myViewName;
1302   }
1303   void SetViewName (const TCollection_AsciiString& theViewName)
1304   {
1305     myViewName = theViewName;
1306   }
1307
1308   //===========================================================================
1309   //function : Constructor for ViewerTest_Names
1310   //purpose  : Get view, viewer, driver names from custom string
1311   //===========================================================================
1312
1313   ViewerTest_Names (const TCollection_AsciiString& theInputString)
1314   {
1315     TCollection_AsciiString aName(theInputString);
1316     if (theInputString.IsEmpty())
1317     {
1318       // Get current configuration
1319       if (ViewerTest_myDrivers.IsEmpty())
1320         myDriverName = CreateName<Handle(Graphic3d_GraphicDriver)>
1321           (ViewerTest_myDrivers, TCollection_AsciiString("Driver"));
1322       else
1323         myDriverName = ViewerTest_myDrivers.Find2
1324         (ViewerTest::GetAISContext()->CurrentViewer()->Driver());
1325
1326       if(ViewerTest_myContexts.IsEmpty())
1327       {
1328         myViewerName = CreateName <Handle(AIS_InteractiveContext)>
1329           (ViewerTest_myContexts, TCollection_AsciiString (myDriverName + "/Viewer"));
1330       }
1331       else
1332       {
1333         myViewerName = ViewerTest_myContexts.Find2 (ViewerTest::GetAISContext());
1334       }
1335
1336       myViewName = CreateName <Handle(V3d_View)> (ViewerTest_myViews, TCollection_AsciiString(myViewerName + "/View"));
1337     }
1338     else
1339     {
1340       // There is at least view name
1341       Standard_Integer aParserNumber = 0;
1342       for (Standard_Integer i = 0; i < 3; ++i)
1343       {
1344         Standard_Integer aParserPos = aName.SearchFromEnd("/");
1345         if(aParserPos != -1)
1346         {
1347           aParserNumber++;
1348           aName.Split(aParserPos-1);
1349         }
1350         else
1351           break;
1352       }
1353       if (aParserNumber == 0)
1354       {
1355         // Only view name
1356         if (!ViewerTest::GetAISContext().IsNull())
1357         {
1358           myDriverName = ViewerTest_myDrivers.Find2
1359           (ViewerTest::GetAISContext()->CurrentViewer()->Driver());
1360           myViewerName = ViewerTest_myContexts.Find2
1361           (ViewerTest::GetAISContext());
1362         }
1363         else
1364         {
1365           // There is no opened contexts here, need to create names for viewer and driver
1366           myDriverName = CreateName<Handle(Graphic3d_GraphicDriver)>
1367             (ViewerTest_myDrivers, TCollection_AsciiString("Driver"));
1368
1369           myViewerName = CreateName <Handle(AIS_InteractiveContext)>
1370             (ViewerTest_myContexts, TCollection_AsciiString (myDriverName + "/Viewer"));
1371         }
1372         myViewName = TCollection_AsciiString(myViewerName + "/" + theInputString);
1373       }
1374       else if (aParserNumber == 1)
1375       {
1376         // Here is viewerName/viewName
1377         if (!ViewerTest::GetAISContext().IsNull())
1378           myDriverName = ViewerTest_myDrivers.Find2
1379           (ViewerTest::GetAISContext()->CurrentViewer()->Driver());
1380         else
1381         {
1382           // There is no opened contexts here, need to create name for driver
1383           myDriverName = CreateName<Handle(Graphic3d_GraphicDriver)>
1384             (ViewerTest_myDrivers, TCollection_AsciiString("Driver"));
1385         }
1386         myViewerName = TCollection_AsciiString(myDriverName + "/" + aName);
1387
1388         myViewName = TCollection_AsciiString(myDriverName + "/" + theInputString);
1389       }
1390       else
1391       {
1392         //Here is driverName/viewerName/viewName
1393         myDriverName = TCollection_AsciiString(aName);
1394
1395         TCollection_AsciiString aViewerName(theInputString);
1396         aViewerName.Split(aViewerName.SearchFromEnd("/") - 1);
1397         myViewerName = TCollection_AsciiString(aViewerName);
1398
1399         myViewName = TCollection_AsciiString(theInputString);
1400       }
1401     }
1402   }
1403 };
1404
1405 //==============================================================================
1406 //function : FindContextByView
1407 //purpose  : Find AIS_InteractiveContext by View
1408 //==============================================================================
1409
1410 Handle(AIS_InteractiveContext) FindContextByView (const Handle(V3d_View)& theView)
1411 {
1412   Handle(AIS_InteractiveContext) anAISContext;
1413
1414   for (NCollection_DoubleMap<TCollection_AsciiString, Handle(AIS_InteractiveContext)>::Iterator
1415        anIter (ViewerTest_myContexts); anIter.More(); anIter.Next())
1416   {
1417     if (anIter.Value()->CurrentViewer() == theView->Viewer())
1418        return anIter.Key2();
1419   }
1420   return anAISContext;
1421 }
1422
1423 //==============================================================================
1424 //function : IsWindowOverlapped
1425 //purpose  : Check if theWindow overlapp another view
1426 //==============================================================================
1427
1428 Standard_Boolean IsWindowOverlapped (const Standard_Integer thePxLeft,
1429                                      const Standard_Integer thePxTop,
1430                                      const Standard_Integer thePxRight,
1431                                      const Standard_Integer thePxBottom,
1432                                      TCollection_AsciiString& theViewId)
1433 {
1434   for(NCollection_DoubleMap <TCollection_AsciiString, Handle(V3d_View)>::Iterator
1435       anIter(ViewerTest_myViews); anIter.More(); anIter.Next())
1436   {
1437     Standard_Integer aTop = 0,
1438       aLeft = 0,
1439       aRight = 0,
1440       aBottom = 0;
1441     anIter.Value()->Window()->Position(aLeft, aTop, aRight, aBottom);
1442     if ((thePxLeft >= aLeft && thePxLeft <= aRight && thePxTop >= aTop && thePxTop <= aBottom) ||
1443         (thePxLeft >= aLeft && thePxLeft <= aRight && thePxBottom >= aTop && thePxBottom <= aBottom) ||
1444         (thePxRight >= aLeft && thePxRight <= aRight && thePxTop >= aTop && thePxTop <= aBottom) ||
1445         (thePxRight >= aLeft && thePxRight <= aRight && thePxBottom >= aTop && thePxBottom <= aBottom))
1446     {
1447       theViewId = anIter.Key1();
1448       return Standard_True;
1449     }
1450   }
1451   return Standard_False;
1452 }
1453
1454 // Workaround: to create and delete non-orthographic views outside ViewerTest
1455 void ViewerTest::RemoveViewName (const TCollection_AsciiString& theName)
1456 {
1457   ViewerTest_myViews.UnBind1 (theName);
1458 }
1459
1460 void ViewerTest::InitViewName (const TCollection_AsciiString& theName,
1461                                const Handle(V3d_View)& theView)
1462 {
1463   ViewerTest_myViews.Bind (theName, theView);
1464 }
1465
1466 TCollection_AsciiString ViewerTest::GetCurrentViewName ()
1467 {
1468   return ViewerTest_myViews.Find2( ViewerTest::CurrentView());
1469 }
1470
1471 //! Auxiliary tool performing continuous redraws of specified window.
1472 class ViewerTest_ContinuousRedrawer
1473 {
1474 public:
1475   //! Return global instance.
1476   static ViewerTest_ContinuousRedrawer& Instance()
1477   {
1478     static ViewerTest_ContinuousRedrawer aRedrawer;
1479     return aRedrawer;
1480   }
1481 public:
1482
1483   //! Destructor.
1484   ~ViewerTest_ContinuousRedrawer()
1485   {
1486     Stop();
1487   }
1488
1489   //! Start thread.
1490   void Start (const Handle(Aspect_Window)& theWindow,
1491               Standard_Real theTargetFps)
1492   {
1493     if (myWindow != theWindow
1494      || myTargetFps != theTargetFps)
1495     {
1496       Stop();
1497       myWindow = theWindow;
1498       myTargetFps = theTargetFps;
1499     }
1500     if (myThread.GetId() == 0)
1501     {
1502       myToStop = false;
1503       myThread.Run (this);
1504     }
1505   }
1506
1507   //! Stop thread.
1508   void Stop (const Handle(Aspect_Window)& theWindow = NULL)
1509   {
1510     if (!theWindow.IsNull()
1511       && myWindow != theWindow)
1512     {
1513       return;
1514     }
1515
1516     {
1517       Standard_Mutex::Sentry aLock (myMutex);
1518       myToStop = true;
1519     }
1520     myThread.Wait();
1521     myToStop = false;
1522     myWindow.Nullify();
1523   }
1524
1525 private:
1526
1527   //! Thread loop.
1528   void doThreadLoop()
1529   {
1530     Handle(Aspect_DisplayConnection) aDisp = new Aspect_DisplayConnection();
1531     OSD_Timer aTimer;
1532     aTimer.Start();
1533     Standard_Real aTimeOld = 0.0;
1534     const Standard_Real aTargetDur = myTargetFps > 0.0 ? 1.0 / myTargetFps : -1.0;
1535     for (;;)
1536     {
1537       {
1538         Standard_Mutex::Sentry aLock (myMutex);
1539         if (myToStop)
1540         {
1541           return;
1542         }
1543       }
1544       if (myTargetFps > 0.0)
1545       {
1546         const Standard_Real aTimeNew  = aTimer.ElapsedTime();
1547         const Standard_Real aDuration = aTimeNew - aTimeOld;
1548         if (aDuration >= aTargetDur)
1549         {
1550           myWindow->InvalidateContent (aDisp);
1551           aTimeOld = aTimeNew;
1552         }
1553       }
1554       else
1555       {
1556         myWindow->InvalidateContent (aDisp);
1557       }
1558
1559       OSD::MilliSecSleep (1);
1560     }
1561   }
1562
1563   //! Thread creation callback.
1564   static Standard_Address doThreadWrapper (Standard_Address theData)
1565   {
1566     ViewerTest_ContinuousRedrawer* aThis = (ViewerTest_ContinuousRedrawer* )theData;
1567     aThis->doThreadLoop();
1568     return 0;
1569   }
1570
1571   //! Empty constructor.
1572   ViewerTest_ContinuousRedrawer()
1573   : myThread (doThreadWrapper),
1574     myTargetFps (0.0),
1575     myToStop (false) {}
1576
1577 private:
1578   Handle(Aspect_Window) myWindow;
1579   OSD_Thread      myThread;
1580   Standard_Mutex  myMutex;
1581   Standard_Real   myTargetFps;
1582   volatile bool   myToStop;
1583 };
1584
1585 //==============================================================================
1586 //function : ViewerInit
1587 //purpose  : Create the window viewer and initialize all the global variable
1588 //==============================================================================
1589
1590 TCollection_AsciiString ViewerTest::ViewerInit (const Standard_Integer thePxLeft,
1591                                                 const Standard_Integer thePxTop,
1592                                                 const Standard_Integer thePxWidth,
1593                                                 const Standard_Integer thePxHeight,
1594                                                 const TCollection_AsciiString& theViewName,
1595                                                 const TCollection_AsciiString& theDisplayName,
1596                                                 const Handle(V3d_View)& theViewToClone)
1597 {
1598   // Default position and dimension of the viewer window.
1599   // Note that left top corner is set to be sufficiently small to have
1600   // window fit in the small screens (actual for remote desktops, see #23003).
1601   // The position corresponds to the window's client area, thus some
1602   // gap is added for window frame to be visible.
1603   Standard_Integer aPxLeft   = 20;
1604   Standard_Integer aPxTop    = 40;
1605   Standard_Integer aPxWidth  = 409;
1606   Standard_Integer aPxHeight = 409;
1607   Standard_Boolean toCreateViewer = Standard_False;
1608   if (!theViewToClone.IsNull())
1609   {
1610     theViewToClone->Window()->Size (aPxWidth, aPxHeight);
1611   }
1612
1613   Handle(OpenGl_GraphicDriver) aGraphicDriver;
1614   ViewerTest_Names aViewNames(theViewName);
1615   if (ViewerTest_myViews.IsBound1 (aViewNames.GetViewName ()))
1616     aViewNames.SetViewName (aViewNames.GetViewerName() + "/" + CreateName<Handle(V3d_View)>(ViewerTest_myViews, "View"));
1617
1618   if (thePxLeft != 0)
1619     aPxLeft = thePxLeft;
1620   if (thePxTop != 0)
1621     aPxTop = thePxTop;
1622   if (thePxWidth != 0)
1623     aPxWidth = thePxWidth;
1624   if (thePxHeight != 0)
1625     aPxHeight = thePxHeight;
1626
1627   // Get graphic driver (create it or get from another view)
1628   const bool isNewDriver = !ViewerTest_myDrivers.IsBound1 (aViewNames.GetDriverName());
1629   if (isNewDriver)
1630   {
1631     // Get connection string
1632   #if !defined(_WIN32) && (!defined(__APPLE__) || defined(MACOSX_USE_GLX))
1633     if (!theDisplayName.IsEmpty())
1634     {
1635       SetDisplayConnection (new Aspect_DisplayConnection (theDisplayName));
1636     }
1637     else
1638     {
1639       ::Display* aDispX = NULL;
1640       // create dedicated display connection instead of reusing Tk connection
1641       // so that to procede events independently through VProcessEvents()/ViewerMainLoop() callbacks
1642       /*Draw_Interpretor& aCommands = Draw::GetInterpretor();
1643       Tcl_Interp* aTclInterp = aCommands.Interp();
1644       Tk_Window aMainWindow = Tk_MainWindow (aTclInterp);
1645       aDispX = aMainWindow != NULL ? Tk_Display (aMainWindow) : NULL;*/
1646       SetDisplayConnection (new Aspect_DisplayConnection (aDispX));
1647     }
1648   #else
1649     (void)theDisplayName; // avoid warning on unused argument
1650     SetDisplayConnection (new Aspect_DisplayConnection ());
1651   #endif
1652
1653     if (Draw_VirtualWindows)
1654     {
1655       // don't waste the time waiting for VSync when window is not displayed on the screen
1656       ViewerTest_myDefaultCaps.swapInterval = 0;
1657       // alternatively we can disable buffer swap at all, but this might be inappropriate for testing
1658       //ViewerTest_myDefaultCaps.buffersNoSwap = true;
1659     }
1660     aGraphicDriver = new OpenGl_GraphicDriver (GetDisplayConnection());
1661     aGraphicDriver->ChangeOptions() = ViewerTest_myDefaultCaps;
1662
1663     ViewerTest_myDrivers.Bind (aViewNames.GetDriverName(), aGraphicDriver);
1664     toCreateViewer = Standard_True;
1665   }
1666   else
1667   {
1668     aGraphicDriver = Handle(OpenGl_GraphicDriver)::DownCast (ViewerTest_myDrivers.Find1 (aViewNames.GetDriverName()));
1669   }
1670
1671   //Dispose the window if input parameters are default
1672   if (!ViewerTest_myViews.IsEmpty() && thePxLeft == 0 && thePxTop == 0)
1673   {
1674     Standard_Integer aTop = 0,
1675                      aLeft = 0,
1676                      aRight = 0,
1677                      aBottom = 0,
1678                      aScreenWidth = 0,
1679                      aScreenHeight = 0;
1680
1681     // Get screen resolution
1682 #if defined(_WIN32) || defined(__WIN32__)
1683     RECT aWindowSize;
1684     GetClientRect(GetDesktopWindow(), &aWindowSize);
1685     aScreenHeight = aWindowSize.bottom;
1686     aScreenWidth = aWindowSize.right;
1687 #elif defined(__APPLE__) && !defined(MACOSX_USE_GLX)
1688     GetCocoaScreenResolution (aScreenWidth, aScreenHeight);
1689 #else
1690     Screen *aScreen = DefaultScreenOfDisplay(GetDisplayConnection()->GetDisplay());
1691     aScreenWidth = WidthOfScreen(aScreen);
1692     aScreenHeight = HeightOfScreen(aScreen);
1693 #endif
1694
1695     TCollection_AsciiString anOverlappedViewId("");
1696
1697     while (IsWindowOverlapped (aPxLeft, aPxTop, aPxLeft + aPxWidth, aPxTop + aPxHeight, anOverlappedViewId))
1698     {
1699       ViewerTest_myViews.Find1(anOverlappedViewId)->Window()->Position (aLeft, aTop, aRight, aBottom);
1700
1701       if (IsWindowOverlapped (aRight + 20, aPxTop, aRight + 20 + aPxWidth, aPxTop + aPxHeight, anOverlappedViewId)
1702         && aRight + 2*aPxWidth + 40 > aScreenWidth)
1703       {
1704         if (aBottom + aPxHeight + 40 > aScreenHeight)
1705         {
1706           aPxLeft = 20;
1707           aPxTop = 40;
1708           break;
1709         }
1710         aPxLeft = 20;
1711         aPxTop = aBottom + 40;
1712       }
1713       else
1714         aPxLeft = aRight + 20;
1715     }
1716   }
1717
1718   // Get viewer name
1719   TCollection_AsciiString aTitle("3D View - ");
1720   aTitle = aTitle + aViewNames.GetViewName() + "(*)";
1721
1722   // Change name of current active window
1723   if (const Handle(V3d_View)& aCurrentView = ViewerTest::CurrentView())
1724   {
1725     aCurrentView->Window()->SetTitle (TCollection_AsciiString ("3D View - ") + ViewerTest_myViews.Find2 (aCurrentView));
1726   }
1727
1728   // Create viewer
1729   Handle(V3d_Viewer) a3DViewer;
1730   // If it's the single view, we first look for empty context
1731   if (ViewerTest_myViews.IsEmpty() && !ViewerTest_myContexts.IsEmpty())
1732   {
1733     NCollection_DoubleMap <TCollection_AsciiString, Handle(AIS_InteractiveContext)>::Iterator
1734       anIter(ViewerTest_myContexts);
1735     if (anIter.More())
1736       ViewerTest::SetAISContext (anIter.Value());
1737     a3DViewer = ViewerTest::GetAISContext()->CurrentViewer();
1738   }
1739   else if (ViewerTest_myContexts.IsBound1(aViewNames.GetViewerName()))
1740   {
1741     ViewerTest::SetAISContext(ViewerTest_myContexts.Find1(aViewNames.GetViewerName()));
1742     a3DViewer = ViewerTest::GetAISContext()->CurrentViewer();
1743   }
1744   else if (a3DViewer.IsNull())
1745   {
1746     toCreateViewer = Standard_True;
1747     a3DViewer = new V3d_Viewer(aGraphicDriver);
1748     a3DViewer->SetDefaultBackgroundColor (ViewerTest_DefaultBackground.FlatColor);
1749     a3DViewer->SetDefaultBgGradientColors (ViewerTest_DefaultBackground.GradientColor1,
1750                                            ViewerTest_DefaultBackground.GradientColor2,
1751                                            ViewerTest_DefaultBackground.FillMethod);
1752   }
1753
1754   // AIS context setup
1755   if (ViewerTest::GetAISContext().IsNull() ||
1756       !(ViewerTest_myContexts.IsBound1(aViewNames.GetViewerName())))
1757   {
1758     Handle(AIS_InteractiveContext) aContext = new AIS_InteractiveContext (a3DViewer);
1759     ViewerTest::SetAISContext (aContext);
1760     ViewerTest_myContexts.Bind (aViewNames.GetViewerName(), ViewerTest::GetAISContext());
1761   }
1762   else
1763   {
1764     ViewerTest::ResetEventManager();
1765   }
1766
1767   // Create window
1768 #if defined(_WIN32)
1769   VT_GetWindow() = new WNT_Window (aTitle.ToCString(),
1770                                     Handle(WNT_WClass)::DownCast (WClass()),
1771                                     Draw_VirtualWindows ? WS_POPUP : WS_OVERLAPPEDWINDOW,
1772                                     aPxLeft, aPxTop,
1773                                     aPxWidth, aPxHeight,
1774                                     Quantity_NOC_BLACK);
1775 #elif defined(__APPLE__) && !defined(MACOSX_USE_GLX)
1776   VT_GetWindow() = new Cocoa_Window (aTitle.ToCString(),
1777                                      aPxLeft, aPxTop,
1778                                      aPxWidth, aPxHeight);
1779   ViewerTest_SetCocoaEventManagerView (VT_GetWindow());
1780 #else
1781   VT_GetWindow() = new Xw_Window (aGraphicDriver->GetDisplayConnection(),
1782                                   aTitle.ToCString(),
1783                                   aPxLeft, aPxTop,
1784                                   aPxWidth, aPxHeight);
1785 #endif
1786   VT_GetWindow()->SetVirtual (Draw_VirtualWindows);
1787
1788   // View setup
1789   Handle(V3d_View) aView;
1790   if (!theViewToClone.IsNull())
1791   {
1792     aView = new ViewerTest_V3dView (a3DViewer, theViewToClone);
1793   }
1794   else
1795   {
1796     aView = new ViewerTest_V3dView (a3DViewer, a3DViewer->DefaultTypeOfView());
1797   }
1798
1799   aView->SetWindow (VT_GetWindow());
1800   ViewerTest::GetAISContext()->RedrawImmediate (a3DViewer);
1801
1802   ViewerTest::CurrentView(aView);
1803   ViewerTest_myViews.Bind (aViewNames.GetViewName(), aView);
1804
1805   // Setup for X11 or NT
1806   OSWindowSetup();
1807
1808   // Set parameters for V3d_View and V3d_Viewer
1809   const Handle (V3d_View) aV3dView = ViewerTest::CurrentView();
1810   aV3dView->SetComputedMode(Standard_False);
1811
1812   a3DViewer->SetDefaultBackgroundColor(Quantity_NOC_BLACK);
1813   if (toCreateViewer)
1814   {
1815     a3DViewer->SetDefaultLights();
1816     a3DViewer->SetLightOn();
1817   }
1818
1819 #if !defined(_WIN32) && (!defined(__APPLE__) || defined(MACOSX_USE_GLX))
1820   if (isNewDriver)
1821   {
1822     ::Display* aDispX = GetDisplayConnection()->GetDisplay();
1823     Tcl_CreateFileHandler (XConnectionNumber (aDispX), TCL_READABLE, VProcessEvents, (ClientData )aDispX);
1824   }
1825 #endif
1826
1827   VT_GetWindow()->Map();
1828
1829   // Set the handle of created view in the event manager
1830   ViewerTest::ResetEventManager();
1831
1832   ViewerTest::CurrentView()->Redraw();
1833
1834   aView.Nullify();
1835   a3DViewer.Nullify();
1836
1837   return aViewNames.GetViewName();
1838 }
1839
1840 //==============================================================================
1841 //function : RedrawAllViews
1842 //purpose  : Redraw all created views
1843 //==============================================================================
1844 void ViewerTest::RedrawAllViews()
1845 {
1846   NCollection_DoubleMap<TCollection_AsciiString, Handle(V3d_View)>::Iterator aViewIt(ViewerTest_myViews);
1847   for (; aViewIt.More(); aViewIt.Next())
1848   {
1849     const Handle(V3d_View)& aView = aViewIt.Key2();
1850     aView->Redraw();
1851   }
1852 }
1853
1854 //==============================================================================
1855 //function : Vinit
1856 //purpose  : Create the window viewer and initialize all the global variable
1857 //    Use Tk_CreateFileHandler on UNIX to catch the X11 Viewer event
1858 //==============================================================================
1859
1860 static int VInit (Draw_Interpretor& theDi, Standard_Integer theArgsNb, const char** theArgVec)
1861 {
1862   TCollection_AsciiString aViewName, aDisplayName;
1863   Standard_Integer aPxLeft = 0, aPxTop = 0, aPxWidth = 0, aPxHeight = 0;
1864   Handle(V3d_View) aCopyFrom;
1865   TCollection_AsciiString aName, aValue;
1866   int is2dMode = -1;
1867   for (Standard_Integer anArgIt = 1; anArgIt < theArgsNb; ++anArgIt)
1868   {
1869     const TCollection_AsciiString anArg = theArgVec[anArgIt];
1870     TCollection_AsciiString anArgCase = anArg;
1871     anArgCase.LowerCase();
1872     if (anArgIt + 1 < theArgsNb
1873      && anArgCase == "-name")
1874     {
1875       aViewName = theArgVec[++anArgIt];
1876     }
1877     else if (anArgIt + 1 < theArgsNb
1878           && (anArgCase == "-left"
1879            || anArgCase == "-l"))
1880     {
1881       aPxLeft = Draw::Atoi (theArgVec[++anArgIt]);
1882     }
1883     else if (anArgIt + 1 < theArgsNb
1884           && (anArgCase == "-top"
1885            || anArgCase == "-t"))
1886     {
1887       aPxTop = Draw::Atoi (theArgVec[++anArgIt]);
1888     }
1889     else if (anArgIt + 1 < theArgsNb
1890           && (anArgCase == "-width"
1891            || anArgCase == "-w"))
1892     {
1893       aPxWidth = Draw::Atoi (theArgVec[++anArgIt]);
1894     }
1895     else if (anArgIt + 1 < theArgsNb
1896           && (anArgCase == "-height"
1897            || anArgCase == "-h"))
1898     {
1899       aPxHeight = Draw::Atoi (theArgVec[++anArgIt]);
1900     }
1901     else if (anArgCase == "-exitonclose")
1902     {
1903       ViewerTest_EventManager::ToExitOnCloseView() = true;
1904       if (anArgIt + 1 < theArgsNb
1905        && ViewerTest::ParseOnOff (theArgVec[anArgIt + 1], ViewerTest_EventManager::ToExitOnCloseView()))
1906       {
1907         ++anArgIt;
1908       }
1909     }
1910     else if (anArgCase == "-closeonescape"
1911           || anArgCase == "-closeonesc")
1912     {
1913       ViewerTest_EventManager::ToCloseViewOnEscape() = true;
1914       if (anArgIt + 1 < theArgsNb
1915        && ViewerTest::ParseOnOff (theArgVec[anArgIt + 1], ViewerTest_EventManager::ToCloseViewOnEscape()))
1916       {
1917         ++anArgIt;
1918       }
1919     }
1920     else if (anArgCase == "-2d_mode"
1921           || anArgCase == "-2dmode"
1922           || anArgCase == "-2d")
1923     {
1924       bool toEnable = true;
1925       if (anArgIt + 1 < theArgsNb
1926        && ViewerTest::ParseOnOff (theArgVec[anArgIt + 1], toEnable))
1927       {
1928         ++anArgIt;
1929       }
1930       is2dMode = toEnable ? 1 : 0;
1931     }
1932     else if (anArgIt + 1 < theArgsNb
1933           && (anArgCase == "-disp"
1934            || anArgCase == "-display"))
1935     {
1936       aDisplayName = theArgVec[++anArgIt];
1937     }
1938     else if (!ViewerTest::CurrentView().IsNull()
1939           &&  aCopyFrom.IsNull()
1940           && (anArgCase == "-copy"
1941            || anArgCase == "-clone"
1942            || anArgCase == "-cloneactive"
1943            || anArgCase == "-cloneactiveview"))
1944     {
1945       aCopyFrom = ViewerTest::CurrentView();
1946     }
1947     // old syntax
1948     else if (ViewerTest::SplitParameter (anArg, aName, aValue))
1949     {
1950       aName.LowerCase();
1951       if (aName == "name")
1952       {
1953         aViewName = aValue;
1954       }
1955       else if (aName == "l"
1956             || aName == "left")
1957       {
1958         aPxLeft = aValue.IntegerValue();
1959       }
1960       else if (aName == "t"
1961             || aName == "top")
1962       {
1963         aPxTop = aValue.IntegerValue();
1964       }
1965       else if (aName == "disp"
1966             || aName == "display")
1967       {
1968         aDisplayName = aValue;
1969       }
1970       else if (aName == "w"
1971             || aName == "width")
1972       {
1973         aPxWidth = aValue.IntegerValue();
1974       }
1975       else if (aName == "h"
1976             || aName == "height")
1977       {
1978         aPxHeight = aValue.IntegerValue();
1979       }
1980       else
1981       {
1982         std::cout << "Syntax error: unknown argument " << anArg << ".\n";
1983         return 1;
1984       }
1985     }
1986     else if (aViewName.IsEmpty())
1987     {
1988       aViewName = anArg;
1989     }
1990     else
1991     {
1992       std::cout << "Syntax error: unknown argument " << anArg << ".\n";
1993       return 1;
1994     }
1995   }
1996
1997 #if defined(_WIN32) || (defined(__APPLE__) && !defined(MACOSX_USE_GLX))
1998   if (!aDisplayName.IsEmpty())
1999   {
2000     aDisplayName.Clear();
2001     std::cout << "Warning: display parameter will be ignored.\n";
2002   }
2003 #endif
2004
2005   ViewerTest_Names aViewNames (aViewName);
2006   if (ViewerTest_myViews.IsBound1 (aViewNames.GetViewName()))
2007   {
2008     TCollection_AsciiString aCommand = TCollection_AsciiString ("vactivate ") + aViewNames.GetViewName();
2009     theDi.Eval (aCommand.ToCString());
2010     if (is2dMode != -1)
2011     {
2012       ViewerTest_V3dView::SetCurrentView2DMode (is2dMode == 1);
2013     }
2014     return 0;
2015   }
2016
2017   TCollection_AsciiString aViewId = ViewerTest::ViewerInit (aPxLeft, aPxTop, aPxWidth, aPxHeight,
2018                                                             aViewName, aDisplayName, aCopyFrom);
2019   if (is2dMode != -1)
2020   {
2021     ViewerTest_V3dView::SetCurrentView2DMode (is2dMode == 1);
2022   }
2023   theDi << aViewId;
2024   return 0;
2025 }
2026
2027 //! Parse HLR algo type.
2028 static Standard_Boolean parseHlrAlgoType (const char* theName,
2029                                           Prs3d_TypeOfHLR& theType)
2030 {
2031   TCollection_AsciiString aName (theName);
2032   aName.LowerCase();
2033   if (aName == "polyalgo")
2034   {
2035     theType = Prs3d_TOH_PolyAlgo;
2036   }
2037   else if (aName == "algo")
2038   {
2039     theType = Prs3d_TOH_Algo;
2040   }
2041   else
2042   {
2043     return Standard_False;
2044   }
2045   return Standard_True;
2046 }
2047
2048 //==============================================================================
2049 //function : VHLR
2050 //purpose  : hidden lines removal algorithm
2051 //==============================================================================
2052
2053 static int VHLR (Draw_Interpretor& di, Standard_Integer argc, const char** argv)
2054 {
2055   const Handle(V3d_View) aView = ViewerTest::CurrentView();
2056   const Handle(AIS_InteractiveContext) aCtx = ViewerTest::GetAISContext();
2057   if (aView.IsNull())
2058   {
2059     std::cerr << "Error: No opened viewer!\n";
2060     return 1;
2061   }
2062
2063   Standard_Boolean hasHlrOnArg = Standard_False;
2064   Standard_Boolean hasShowHiddenArg = Standard_False;
2065   Standard_Boolean isHLROn = Standard_False;
2066   Standard_Boolean toShowHidden = aCtx->DefaultDrawer()->DrawHiddenLine();
2067   Prs3d_TypeOfHLR  aTypeOfHLR = Prs3d_TOH_NotSet;
2068   ViewerTest_AutoUpdater anUpdateTool (Handle(AIS_InteractiveContext)(), aView);
2069   for (Standard_Integer anArgIter = 1; anArgIter < argc; ++anArgIter)
2070   {
2071     TCollection_AsciiString anArg (argv[anArgIter]);
2072     anArg.LowerCase();
2073     if (anUpdateTool.parseRedrawMode (anArg))
2074     {
2075       continue;
2076     }
2077     else if (anArg == "-showhidden"
2078           && anArgIter + 1 < argc
2079           && ViewerTest::ParseOnOff (argv[anArgIter + 1], toShowHidden))
2080     {
2081       ++anArgIter;
2082       hasShowHiddenArg = Standard_True;
2083       continue;
2084     }
2085     else if ((anArg == "-type"
2086            || anArg == "-algo"
2087            || anArg == "-algotype")
2088           && anArgIter + 1 < argc
2089           && parseHlrAlgoType (argv[anArgIter + 1], aTypeOfHLR))
2090     {
2091       ++anArgIter;
2092       continue;
2093     }
2094     else if (!hasHlrOnArg
2095           && ViewerTest::ParseOnOff (argv[anArgIter], isHLROn))
2096     {
2097       hasHlrOnArg = Standard_True;
2098       continue;
2099     }
2100     // old syntax
2101     else if (!hasShowHiddenArg
2102           && ViewerTest::ParseOnOff(argv[anArgIter], toShowHidden))
2103     {
2104       hasShowHiddenArg = Standard_True;
2105       continue;
2106     }
2107     else
2108     {
2109       std::cout << "Syntax error at '" << argv[anArgIter] << "'\n";
2110       return 1;
2111     }
2112   }
2113   if (!hasHlrOnArg)
2114   {
2115     di << "HLR:        " << aView->ComputedMode() << "\n";
2116     di << "HiddenLine: " << aCtx->DefaultDrawer()->DrawHiddenLine() << "\n";
2117     di << "HlrAlgo:    ";
2118     switch (aCtx->DefaultDrawer()->TypeOfHLR())
2119     {
2120       case Prs3d_TOH_NotSet:   di << "NotSet\n";   break;
2121       case Prs3d_TOH_PolyAlgo: di << "PolyAlgo\n"; break;
2122       case Prs3d_TOH_Algo:     di << "Algo\n";     break;
2123     }
2124     anUpdateTool.Invalidate();
2125     return 0;
2126   }
2127
2128   Standard_Boolean toRecompute = Standard_False;
2129   if (aTypeOfHLR != Prs3d_TOH_NotSet
2130    && aTypeOfHLR != aCtx->DefaultDrawer()->TypeOfHLR())
2131   {
2132     toRecompute = Standard_True;
2133     aCtx->DefaultDrawer()->SetTypeOfHLR (aTypeOfHLR);
2134   }
2135   if (toShowHidden != aCtx->DefaultDrawer()->DrawHiddenLine())
2136   {
2137     toRecompute = Standard_True;
2138     if (toShowHidden)
2139     {
2140       aCtx->DefaultDrawer()->EnableDrawHiddenLine();
2141     }
2142     else
2143     {
2144       aCtx->DefaultDrawer()->DisableDrawHiddenLine();
2145     }
2146   }
2147
2148   // redisplay shapes
2149   if (aView->ComputedMode() && isHLROn && toRecompute)
2150   {
2151     AIS_ListOfInteractive aListOfShapes;
2152     aCtx->DisplayedObjects (aListOfShapes);
2153     for (AIS_ListIteratorOfListOfInteractive anIter (aListOfShapes); anIter.More(); anIter.Next())
2154     {
2155       if (Handle(AIS_Shape) aShape = Handle(AIS_Shape)::DownCast(anIter.Value()))
2156       {
2157         aCtx->Redisplay (aShape, Standard_False);
2158       }
2159     }
2160   }
2161
2162   aView->SetComputedMode (isHLROn);
2163   return 0;
2164 }
2165
2166 //==============================================================================
2167 //function : VHLRType
2168 //purpose  : change type of using HLR algorithm
2169 //==============================================================================
2170
2171 static int VHLRType (Draw_Interpretor& , Standard_Integer argc, const char** argv)
2172 {
2173   const Handle(V3d_View) aView = ViewerTest::CurrentView();
2174   const Handle(AIS_InteractiveContext) aCtx = ViewerTest::GetAISContext();
2175   if (aView.IsNull())
2176   {
2177     std::cerr << "Error: No opened viewer!\n";
2178     return 1;
2179   }
2180
2181   Prs3d_TypeOfHLR aTypeOfHLR = Prs3d_TOH_NotSet;
2182   ViewerTest_AutoUpdater anUpdateTool (Handle(AIS_InteractiveContext)(), aView);
2183   AIS_ListOfInteractive aListOfShapes;
2184   for (Standard_Integer anArgIter = 1; anArgIter < argc; ++anArgIter)
2185   {
2186     TCollection_AsciiString anArg (argv[anArgIter]);
2187     anArg.LowerCase();
2188     if (anUpdateTool.parseRedrawMode (anArg))
2189     {
2190       continue;
2191     }
2192     else if ((anArg == "-type"
2193            || anArg == "-algo"
2194            || anArg == "-algotype")
2195           && anArgIter + 1 < argc
2196           && parseHlrAlgoType (argv[anArgIter + 1], aTypeOfHLR))
2197     {
2198       ++anArgIter;
2199       continue;
2200     }
2201     // old syntax
2202     else if (aTypeOfHLR == Prs3d_TOH_NotSet
2203           && parseHlrAlgoType (argv[anArgIter], aTypeOfHLR))
2204     {
2205       continue;
2206     }
2207     else
2208     {
2209       ViewerTest_DoubleMapOfInteractiveAndName& aMap = GetMapOfAIS();
2210       TCollection_AsciiString aName (argv[anArgIter]);
2211       if (!aMap.IsBound2 (aName))
2212       {
2213         std::cout << "Syntax error: Wrong shape name '" << aName << "'.\n";
2214         return 1;
2215       }
2216
2217       Handle(AIS_Shape) aShape = Handle(AIS_Shape)::DownCast (aMap.Find2 (aName));
2218       if (aShape.IsNull())
2219       {
2220         std::cout << "Syntax error: '" << aName << "' is not a shape presentation.\n";
2221         return 1;
2222       }
2223       aListOfShapes.Append (aShape);
2224       continue;
2225     }
2226   }
2227   if (aTypeOfHLR == Prs3d_TOH_NotSet)
2228   {
2229     std::cout << "Syntax error: wrong number of arguments!\n";
2230     return 1;
2231   }
2232
2233   const Standard_Boolean isGlobal = aListOfShapes.IsEmpty();
2234   if (isGlobal)
2235   {
2236     aCtx->DisplayedObjects (aListOfShapes);
2237     aCtx->DefaultDrawer()->SetTypeOfHLR (aTypeOfHLR);
2238   }
2239
2240   for (AIS_ListIteratorOfListOfInteractive anIter(aListOfShapes); anIter.More(); anIter.Next())
2241   {
2242     Handle(AIS_Shape) aShape = Handle(AIS_Shape)::DownCast(anIter.Value());
2243     if (aShape.IsNull())
2244     {
2245       continue;
2246     }
2247
2248     const bool toUpdateShape = aShape->TypeOfHLR() != aTypeOfHLR
2249                             && aView->ComputedMode();
2250     if (!isGlobal
2251      || aShape->TypeOfHLR() != aTypeOfHLR)
2252     {
2253       aShape->SetTypeOfHLR (aTypeOfHLR);
2254     }
2255     if (toUpdateShape)
2256     {
2257       aCtx->Redisplay (aShape, Standard_False);
2258     }
2259   }
2260   return 0;
2261 }
2262
2263 //==============================================================================
2264 //function : FindViewIdByWindowHandle
2265 //purpose  : Find theView Id in the map of views by window handle
2266 //==============================================================================
2267 #if defined(_WIN32) || (!defined(__APPLE__) || defined(MACOSX_USE_GLX))
2268 TCollection_AsciiString FindViewIdByWindowHandle (Aspect_Drawable theWindowHandle)
2269 {
2270   for (NCollection_DoubleMap<TCollection_AsciiString, Handle(V3d_View)>::Iterator
2271        anIter(ViewerTest_myViews); anIter.More(); anIter.Next())
2272   {
2273     Aspect_Drawable aWindowHandle = anIter.Value()->Window()->NativeHandle();
2274     if (aWindowHandle == theWindowHandle)
2275       return anIter.Key1();
2276   }
2277   return TCollection_AsciiString("");
2278 }
2279 #endif
2280
2281 //! Make the view active
2282 void ActivateView (const TCollection_AsciiString& theViewName,
2283                    Standard_Boolean theToUpdate = Standard_True)
2284 {
2285   const Handle(V3d_View) aView = ViewerTest_myViews.Find1(theViewName);
2286   if (aView.IsNull())
2287   {
2288     return;
2289   }
2290
2291   Handle(AIS_InteractiveContext) anAISContext = FindContextByView(aView);
2292   if (!anAISContext.IsNull())
2293   {
2294     if (const Handle(V3d_View)& aCurrentView = ViewerTest::CurrentView())
2295     {
2296       aCurrentView->Window()->SetTitle (TCollection_AsciiString ("3D View - ") + ViewerTest_myViews.Find2 (aCurrentView));
2297     }
2298
2299     ViewerTest::CurrentView (aView);
2300     ViewerTest::SetAISContext (anAISContext);
2301     aView->Window()->SetTitle (TCollection_AsciiString("3D View - ") + theViewName + "(*)");
2302 #if defined(_WIN32)
2303     VT_GetWindow() = Handle(WNT_Window)::DownCast(ViewerTest::CurrentView()->Window());
2304 #elif defined(__APPLE__) && !defined(MACOSX_USE_GLX)
2305     VT_GetWindow() = Handle(Cocoa_Window)::DownCast(ViewerTest::CurrentView()->Window());
2306 #else
2307     VT_GetWindow() = Handle(Xw_Window)::DownCast(ViewerTest::CurrentView()->Window());
2308 #endif
2309     SetDisplayConnection(ViewerTest::CurrentView()->Viewer()->Driver()->GetDisplayConnection());
2310     if (theToUpdate)
2311     {
2312       ViewerTest::CurrentView()->Redraw();
2313     }
2314   }
2315 }
2316
2317 //==============================================================================
2318 //function : RemoveView
2319 //purpose  :
2320 //==============================================================================
2321 void ViewerTest::RemoveView (const Handle(V3d_View)& theView,
2322                              const Standard_Boolean  theToRemoveContext)
2323 {
2324   if (!ViewerTest_myViews.IsBound2 (theView))
2325   {
2326     return;
2327   }
2328
2329   const TCollection_AsciiString aViewName = ViewerTest_myViews.Find2 (theView);
2330   RemoveView (aViewName, theToRemoveContext);
2331 }
2332
2333 //==============================================================================
2334 //function : RemoveView
2335 //purpose  : Close and remove view from display, clear maps if neccessary
2336 //==============================================================================
2337 void ViewerTest::RemoveView (const TCollection_AsciiString& theViewName, const Standard_Boolean isContextRemoved)
2338 {
2339   if (!ViewerTest_myViews.IsBound1(theViewName))
2340   {
2341     cout << "Wrong view name\n";
2342     return;
2343   }
2344
2345   // Activate another view if it's active now
2346   if (ViewerTest_myViews.Find1(theViewName) == ViewerTest::CurrentView())
2347   {
2348     if (ViewerTest_myViews.Extent() > 1)
2349     {
2350       TCollection_AsciiString aNewViewName;
2351       for (NCollection_DoubleMap <TCollection_AsciiString, Handle(V3d_View)>::Iterator anIter (ViewerTest_myViews);
2352            anIter.More(); anIter.Next())
2353       {
2354         if (anIter.Key1() != theViewName)
2355         {
2356           aNewViewName = anIter.Key1();
2357           break;
2358         }
2359       }
2360       ActivateView (aNewViewName);
2361     }
2362     else
2363     {
2364       VT_GetWindow().Nullify();
2365       ViewerTest::CurrentView (Handle(V3d_View)());
2366       if (isContextRemoved)
2367       {
2368         Handle(AIS_InteractiveContext) anEmptyContext;
2369         ViewerTest::SetAISContext(anEmptyContext);
2370       }
2371     }
2372   }
2373
2374   // Delete view
2375   Handle(V3d_View) aView = ViewerTest_myViews.Find1(theViewName);
2376   Handle(AIS_InteractiveContext) aCurrentContext = FindContextByView(aView);
2377   ViewerTest_ContinuousRedrawer& aRedrawer = ViewerTest_ContinuousRedrawer::Instance();
2378   aRedrawer.Stop (aView->Window());
2379
2380   // Remove view resources
2381   ViewerTest_myViews.UnBind1(theViewName);
2382   aView->Window()->Unmap();
2383   aView->Remove();
2384
2385 #if !defined(_WIN32) && !defined(__WIN32__) && (!defined(__APPLE__) || defined(MACOSX_USE_GLX))
2386   XFlush (GetDisplayConnection()->GetDisplay());
2387 #endif
2388
2389   // Keep context opened only if the closed view is last to avoid
2390   // unused empty contexts
2391   if (!aCurrentContext.IsNull())
2392   {
2393     // Check if there are more difined views in the viewer
2394     aCurrentContext->CurrentViewer()->InitDefinedViews();
2395     if ((isContextRemoved || ViewerTest_myContexts.Size() != 1) && !aCurrentContext->CurrentViewer()->MoreDefinedViews())
2396     {
2397       // Remove driver if there is no viewers that use it
2398       Standard_Boolean isRemoveDriver = Standard_True;
2399       for(NCollection_DoubleMap<TCollection_AsciiString, Handle(AIS_InteractiveContext)>::Iterator
2400           anIter(ViewerTest_myContexts); anIter.More(); anIter.Next())
2401       {
2402         if (aCurrentContext != anIter.Key2() &&
2403           aCurrentContext->CurrentViewer()->Driver() == anIter.Value()->CurrentViewer()->Driver())
2404         {
2405           isRemoveDriver = Standard_False;
2406           break;
2407         }
2408       }
2409
2410       aCurrentContext->RemoveAll (Standard_False);
2411       if(isRemoveDriver)
2412       {
2413         ViewerTest_myDrivers.UnBind2 (aCurrentContext->CurrentViewer()->Driver());
2414       #if !defined(_WIN32) && !defined(__WIN32__) && (!defined(__APPLE__) || defined(MACOSX_USE_GLX))
2415         Tcl_DeleteFileHandler (XConnectionNumber (aCurrentContext->CurrentViewer()->Driver()->GetDisplayConnection()->GetDisplay()));
2416       #endif
2417       }
2418
2419       ViewerTest_myContexts.UnBind2(aCurrentContext);
2420     }
2421   }
2422   cout << "3D View - " << theViewName << " was deleted.\n";
2423   if (ViewerTest_EventManager::ToExitOnCloseView())
2424   {
2425     Draw_Interprete ("exit");
2426   }
2427 }
2428
2429 //==============================================================================
2430 //function : VClose
2431 //purpose  : Remove the view defined by its name
2432 //==============================================================================
2433
2434 static int VClose (Draw_Interpretor& /*theDi*/,
2435                    Standard_Integer  theArgsNb,
2436                    const char**      theArgVec)
2437 {
2438   NCollection_List<TCollection_AsciiString> aViewList;
2439   if (theArgsNb > 1)
2440   {
2441     TCollection_AsciiString anArg (theArgVec[1]);
2442     anArg.UpperCase();
2443     if (anArg.IsEqual ("ALL")
2444      || anArg.IsEqual ("*"))
2445     {
2446       for (NCollection_DoubleMap<TCollection_AsciiString, Handle(V3d_View)>::Iterator anIter (ViewerTest_myViews);
2447            anIter.More(); anIter.Next())
2448       {
2449         aViewList.Append (anIter.Key1());
2450       }
2451       if (aViewList.IsEmpty())
2452       {
2453         std::cout << "No view to close\n";
2454         return 0;
2455       }
2456     }
2457     else
2458     {
2459       ViewerTest_Names aViewName (theArgVec[1]);
2460       if (!ViewerTest_myViews.IsBound1 (aViewName.GetViewName()))
2461       {
2462         std::cerr << "The view with name '" << theArgVec[1] << "' does not exist\n";
2463         return 1;
2464       }
2465       aViewList.Append (aViewName.GetViewName());
2466     }
2467   }
2468   else
2469   {
2470     // close active view
2471     if (ViewerTest::CurrentView().IsNull())
2472     {
2473       std::cerr << "No active view!\n";
2474       return 1;
2475     }
2476     aViewList.Append (ViewerTest_myViews.Find2 (ViewerTest::CurrentView()));
2477   }
2478
2479   Standard_Boolean toRemoveContext = (theArgsNb != 3 || Draw::Atoi (theArgVec[2]) != 1);
2480   for (NCollection_List<TCollection_AsciiString>::Iterator anIter(aViewList);
2481        anIter.More(); anIter.Next())
2482   {
2483     ViewerTest::RemoveView (anIter.Value(), toRemoveContext);
2484   }
2485
2486   return 0;
2487 }
2488
2489 //==============================================================================
2490 //function : VActivate
2491 //purpose  : Activate the view defined by its ID
2492 //==============================================================================
2493
2494 static int VActivate (Draw_Interpretor& theDi, Standard_Integer theArgsNb, const char** theArgVec)
2495 {
2496   if (theArgsNb == 1)
2497   {
2498     theDi.Eval("vviewlist");
2499     return 0;
2500   }
2501
2502   TCollection_AsciiString aNameString;
2503   Standard_Boolean toUpdate = Standard_True;
2504   Standard_Boolean toActivate = Standard_True;
2505   for (Standard_Integer anArgIter = 1; anArgIter < theArgsNb; ++anArgIter)
2506   {
2507     TCollection_AsciiString anArg (theArgVec[anArgIter]);
2508     anArg.LowerCase();
2509     if (toUpdate
2510      && anArg == "-noupdate")
2511     {
2512       toUpdate = Standard_False;
2513     }
2514     else if (toActivate
2515           && aNameString.IsEmpty()
2516           && anArg == "none")
2517     {
2518       ViewerTest::CurrentView()->Window()->SetTitle (TCollection_AsciiString ("3D View - ") + ViewerTest_myViews.Find2 (ViewerTest::CurrentView()));
2519       VT_GetWindow().Nullify();
2520       ViewerTest::CurrentView (Handle(V3d_View)());
2521       ViewerTest::ResetEventManager();
2522       theDi << theArgVec[0] << ": all views are inactive\n";
2523       toActivate = Standard_False;
2524     }
2525     else if (toActivate
2526           && aNameString.IsEmpty())
2527     {
2528       aNameString = theArgVec[anArgIter];
2529     }
2530     else
2531     {
2532       std::cout << "Syntax error at '" << theArgVec[anArgIter] << "'\n";
2533       return 1;
2534     }
2535   }
2536
2537   if (!toActivate)
2538   {
2539     return 0;
2540   }
2541   else if (aNameString.IsEmpty())
2542   {
2543     std::cout << "Syntax error: wrong number of arguments\n";
2544     return 1;
2545   }
2546
2547   // Check if this view exists in the viewer with the driver
2548   ViewerTest_Names aViewNames (aNameString);
2549   if (!ViewerTest_myViews.IsBound1(aViewNames.GetViewName()))
2550   {
2551     theDi << "Syntax error: wrong view name '" << aNameString << "'\n";
2552     return 1;
2553   }
2554
2555   // Check if it is active already
2556   if (ViewerTest::CurrentView() == ViewerTest_myViews.Find1(aViewNames.GetViewName()))
2557   {
2558     theDi << theArgVec[0] << ": the view is active already\n";
2559     return 0;
2560   }
2561
2562   ActivateView (aViewNames.GetViewName(), toUpdate);
2563   return 0;
2564 }
2565
2566 //==============================================================================
2567 //function : VViewList
2568 //purpose  : Print current list of views per viewer and graphic driver ID
2569 //           shared between viewers
2570 //==============================================================================
2571
2572 static int VViewList (Draw_Interpretor& theDi, Standard_Integer theArgsNb, const char** theArgVec)
2573 {
2574   if (theArgsNb > 2)
2575   {
2576     theDi << theArgVec[0] << ": Wrong number of command arguments\n"
2577           << "Usage: " << theArgVec[0] << " name";
2578     return 1;
2579   }
2580   if (ViewerTest_myContexts.Size() < 1)
2581     return 0;
2582
2583   Standard_Boolean isTreeView =
2584     (( theArgsNb==1 ) || ( strcasecmp( theArgVec[1], "long" ) != 0 ));
2585
2586   if (isTreeView)
2587   {
2588     theDi << theArgVec[0] <<":\n";
2589   }
2590
2591   for (NCollection_DoubleMap <TCollection_AsciiString, Handle(Graphic3d_GraphicDriver)>::Iterator aDriverIter (ViewerTest_myDrivers);
2592        aDriverIter.More(); aDriverIter.Next())
2593   {
2594     if (isTreeView)
2595       theDi << aDriverIter.Key1() << ":\n";
2596
2597     for (NCollection_DoubleMap <TCollection_AsciiString, Handle(AIS_InteractiveContext)>::Iterator
2598       aContextIter(ViewerTest_myContexts); aContextIter.More(); aContextIter.Next())
2599     {
2600       if (aContextIter.Key1().Search(aDriverIter.Key1()) != -1)
2601       {
2602         if (isTreeView)
2603         {
2604           TCollection_AsciiString aContextName(aContextIter.Key1());
2605           theDi << " " << aContextName.Split(aDriverIter.Key1().Length() + 1) << ":\n";
2606         }
2607
2608         for (NCollection_DoubleMap <TCollection_AsciiString, Handle(V3d_View)>::Iterator aViewIter (ViewerTest_myViews);
2609              aViewIter.More(); aViewIter.Next())
2610         {
2611           if (aViewIter.Key1().Search(aContextIter.Key1()) != -1)
2612           {
2613             TCollection_AsciiString aViewName(aViewIter.Key1());
2614             if (isTreeView)
2615             {
2616               if (aViewIter.Value() == ViewerTest::CurrentView())
2617                 theDi << "  " << aViewName.Split(aContextIter.Key1().Length() + 1) << "(*)\n";
2618               else
2619                 theDi << "  " << aViewName.Split(aContextIter.Key1().Length() + 1) << "\n";
2620             }
2621             else
2622             {
2623               theDi << aViewName << " ";
2624             }
2625           }
2626         }
2627       }
2628     }
2629   }
2630   return 0;
2631 }
2632
2633 //==============================================================================
2634 //function : GetMousePosition
2635 //purpose  :
2636 //==============================================================================
2637 void ViewerTest::GetMousePosition (Standard_Integer& theX,
2638                                    Standard_Integer& theY)
2639 {
2640   if (Handle(ViewerTest_EventManager) aViewCtrl = ViewerTest::CurrentEventManager())
2641   {
2642     theX = aViewCtrl->LastMousePosition().x();
2643     theY = aViewCtrl->LastMousePosition().y();
2644   }
2645 }
2646
2647 //==============================================================================
2648 //function : VViewProj
2649 //purpose  : Switch view projection
2650 //==============================================================================
2651 static int VViewProj (Draw_Interpretor& ,
2652                       Standard_Integer theNbArgs,
2653                       const char** theArgVec)
2654 {
2655   static Standard_Boolean isYup = Standard_False;
2656   const Handle(V3d_View)& aView = ViewerTest::CurrentView();
2657   if (aView.IsNull())
2658   {
2659     std::cout << "Error: no active view\n";
2660     return 1;
2661   }
2662
2663   TCollection_AsciiString aCmdName (theArgVec[0]);
2664   Standard_Boolean isGeneralCmd = Standard_False;
2665   if (aCmdName == "vfront")
2666   {
2667     aView->SetProj (isYup ? V3d_TypeOfOrientation_Yup_Front : V3d_TypeOfOrientation_Zup_Front, isYup);
2668   }
2669   else if (aCmdName == "vback")
2670   {
2671     aView->SetProj (isYup ? V3d_TypeOfOrientation_Yup_Back : V3d_TypeOfOrientation_Zup_Back, isYup);
2672   }
2673   else if (aCmdName == "vtop")
2674   {
2675     aView->SetProj (isYup ? V3d_TypeOfOrientation_Yup_Top : V3d_TypeOfOrientation_Zup_Top, isYup);
2676   }
2677   else if (aCmdName == "vbottom")
2678   {
2679     aView->SetProj (isYup ? V3d_TypeOfOrientation_Yup_Bottom : V3d_TypeOfOrientation_Zup_Bottom, isYup);
2680   }
2681   else if (aCmdName == "vleft")
2682   {
2683     aView->SetProj (isYup ? V3d_TypeOfOrientation_Yup_Left : V3d_TypeOfOrientation_Zup_Left, isYup);
2684   }
2685   else if (aCmdName == "vright")
2686   {
2687     aView->SetProj (isYup ? V3d_TypeOfOrientation_Yup_Right : V3d_TypeOfOrientation_Zup_Right, isYup);
2688   }
2689   else if (aCmdName == "vaxo")
2690   {
2691     aView->SetProj (isYup ? V3d_TypeOfOrientation_Yup_AxoRight : V3d_TypeOfOrientation_Zup_AxoRight, isYup);
2692   }
2693   else
2694   {
2695     isGeneralCmd = Standard_True;
2696     for (Standard_Integer anArgIter = 1; anArgIter < theNbArgs; ++anArgIter)
2697     {
2698       TCollection_AsciiString anArgCase (theArgVec[anArgIter]);
2699       anArgCase.LowerCase();
2700       if (anArgCase == "-zup")
2701       {
2702         isYup = Standard_False;
2703       }
2704       else if (anArgCase == "-yup")
2705       {
2706         isYup = Standard_True;
2707       }
2708       else if (anArgCase == "-front"
2709             || anArgCase == "front"
2710             || anArgCase == "-f"
2711             || anArgCase == "f")
2712       {
2713         aView->SetProj (isYup ? V3d_TypeOfOrientation_Yup_Front : V3d_TypeOfOrientation_Zup_Front, isYup);
2714       }
2715       else if (anArgCase == "-back"
2716             || anArgCase == "back"
2717             || anArgCase == "-b"
2718             || anArgCase == "b")
2719       {
2720         aView->SetProj (isYup ? V3d_TypeOfOrientation_Yup_Back : V3d_TypeOfOrientation_Zup_Back, isYup);
2721       }
2722       else if (anArgCase == "-top"
2723             || anArgCase == "top"
2724             || anArgCase == "-t"
2725             || anArgCase == "t")
2726       {
2727         aView->SetProj (isYup ? V3d_TypeOfOrientation_Yup_Top : V3d_TypeOfOrientation_Zup_Top, isYup);
2728       }
2729       else if (anArgCase == "-bottom"
2730             || anArgCase == "bottom"
2731             || anArgCase == "-bot"
2732             || anArgCase == "bot"
2733             || anArgCase == "-b"
2734             || anArgCase == "b")
2735       {
2736         aView->SetProj (isYup ? V3d_TypeOfOrientation_Yup_Bottom : V3d_TypeOfOrientation_Zup_Bottom, isYup);
2737       }
2738       else if (anArgCase == "-left"
2739             || anArgCase == "left"
2740             || anArgCase == "-l"
2741             || anArgCase == "l")
2742       {
2743         aView->SetProj (isYup ? V3d_TypeOfOrientation_Yup_Left : V3d_TypeOfOrientation_Zup_Left, isYup);
2744       }
2745       else if (anArgCase == "-right"
2746             || anArgCase == "right"
2747             || anArgCase == "-r"
2748             || anArgCase == "r")
2749       {
2750         aView->SetProj (isYup ? V3d_TypeOfOrientation_Yup_Right : V3d_TypeOfOrientation_Zup_Right, isYup);
2751       }
2752       else if (anArgCase == "-axoleft"
2753             || anArgCase == "-leftaxo"
2754             || anArgCase == "axoleft"
2755             || anArgCase == "leftaxo")
2756       {
2757         aView->SetProj (isYup ? V3d_TypeOfOrientation_Yup_AxoLeft : V3d_TypeOfOrientation_Zup_AxoLeft, isYup);
2758       }
2759       else if (anArgCase == "-axo"
2760             || anArgCase == "axo"
2761             || anArgCase == "-a"
2762             || anArgCase == "a"
2763             || anArgCase == "-axoright"
2764             || anArgCase == "-rightaxo"
2765             || anArgCase == "axoright"
2766             || anArgCase == "rightaxo")
2767       {
2768         aView->SetProj (isYup ? V3d_TypeOfOrientation_Yup_AxoRight : V3d_TypeOfOrientation_Zup_AxoRight, isYup);
2769       }
2770       else if (anArgCase == "+x")
2771       {
2772         aView->SetProj (V3d_Xpos, isYup);
2773       }
2774       else if (anArgCase == "-x")
2775       {
2776         aView->SetProj (V3d_Xneg, isYup);
2777       }
2778       else if (anArgCase == "+y")
2779       {
2780         aView->SetProj (V3d_Ypos, isYup);
2781       }
2782       else if (anArgCase == "-y")
2783       {
2784         aView->SetProj (V3d_Yneg, isYup);
2785       }
2786       else if (anArgCase == "+z")
2787       {
2788         aView->SetProj (V3d_Zpos, isYup);
2789       }
2790       else if (anArgCase == "-z")
2791       {
2792         aView->SetProj (V3d_Zneg, isYup);
2793       }
2794       else if (anArgCase == "+x+y+z")
2795       {
2796         aView->SetProj (V3d_XposYposZpos, isYup);
2797       }
2798       else if (anArgCase == "+x+y-z")
2799       {
2800         aView->SetProj (V3d_XposYposZneg, isYup);
2801       }
2802       else if (anArgCase == "+x-y+z")
2803       {
2804         aView->SetProj (V3d_XposYnegZpos, isYup);
2805       }
2806       else if (anArgCase == "+x-y-z")
2807       {
2808         aView->SetProj (V3d_XposYnegZneg, isYup);
2809       }
2810       else if (anArgCase == "-x+y+z")
2811       {
2812         aView->SetProj (V3d_XnegYposZpos, isYup);
2813       }
2814       else if (anArgCase == "-x+y-z")
2815       {
2816         aView->SetProj (V3d_XnegYposZneg, isYup);
2817       }
2818       else if (anArgCase == "-x-y+z")
2819       {
2820         aView->SetProj (V3d_XnegYnegZpos, isYup);
2821       }
2822       else if (anArgCase == "-x-y-z")
2823       {
2824         aView->SetProj (V3d_XnegYnegZneg, isYup);
2825       }
2826       else if (anArgCase == "+x+y")
2827       {
2828         aView->SetProj (V3d_XposYpos, isYup);
2829       }
2830       else if (anArgCase == "+x-y")
2831       {
2832         aView->SetProj (V3d_XposYneg, isYup);
2833       }
2834       else if (anArgCase == "-x+y")
2835       {
2836         aView->SetProj (V3d_XnegYpos, isYup);
2837       }
2838       else if (anArgCase == "-x-y")
2839       {
2840         aView->SetProj (V3d_XnegYneg, isYup);
2841       }
2842       else if (anArgCase == "+x+z")
2843       {
2844         aView->SetProj (V3d_XposZpos, isYup);
2845       }
2846       else if (anArgCase == "+x-z")
2847       {
2848         aView->SetProj (V3d_XposZneg, isYup);
2849       }
2850       else if (anArgCase == "-x+z")
2851       {
2852         aView->SetProj (V3d_XnegZpos, isYup);
2853       }
2854       else if (anArgCase == "-x-z")
2855       {
2856         aView->SetProj (V3d_XnegZneg, isYup);
2857       }
2858       else if (anArgCase == "+y+z")
2859       {
2860         aView->SetProj (V3d_YposZpos, isYup);
2861       }
2862       else if (anArgCase == "+y-z")
2863       {
2864         aView->SetProj (V3d_YposZneg, isYup);
2865       }
2866       else if (anArgCase == "-y+z")
2867       {
2868         aView->SetProj (V3d_YnegZpos, isYup);
2869       }
2870       else if (anArgCase == "-y-z")
2871       {
2872         aView->SetProj (V3d_YnegZneg, isYup);
2873       }
2874       else if (anArgIter + 1 < theNbArgs
2875             && anArgCase == "-frame"
2876             && TCollection_AsciiString (theArgVec[anArgIter + 1]).Length() == 4)
2877       {
2878         TCollection_AsciiString aFrameDef (theArgVec[++anArgIter]);
2879         aFrameDef.LowerCase();
2880         gp_Dir aRight, anUp;
2881         if (aFrameDef.Value (2) == aFrameDef.Value (4))
2882         {
2883           std::cout << "Syntax error at '" << theArgVec[anArgIter] << "'\n";
2884           return 1;
2885         }
2886
2887         if (aFrameDef.Value (2) == 'x')
2888         {
2889           aRight = aFrameDef.Value (1) == '+' ? gp::DX() : -gp::DX();
2890         }
2891         else if (aFrameDef.Value (2) == 'y')
2892         {
2893           aRight = aFrameDef.Value (1) == '+' ? gp::DY() : -gp::DY();
2894         }
2895         else if (aFrameDef.Value (2) == 'z')
2896         {
2897           aRight = aFrameDef.Value (1) == '+' ? gp::DZ() : -gp::DZ();
2898         }
2899         else
2900         {
2901           std::cout << "Syntax error at '" << theArgVec[anArgIter] << "'\n";
2902           return 1;
2903         }
2904
2905         if (aFrameDef.Value (4) == 'x')
2906         {
2907           anUp = aFrameDef.Value (3) == '+' ? gp::DX() : -gp::DX();
2908         }
2909         else if (aFrameDef.Value (4) == 'y')
2910         {
2911           anUp = aFrameDef.Value (3) == '+' ? gp::DY() : -gp::DY();
2912         }
2913         else if (aFrameDef.Value (4) == 'z')
2914         {
2915           anUp = aFrameDef.Value (3) == '+' ? gp::DZ() : -gp::DZ();
2916         }
2917         else
2918         {
2919           std::cout << "Syntax error at '" << theArgVec[anArgIter] << "'\n";
2920           return 1;
2921         }
2922
2923         const Handle(Graphic3d_Camera)& aCamera = aView->Camera();
2924         const gp_Pnt anOriginVCS = aCamera->ConvertWorld2View (gp::Origin());
2925         const gp_Dir aDir = anUp.Crossed (aRight);
2926         aCamera->SetCenter (gp_Pnt (0, 0, 0));
2927         aCamera->SetDirection (aDir);
2928         aCamera->SetUp (anUp);
2929         aCamera->OrthogonalizeUp();
2930
2931         aView->Panning (anOriginVCS.X(), anOriginVCS.Y());
2932         aView->Update();
2933       }
2934       else
2935       {
2936         std::cout << "Syntax error at '" << theArgVec[anArgIter] << "'\n";
2937         return 1;
2938       }
2939     }
2940   }
2941
2942   if (!isGeneralCmd
2943     && theNbArgs != 1)
2944   {
2945     std::cout << "Syntax error: wrong number of arguments\n";
2946     return 1;
2947   }
2948   return 0;
2949 }
2950
2951 //==============================================================================
2952 //function : VHelp
2953 //purpose  : Dsiplay help on viewer Keyboead and mouse commands
2954 //Draw arg : No args
2955 //==============================================================================
2956
2957 static int VHelp(Draw_Interpretor& di, Standard_Integer , const char** )
2958 {
2959   di << "=========================\n";
2960   di << "F : FitAll\n";
2961   di << "T : TopView\n";
2962   di << "B : BottomView\n";
2963   di << "R : RightView\n";
2964   di << "L : LeftView\n";
2965   di << "A : AxonometricView\n";
2966   di << "D : ResetView\n";
2967
2968   di << "=========================\n";
2969   di << "S : Shading\n";
2970   di << "W : Wireframe\n";
2971   di << "H : HiddenLineRemoval\n";
2972   di << "U : Unset display mode\n";
2973   di << "Delete : Remove selection from viewer\n";
2974
2975   di << "=========================\n";
2976   di << "Selection mode \n";
2977   di << "0 : Shape\n";
2978   di << "1 : Vertex\n";
2979   di << "2 : Edge\n";
2980   di << "3 : Wire\n";
2981   di << "4 : Face\n";
2982   di << "5 : Shell\n";
2983   di << "6 : Solid\n";
2984   di << "7 : Compound\n";
2985
2986   di << "=========================\n";
2987   di << "< : Hilight next detected\n";
2988   di << "> : Hilight previous detected\n";
2989
2990   return 0;
2991 }
2992
2993 #ifdef _WIN32
2994
2995 static LRESULT WINAPI AdvViewerWindowProc (HWND theWinHandle,
2996                                            UINT theMsg,
2997                                            WPARAM wParam,
2998                                            LPARAM lParam )
2999 {
3000   if (ViewerTest_myViews.IsEmpty())
3001   {
3002     return ViewerWindowProc (theWinHandle, theMsg, wParam, lParam);
3003   }
3004
3005   switch (theMsg)
3006   {
3007     case WM_CLOSE:
3008     {
3009       // Delete view from map of views
3010       ViewerTest::RemoveView (FindViewIdByWindowHandle (theWinHandle));
3011       return 0;
3012     }
3013     case WM_ACTIVATE:
3014     {
3015       if (LOWORD(wParam) == WA_CLICKACTIVE
3016        || LOWORD(wParam) == WA_ACTIVE
3017        || ViewerTest::CurrentView().IsNull())
3018       {
3019         // Activate inactive window
3020         if (VT_GetWindow().IsNull()
3021          || (HWND )VT_GetWindow()->HWindow() != theWinHandle)
3022         {
3023           ActivateView (FindViewIdByWindowHandle (theWinHandle));
3024         }
3025       }
3026       break;
3027     }
3028     default:
3029     {
3030       return ViewerWindowProc (theWinHandle, theMsg, wParam, lParam);
3031     }
3032   }
3033   return 0;
3034 }
3035
3036 static LRESULT WINAPI ViewerWindowProc (HWND theWinHandle,
3037                                         UINT theMsg,
3038                                         WPARAM wParam,
3039                                         LPARAM lParam)
3040 {
3041   const Handle(V3d_View)& aView = ViewerTest::CurrentView();
3042   if (aView.IsNull())
3043   {
3044     return DefWindowProcW (theWinHandle, theMsg, wParam, lParam);
3045   }
3046
3047   switch (theMsg)
3048   {
3049     case WM_PAINT:
3050     {
3051       PAINTSTRUCT aPaint;
3052       BeginPaint(theWinHandle, &aPaint);
3053       EndPaint  (theWinHandle, &aPaint);
3054       ViewerTest::CurrentEventManager()->ProcessExpose();
3055       break;
3056     }
3057     case WM_SIZE:
3058     {
3059       ViewerTest::CurrentEventManager()->ProcessConfigure();
3060       break;
3061     }
3062     case WM_MOVE:
3063     case WM_MOVING:
3064     case WM_SIZING:
3065     {
3066       switch (aView->RenderingParams().StereoMode)
3067       {
3068         case Graphic3d_StereoMode_RowInterlaced:
3069         case Graphic3d_StereoMode_ColumnInterlaced:
3070         case Graphic3d_StereoMode_ChessBoard:
3071         {
3072           // track window moves to reverse stereo pair
3073           aView->MustBeResized();
3074           aView->Update();
3075           break;
3076         }
3077         default:
3078           break;
3079       }
3080       break;
3081     }
3082     case WM_KEYUP:
3083     case WM_KEYDOWN:
3084     {
3085       const Aspect_VKey aVKey = WNT_Window::VirtualKeyFromNative ((Standard_Integer )wParam);
3086       if (aVKey != Aspect_VKey_UNKNOWN)
3087       {
3088         const double aTimeStamp = ViewerTest::CurrentEventManager()->EventTime();
3089         if (theMsg == WM_KEYDOWN)
3090         {
3091           ViewerTest::CurrentEventManager()->KeyDown (aVKey, aTimeStamp);
3092         }
3093         else
3094         {
3095           ViewerTest::CurrentEventManager()->KeyUp (aVKey, aTimeStamp);
3096         }
3097         ViewerTest::CurrentEventManager()->FlushViewEvents (ViewerTest::GetAISContext(), ViewerTest::CurrentView(), true);
3098       }
3099       break;
3100     }
3101     case WM_LBUTTONUP:
3102     case WM_MBUTTONUP:
3103     case WM_RBUTTONUP:
3104     case WM_LBUTTONDOWN:
3105     case WM_MBUTTONDOWN:
3106     case WM_RBUTTONDOWN:
3107     {
3108       const Graphic3d_Vec2i aPos (LOWORD(lParam), HIWORD(lParam));
3109       const Aspect_VKeyFlags aFlags = WNT_Window::MouseKeyFlagsFromEvent (wParam);
3110       Aspect_VKeyMouse aButton = Aspect_VKeyMouse_NONE;
3111       switch (theMsg)
3112       {
3113         case WM_LBUTTONUP:
3114         case WM_LBUTTONDOWN:
3115           aButton = Aspect_VKeyMouse_LeftButton;
3116           break;
3117         case WM_MBUTTONUP:
3118         case WM_MBUTTONDOWN:
3119           aButton = Aspect_VKeyMouse_MiddleButton;
3120           break;
3121         case WM_RBUTTONUP:
3122         case WM_RBUTTONDOWN:
3123           aButton = Aspect_VKeyMouse_RightButton;
3124           break;
3125       }
3126       if (theMsg == WM_LBUTTONDOWN
3127        || theMsg == WM_MBUTTONDOWN
3128        || theMsg == WM_RBUTTONDOWN)
3129       {
3130         if (aButton == Aspect_VKeyMouse_LeftButton)
3131         {
3132           TheIsAnimating = Standard_False;
3133         }
3134
3135         SetFocus  (theWinHandle);
3136         SetCapture(theWinHandle);
3137         ViewerTest::CurrentEventManager()->PressMouseButton (aPos, aButton, aFlags, false);
3138       }
3139       else
3140       {
3141         ReleaseCapture();
3142         ViewerTest::CurrentEventManager()->ReleaseMouseButton (aPos, aButton, aFlags, false);
3143       }
3144       ViewerTest::CurrentEventManager()->FlushViewEvents (ViewerTest::GetAISContext(), ViewerTest::CurrentView(), true);
3145       break;
3146     }
3147     case WM_MOUSEWHEEL:
3148     {
3149       const int aDelta = GET_WHEEL_DELTA_WPARAM (wParam);
3150       const Standard_Real aDeltaF = Standard_Real(aDelta) / Standard_Real(WHEEL_DELTA);
3151       const Aspect_VKeyFlags aFlags = WNT_Window::MouseKeyFlagsFromEvent (wParam);
3152       Graphic3d_Vec2i aPos (int(short(LOWORD(lParam))), int(short(HIWORD(lParam))));
3153       POINT aCursorPnt = { aPos.x(), aPos.y() };
3154       if (ScreenToClient (theWinHandle, &aCursorPnt))
3155       {
3156         aPos.SetValues (aCursorPnt.x, aCursorPnt.y);
3157       }
3158
3159       ViewerTest::CurrentEventManager()->UpdateMouseScroll (Aspect_ScrollDelta (aPos, aDeltaF, aFlags));
3160       ViewerTest::CurrentEventManager()->FlushViewEvents (ViewerTest::GetAISContext(), ViewerTest::CurrentView(), true);
3161       break;
3162     }
3163     case WM_MOUSEMOVE:
3164     {
3165       Graphic3d_Vec2i aPos (LOWORD(lParam), HIWORD(lParam));
3166       Aspect_VKeyMouse aButtons = WNT_Window::MouseButtonsFromEvent (wParam);
3167       Aspect_VKeyFlags aFlags   = WNT_Window::MouseKeyFlagsFromEvent(wParam);
3168
3169       // don't make a slide-show from input events - fetch the actual mouse cursor position
3170       CURSORINFO aCursor;
3171       aCursor.cbSize = sizeof(aCursor);
3172       if (::GetCursorInfo (&aCursor) != FALSE)
3173       {
3174         POINT aCursorPnt = { aCursor.ptScreenPos.x, aCursor.ptScreenPos.y };
3175         if (ScreenToClient (theWinHandle, &aCursorPnt))
3176         {
3177           // as we override mouse position, we need overriding also mouse state
3178           aPos.SetValues (aCursorPnt.x, aCursorPnt.y);
3179           aButtons = WNT_Window::MouseButtonsAsync();
3180           aFlags   = WNT_Window::MouseKeyFlagsAsync();
3181         }
3182       }
3183
3184       if (VT_GetWindow().IsNull()
3185       || (HWND )VT_GetWindow()->HWindow() != theWinHandle)
3186       {
3187         // mouse move events come also for inactive windows
3188         break;
3189       }
3190
3191       ViewerTest::CurrentEventManager()->UpdateMousePosition (aPos, aButtons, aFlags, false);
3192       ViewerTest::CurrentEventManager()->FlushViewEvents (ViewerTest::GetAISContext(), aView, true);
3193       break;
3194     }
3195     default:
3196     {
3197       return DefWindowProcW (theWinHandle, theMsg, wParam, lParam);
3198     }
3199   }
3200   return 0L;
3201 }
3202
3203 //==============================================================================
3204 //function : ViewerMainLoop
3205 //purpose  : Get a Event on the view and dispatch it
3206 //==============================================================================
3207
3208 int ViewerMainLoop (Standard_Integer theNbArgs, const char** theArgVec)
3209 {
3210   Handle(ViewerTest_EventManager) aViewCtrl = ViewerTest::CurrentEventManager();
3211   if (aViewCtrl.IsNull()
3212    || theNbArgs < 4)
3213   {
3214     return 0;
3215   }
3216
3217   aViewCtrl->StartPickPoint (theArgVec[1], theArgVec[2], theArgVec[3]);
3218
3219   std::cout << "Start picking\n";
3220
3221   MSG aMsg;
3222   aMsg.wParam = 1;
3223   while (aViewCtrl->ToPickPoint())
3224   {
3225     // Wait for a VT_ProcessButton1Press() to toggle pick to 1 or 0
3226     if (GetMessageW (&aMsg, NULL, 0, 0))
3227     {
3228       TranslateMessage (&aMsg);
3229       DispatchMessageW (&aMsg);
3230     }
3231   }
3232
3233   std::cout << "Picking done\n";
3234   return 0;
3235 }
3236
3237 #elif !defined(__APPLE__) || defined(MACOSX_USE_GLX)
3238
3239 int min( int a, int b )
3240 {
3241   if( a<b )
3242     return a;
3243   else
3244     return b;
3245 }
3246
3247 int max( int a, int b )
3248 {
3249   if( a>b )
3250     return a;
3251   else
3252     return b;
3253 }
3254
3255 int ViewerMainLoop (Standard_Integer theNbArgs, const char** theArgVec)
3256 {
3257   static XEvent aReport;
3258   const Standard_Boolean toPick = theNbArgs > 0;
3259   if (theNbArgs > 0)
3260   {
3261     if (ViewerTest::CurrentEventManager().IsNull())
3262     {
3263       return 0;
3264     }
3265     ViewerTest::CurrentEventManager()->StartPickPoint (theArgVec[1], theArgVec[2], theArgVec[3]);
3266   }
3267
3268   Display* aDisplay = GetDisplayConnection()->GetDisplay();
3269   XNextEvent (aDisplay, &aReport);
3270
3271   // Handle event for the chosen display connection
3272   switch (aReport.type)
3273   {
3274     case ClientMessage:
3275     {
3276       if ((Atom)aReport.xclient.data.l[0] == GetDisplayConnection()->GetAtom(Aspect_XA_DELETE_WINDOW))
3277       {
3278         // Close the window
3279         ViewerTest::RemoveView(FindViewIdByWindowHandle (aReport.xclient.window));
3280         return toPick ? 0 : 1;
3281       }
3282       break;
3283     }
3284     case FocusIn:
3285     {
3286       // Activate inactive view
3287       Window aWindow = !VT_GetWindow().IsNull() ? VT_GetWindow()->XWindow() : 0;
3288       if (aWindow != aReport.xfocus.window)
3289       {
3290         ActivateView (FindViewIdByWindowHandle (aReport.xfocus.window));
3291       }
3292       break;
3293     }
3294     case Expose:
3295     {
3296       Window anXWindow = !VT_GetWindow().IsNull() ? VT_GetWindow()->XWindow() : 0;
3297       if (anXWindow == aReport.xexpose.window)
3298       {
3299         ViewerTest::CurrentEventManager()->ProcessExpose();
3300       }
3301
3302       // remove all the ExposureMask and process them at once
3303       for (int aNbMaxEvents = XPending (aDisplay); aNbMaxEvents > 0; --aNbMaxEvents)
3304       {
3305         if (!XCheckWindowEvent (aDisplay, anXWindow, ExposureMask, &aReport))
3306         {
3307           break;
3308         }
3309       }
3310
3311       break;
3312     }
3313     case ConfigureNotify:
3314     {
3315       // remove all the StructureNotifyMask and process them at once
3316       Window anXWindow = !VT_GetWindow().IsNull() ? VT_GetWindow()->XWindow() : 0;
3317       for (int aNbMaxEvents = XPending (aDisplay); aNbMaxEvents > 0; --aNbMaxEvents)
3318       {
3319         if (!XCheckWindowEvent (aDisplay, anXWindow, StructureNotifyMask, &aReport))
3320         {
3321           break;
3322         }
3323       }
3324
3325       if (anXWindow == aReport.xconfigure.window)
3326       {
3327         ViewerTest::CurrentEventManager()->ProcessConfigure();
3328       }
3329       break;
3330     }
3331     case KeyPress:
3332     case KeyRelease:
3333     {
3334       XKeyEvent*   aKeyEvent = (XKeyEvent* )&aReport;
3335       const KeySym aKeySym = XLookupKeysym (aKeyEvent, 0);
3336       const Aspect_VKey aVKey = Xw_Window::VirtualKeyFromNative (aKeySym);
3337       if (aVKey != Aspect_VKey_UNKNOWN)
3338       {
3339         const double aTimeStamp = ViewerTest::CurrentEventManager()->EventTime();
3340         if (aReport.type == KeyPress)
3341         {
3342           ViewerTest::CurrentEventManager()->KeyDown (aVKey, aTimeStamp);
3343         }
3344         else
3345         {
3346           ViewerTest::CurrentEventManager()->KeyUp (aVKey, aTimeStamp);
3347         }
3348         ViewerTest::CurrentEventManager()->FlushViewEvents (ViewerTest::GetAISContext(), ViewerTest::CurrentView(), true);
3349       }
3350       break;
3351     }
3352     case ButtonPress:
3353     case ButtonRelease:
3354     {
3355       const Graphic3d_Vec2i aPos (aReport.xbutton.x, aReport.xbutton.y);
3356       Aspect_VKeyFlags aFlags = Aspect_VKeyFlags_NONE;
3357       Aspect_VKeyMouse aButton = Aspect_VKeyMouse_NONE;
3358       if (aReport.xbutton.button == Button1)
3359       {
3360         aButton = Aspect_VKeyMouse_LeftButton;
3361       }
3362       if (aReport.xbutton.button == Button2)
3363       {
3364         aButton = Aspect_VKeyMouse_MiddleButton;
3365       }
3366       if (aReport.xbutton.button == Button3)
3367       {
3368         aButton = Aspect_VKeyMouse_RightButton;
3369       }
3370
3371       if (aReport.xbutton.state & ControlMask)
3372       {
3373         aFlags |= Aspect_VKeyFlags_CTRL;
3374       }
3375       if (aReport.xbutton.state & ShiftMask)
3376       {
3377         aFlags |= Aspect_VKeyFlags_SHIFT;
3378       }
3379       if (ViewerTest::CurrentEventManager()->Keys().IsKeyDown (Aspect_VKey_Alt))
3380       {
3381         aFlags |= Aspect_VKeyFlags_ALT;
3382       }
3383
3384       if (aReport.xbutton.button == Button4
3385        || aReport.xbutton.button&