Package gui

     $Name: v3r6 $
 $Revision: 1.2 $
     $Date: 2003/07/21 00:09:14 $

Access to source:

headers: the gui external header  directory
source: the src directory

Introduction

gui is a visualization and control package designed  for debugging of  reconstruction code.  It defines a 3-d display of lines, surfaces, and character data following the OpenGL model, and implements a default wire-frame viewer with keyboard control of orientation, perspective, and magnification of four independent views, which can be displayed simultaneously or individually. 

Its strength is in the rapid feedback allowed by tight integration with the code that is generating the geometrical data to be displayed, in that guiMgr can be used with a debugger, and it provides functions that allow stepping through stages of reconstruction. That is, the user can step through code that is generating data with geometrical representations, and watch the evolution of the display.

Display data can be written to a file in VRML format to use, e.g., the Cosmo viewer. There is convenient access to the menu system of the native GUI (Windows or X), allowing user-defined buttons and actions. This control is used by the package to provide menu buttons that hide/show individual graphical elements in the default display, with a cascading menu option. 

A separate package interfaces it to the Gaudi framework, see GuiSvc. There is no dependence on external packages.  Finally, it is light, there are less than 9K lines of code.

The GuiMgr object

A singleton object of the class GuiMgr handles initialization and gives access to all the functionality of the package.

GuiMgr * guiMgr = new GuiMgr;  // create the single GuiMgr object

or

GuiMgr * guiMgr = GuiMgr::instance(); // create if doesn't exist

The GuiMgr constructor creates an application window with a menu bar and a drawing area, and a console window for NT, but does not open the window or start the message loop until the method run is called. Before this, the user may set up display and menu items.  The display functions are accessible via the DisplayControl object, described next, and the menu by the Menu object, described after that. Finally a section describes the "event loop" functionality. Note that all gui symbols are in the gui namespace. 

Display

The display object started by GuiMgr is accessed via the display method

DisplayControl& display = GuiMgr::instance()->display();

To display an object, one must define a "rep", a class that inherits from the class DisplayRep, which in turn inherits from DisplayList.  DisplayList  is abstract, the user must define a method update. The following is a trivial example, which displays a marker at a point.

class PointRep : public gui::DisplayRep {
public:
  POintRep(const Hep3Vector* p):_p(p){}
  void update(){
     marker_at(*_p);
  }
private:
  const Hep3Vector* _p;
};

It would be used by creating an object (which must be on the heap), and passing a pointer to the display during setup.

SpacePoint p;
//...
display.add(new PointRep(&p));

This will add a PointRep object to the list managed by the DisplayControl object. It is deleted by the DisplayControl destructor. Presuming that the SpacePoint above changes each event, there is no need to do anything more.

Drawing to the screen uses a list of primitives managed by DisplayList. The update method generates this list, and the default clear erases it. In an event loop, the following sequence occurs:

  1. Begin event: clear. All reps are cleared, removing drawing instructions. The display, if refreshed, will be blank.
  2. User changes data that the reps have access to, like the SpacePoint above.
  3. End event: update. All reps have updates called, and display is refreshed with new display list.

Appending reps to an existing rep

After creating a rep, say to display a series of points, it is convenient to simply run the code in other reps. This done by the append method, which can be called in the update method of the original rep. For example, 

class PointListRep : public gui::DisplayRep {
public:
  PointListRep(const vector<Hep3Vector>& pl ):_pl(pl){};
  void update() {
    for(vector<SpacePoint>:const_iterator it=_pl.begin();
      it!=_pl.end(); ++it)
         append(PointRep(*it));
  }
private:
  const vector<Hep3Vector>& _pl
};

The append method calls the update method of its argument, then copies that rep's display list to its own. The rep that was copied can then be deleted, as happens in the example above. See the geomrep package for useful reps that will display various  geometry objects.

Static display

Note that the display of static detector objects should not be recreated. This is accomplished by overriding clear to do nothing, and returning from update if it has been already been called. But if the necessary data is available at initialization, it is more convenient to generate the display commands in the constructor.

Display with a show/hide button

The above example does not allow turning off the display of the point. (Except by disabling the entire display, see below.) An additional optional argument to DisplayControl::add provides this.

display->add(new PointRep(&p) "Point");

Now, a toggle button labeled "Point" will appear on the Display pull-down menu. A third optional argument governs whether it is  initially on or off. See the DisplayControl header for a more complete description

Display submenu

One can define cascading submenus with buttons for various components, each with a separate control. The method is

DisplayControl::SubMenu& sub =
	display->sub_menu("Points");

The reference sub in the example can have reps added to it, as

sub.add(new PointRep(&a), "Point A");

Display Options

The 3-d display is controlled by buttons on the Display menu  and by special keys. The menu options are:

axes
toggle to display the axes
Reference point
toggle (initially off) to display the 
coordinates of the reference point
Scale
toggle (initially off) that displays a scale bar
Set ref.pt...
Brings up a dialog box to set the reference point
Set magnification...
Brings up a dialog box to set the magnification factor
3D Enabled
toggle to enable the 3D display
2D Enabled
toggle to enable the 2D display
clear
Issue a "clear" to all DisplayReps
update
Issue an "update" to all DisplayReps
Dump to ...
Write the current screen contents to postscript (without color) or vrml
Print instructions
Write the list of keystroke controls to the standard output. (summarized below)

A left-mouse click in the drawing area moves the reference point (center of viewing area) transversely to the point clicked on. It is a convenient way to follow a track, for example. In Windows, a right-mouse click brings up the Display menu.

The keystroke commands that control the display appearance are

Left,Right
Up,Dn
move the viewpoint so the image appears to move in the desired direction
PgUp, PgDn zoom in, out (change magnification) (also m, s )
i,o move in, out (change perspective)
Home
r
reset view: restore all view port parameters to defaults for the selected view
0 (zero) toggle single/quad view
1,2,3,4 select view#
u refresh view
x,y,z select axis to use for rotation by the <> keys below
<, rotate the viewpoint left 1,10 degrees about the selected axis
>. rotate the viewpoint right 1, 10 degrees

Menu

Dove handles a the menu bar, with drop-down menus. This is accessible to the user, who can add buttons to the File menu, Display menu (as above), Print, and EventLoop menus or create new drop-down menu buttons on the menu bar. When a button is pushed, the windowing system generates a call to a Command object. That is, a user-defined class that inherits from Command and implements an execute method. A particularly useful way to generate such an object is to use the SimpleCommand<class Receiver> template.

The menu bar is accessible by, e.g.

Menu& menu = GuiMgr::instance()->menu();

To add a new drop-down menu:

SubMenu& submenu = menu.sub_menu("UserMenu");

Or to be able to add to the file menu:

SubMenu& filemenu = menu.file_menu();

Finally,  the "event loop" menu is available to add items to:

SubMenu& eventmenu = Dove::instance()->sub_menu();

A SubMenu (corresponding to a physical pull-down menu) has four  methods of interest:

void 	add_toggle(const std::string& label, bool state,
		Command* set, Command* unset);
void 	add_button(const std::string& label, Command* command);
void 	add_separator();
SubMenu& sub_menu(const std::string& label);

User input: the query methods

The menu object, by communication with the underlying GUI, allows simple data entry by a dialog box. The methods are:

void Menu::query(const std::string& ask, int* value);
void Menu::query(const std::string& ask, double* value, int count=1);
void Menu::query(const std::string& ask, float* value);
void Menu::query(const std::string& ask, std::string* value);

where ask is a prompt string, and value a pointer to the appropriate value or list.

Dialogbox message

The interface to the windowing system provides a simple modal output message box. An example is

guiMgr->gui().inform("This is a message");

Event Loop

The GuiMgr object provides methods that allow use of GuiMgr in an "event loop", that is a loop in which it is assumed that the display will completely change. Note that when the GUI is in control, it is in a "message loop", where it will remain until a message changes the status.

A pull-down menu, shown at right, gives user control. The public methods that can be used to implement a loop are:

void run(bool paused)
Starts the basic message loop. Must be called first. If paused is true, waits for further input. Otherwise returns after processing messages.
void begin_event()
Must be called at the start of the loop. Clears the display and checks for messages.
void end_event()
Must be called at the end of the event loop (following all user code that might change the display.) It updates the display, checks for and processes window system messages, and if in a paused state, enters a new message loop waiting for a step or run command. Otherwise resumes based on the pause interval: this is an integer representing the delay in ms before returning to the event loop, and starting the next event. It is initialized in the GuiMgr constructor (default -1meaning infinite), and can be changed in the GUI, under the EventLoop menu's "set pause interval".
bool done()
Returns true if user has pressed the Exit button on the File menu. Should be used to exit the event loop.
void pause()
Sets status to pause on next message loop (end_event or break_here), or, if already in such a loop, leave it. That is,  single step. User callable to set status to paused.
void resume()
 Sets status to skip the next message loop (or resume if paused in a loop).
void break_point(const std::string& title="[user pause]")
User can call to pause and optionally append title string. Display reps are updated and the display refreshed. Will actually pause if GuiMgr is in a paused state, controlled by space/cr keys or call to pause() as explained above.

Toby Burnett