// @(#)root/test:$name:  $:$id: stressGUI.cxx,v 1.0 exp $
// Author: Bertrand Bellenot

//
//    ROOT GUI test suite.
//
// The suite of programs below tests many elements of the ROOT GUI classes
//
// The test can only be run as a standalone program.
// To build and run it:
//
//    make stressGUI
//    stressGUI
//
// To get a short help:
//    stressGUI -help
//

#include <stdlib.h>
#include <time.h>
#include <Riostream.h>
#include <TString.h>
#include <TROOT.h>
#include <TClass.h>
#include <TEnv.h>
#include <TError.h>
#include <TBenchmark.h>
#include <TSystem.h>
#include <TApplication.h>
#include <TDatime.h>
#include <TFile.h>
#include <TObjArray.h>

#include <TGFrame.h>
#include <TImage.h>
#include <TCanvas.h>

#include <TMD5.h>
#include <TG3DLine.h>
#include <TGButton.h>
#include <TGButtonGroup.h>
#include <TGColorDialog.h>
#include <TGComboBox.h>
#include <TGLabel.h>
#include <TGListBox.h>
#include <TGListTree.h>
#include <TGMenu.h>
#include <TGMsgBox.h>
#include <TGNumberEntry.h>
#include <TGProgressBar.h>
#include <TGResourcePool.h>
#include <TGShutter.h>
#include <TGSimpleTable.h>
#include <TGTextEdit.h>
#include <TRootCanvas.h>
#include <TGTab.h>
#include <TGPack.h>
#include <TGColorDialog.h>
#include <TGFontDialog.h>
#include <TGTextEditDialogs.h>
#include <TGTableLayout.h>
#include <TGMdi.h>
#include <TGSlider.h>
#include <TGDoubleSlider.h>
#include <TGTripleSlider.h>
#include <TBrowser.h>
#include <TGPasswdDialog.h>
#include <TGImageMap.h>
#include <TASPaletteEditor.h>
#include <TControlBar.h>
#include <TGSpeedo.h>
#include <TGShapedFrame.h>
#include <TGSplitFrame.h>
#include <TGTextEditor.h>
#include <TRootHelpDialog.h>
#include <TGHtmlBrowser.h>
#include <HelpText.h>
#include <TSystemDirectory.h>
#include <TInterpreter.h>
#include <TStopwatch.h>

#include <TRecorder.h>

void     stressGUI();
void     ProcessFrame(TGFrame *f, const char *title);

// Tests functions.
void     testLayout();
void     testTextAlign();
void     testGroupState();
void     testLabels();
void     testSplitButton();
void     testTextEntries();
void     testListTree();
void     testShutter();
void     testProgressBar();
void     testNumberEntry();
void     testEditor();
void     testCanvas();
void     testColorDlg();
void     testFontDlg();
void     testSearchDlg();
void     testTableLayout();
void     testPack();
void     testSliders();
void     testBrowsers();
void     testSplitFrame();
void     testControlBars();
void     testHelpDialog();
void     testPaletteEditor();
void     testHtmlBrowser();

void     run_tutorials();
void     guitest_playback();
void     dnd_playback();
void     mditest_playback();
void     fitpanel_playback();
void     graph_edit_playback();

// Global variables.
RedirectHandle_t gRH;
Int_t    gTestNum = 0;
Bool_t   gOptionRef  = kFALSE;
Bool_t   gOptionKeep = kFALSE;
Bool_t   gOptionFull = kFALSE;
char     outfile[80];
char     gLine[80];
Int_t    sizes[100];
TString  gTmpfilename;
TString  gRootSys;

FILE    *sgref = 0;

//______________________________________________________________________________
int main(int argc, char *argv[])
{
   // Application main entry point.

   // use $ROOTSYS/etc/system.rootrc default values
   gEnv->ReadFile(TString::Format("%s/etc/system.rootrc",
                  gSystem->Getenv("ROOTSYS")), kEnvAll);
   gOptionRef  = kFALSE;
   gOptionKeep = kFALSE;
   gOptionFull = kFALSE;
   gTmpfilename = "stress-gui";
   FILE *f = gSystem->TempFileName(gTmpfilename);
   fclose(f);
   for (int i = 0; i < argc; i++) {
      if (!strcmp(argv[i], "-ref")) gOptionRef = kTRUE;
      if (!strcmp(argv[i], "-keep")) gOptionKeep = kTRUE;
      if (!strcmp(argv[i], "-full")) gOptionFull = kTRUE;
      if (!strcmp(argv[i], "-help") || !strcmp(argv[i], "-?")) {
         printf("Usage: stressGUI [-ref] [-keep] [-full] [-help] [-?] \n");
         printf("Options:\n");
         printf("\n");
         printf("  -ref: Generate the reference output file \"stressGUI.ref\"\n");
         printf("\n");
         printf("  -keep: Keep the png files even for passed tests\n");
         printf("        (by default the png files are deleted)\n");
         printf("\n");
         printf("  -full: Full test: replay also recorder sessions\n");
         printf("        (guitest, drag and drop, fitpanel, ...)\n");
         printf("\n");
         printf("  -help, -?: Print usage and exit\n");
         return 0;
      }
   }
   TApplication theApp("App", &argc, argv);
   gBenchmark = new TBenchmark();
   stressGUI();
   theApp.Terminate();
   return 0;
}

//______________________________________________________________________________
void stressGUI()
{
   // Run all stress GUI tests.

   if (gOptionRef) {
      sgref = fopen("stressGUI.ref", "wt");
   }
   else {
      // Read the reference file "stressGUI.ref"
      sgref = fopen("stressGUI.ref", "rt");
      if (sgref == 0) {
         printf("\nReference file \"stressGUI.ref\" not found!\n");
         printf("Please generate the reference file by executing\n");
         printf("stressGUI with the -ref flag, as shown below:\n");
         printf("   stressGUI -ref\n");
         gSystem->Unlink(gTmpfilename.Data());
         exit(0);
      }
      char line[160];
      Int_t i = -1;
      while (fgets(line, 160, sgref)) {
         if ((i >= 0) && (strlen(line) > 15)) {
            sscanf(&line[8],  "%d", &sizes[i]);
         }
         i++;
      }
      fclose(sgref);
   }
   gRootSys = gSystem->UnixPathName(gSystem->Getenv("ROOTSYS"));
#ifdef WIN32
   // remove the drive letter (e.g. "C:/") from $ROOTSYS, if any
   if (gRootSys[1] == ':' && gRootSys[2] == '/')
      gRootSys.Remove(0, 2);
#endif

   gVirtualX->Warp(gClient->GetDisplayWidth()-50, gClient->GetDisplayHeight()-50,
                   gClient->GetDefaultRoot()->GetId());
   // uncomment the next few lines to avoid (forbid) any mouse interaction
//   gVirtualX->GrabPointer(gClient->GetDefaultRoot()->GetId(), kButtonPressMask |
//                          kButtonReleaseMask | kPointerMotionMask, kNone,
//                          gVirtualX->CreateCursor(kWatch), kTRUE, kFALSE);

   if (gOptionRef) {
      fprintf(sgref, "Test#     Size#\n");
   } else {
      cout << "**********************************************************************" <<endl;
      cout << "*  Starting  GUI - S T R E S S suite                                 *" <<endl;
      cout << "**********************************************************************" <<endl;
   }
   gTestNum = 0;

   gBenchmark->Start("stressGUI");

   if (!gOptionRef) {
      cout << "*  Running macros in $ROOTSYS/tutorials/gui - S T R E S S            *" <<endl;
      cout << "**********************************************************************" <<endl;
   }
   run_tutorials();
   if (!gOptionRef) {
      cout << "**********************************************************************" <<endl;
      cout << "*  Starting Basic GUI Widgets - S T R E S S                          *" <<endl;
      cout << "**********************************************************************" <<endl;
   }
   testLayout();
   testTextAlign();
   testGroupState();
   testLabels();
   testSplitButton();
   testTextEntries();
   testListTree();
   testShutter();
   testProgressBar();
   testNumberEntry();
   testTableLayout();
   if (!gOptionRef) {
      cout << "**********************************************************************" <<endl;
      cout << "*  Starting High Level GUI Widgets - S T R E S S                     *" <<endl;
      cout << "**********************************************************************" <<endl;
   }
   testPack();
   testSearchDlg();
   testFontDlg();
   testColorDlg();
   testEditor();
   testCanvas();
   testSliders();
   testBrowsers();
   testSplitFrame();
   testControlBars();
   testHelpDialog();
   testPaletteEditor();
   testHtmlBrowser();

   if (!gOptionRef) {

      if (gOptionFull) {
         cout << "**********************************************************************" <<endl;
         cout << "*  Starting Drag and Drop playback - S T R E S S                     *" <<endl;
         cout << "**********************************************************************" <<endl;
         dnd_playback();

         cout << "**********************************************************************" <<endl;
         cout << "*  Starting MDI test playback - S T R E S S                          *" <<endl;
         cout << "**********************************************************************" <<endl;
         mditest_playback();

         cout << "**********************************************************************" <<endl;
         cout << "*  Starting guitest recorder playback - S T R E S S                  *" <<endl;
         cout << "**********************************************************************" <<endl;
         guitest_playback();

         cout << "**********************************************************************" <<endl;
         cout << "*  Starting fit panel recorder playback - S T R E S S                *" <<endl;
         cout << "**********************************************************************" <<endl;
         fitpanel_playback();

         cout << "**********************************************************************" <<endl;
         cout << "*  Starting graphic editors recorder playback - S T R E S S          *" <<endl;
         cout << "**********************************************************************" <<endl;
         graph_edit_playback();
      }
      cout << "**********************************************************************" <<endl;

      gBenchmark->Stop("stressGUI");

      //Print table with results
      Bool_t UNIX = strcmp(gSystem->GetName(), "Unix") == 0;
      if (UNIX) {
         TString sp = gSystem->GetFromPipe("uname -a");
         sp.Resize(60);
         printf("*  SYS: %s\n",sp.Data());
         if (strstr(gSystem->GetBuildNode(),"Linux")) {
            sp = gSystem->GetFromPipe("lsb_release -d -s");
            printf("*  SYS: %s\n",sp.Data());
         }
         if (strstr(gSystem->GetBuildNode(),"Darwin")) {
            sp  = gSystem->GetFromPipe("sw_vers -productVersion");
            sp += " Mac OS X ";
            printf("*  SYS: %s\n",sp.Data());
         }
      } else {
         const char *os = gSystem->Getenv("OS");
         if (!os) printf("*  SYS: Windows 95\n");
         else     printf("*  SYS: %s %s \n",os,gSystem->Getenv("PROCESSOR_IDENTIFIER"));
      }

      printf("**********************************************************************\n");
      printf("*  ");
      gBenchmark->Print("stressGUI");

      Double_t ct = gBenchmark->GetCpuTime("stressGUI");  // ref: 13 s
      Double_t rt = gBenchmark->GetRealTime("stressGUI"); // ref: 300 s
      // normalize at 1000 rootmarks
      Double_t full_marks = 0.5 *((13.0/ct) + (300.0/rt));
      if (!gOptionFull)
         full_marks = 0.5 *((4.5/ct) + (35.0/rt));
      const Double_t rootmarks = 1000.0 * full_marks;

      printf("**********************************************************************\n");
      printf("*  ROOTMARKS = %6.1f   *  Root%-8s  %d/%04d\n", rootmarks, gROOT->GetVersion(),
             gROOT->GetVersionDate(), gROOT->GetVersionTime());
      printf("**********************************************************************\n");
   }
   gVirtualX->GrabPointer(0, 0, 0, 0, kFALSE);  // ungrab pointer
   if (gOptionRef) {
      fclose(sgref);
   }
   gSystem->Unlink(gTmpfilename.Data());
#ifdef WIN32
   gSystem->Exec("erase /q /s TxtEdit* >nul 2>&1");
   gSystem->Exec("erase /q /s TxtView* >nul 2>&1");
#else
   gSystem->Exec("rm -f TxtEdit*");
   gSystem->Exec("rm -f TxtView*");
#endif
}

////////////////////////////////////////////////////////////////////////////////
//                                Utilities
////////////////////////////////////////////////////////////////////////////////

//______________________________________________________________________________
Int_t FileSize(const char *filename)
{
   // Return the size of the file "filename".

   FileStat_t fs;
   gSystem->GetPathInfo(filename, fs);
   return (Int_t)fs.fSize;
}

//______________________________________________________________________________
Bool_t VerifySize(const char *filename, const char *title)
{
   // Verify the file size.

   Int_t  ftol = 0;
   Bool_t success = kFALSE;
   Int_t fsize = FileSize(filename);
   // results depends on the files in $ROOTSYS/test
   if (strstr(title, "Browser")) ftol = 350;
   // not relevant as the CPU load and the background may vary...
   if (strstr(title, "CPUMeter.C")) ftol = 50000;
   if (strstr(title, "games.C")) ftol = 150;
   if (strstr(title, "ntupleTableTest.C")) ftol = 100;

   if (!gOptionRef) {
      if ((fsize < sizes[gTestNum] - ftol) || (fsize > sizes[gTestNum] + ftol))
         success = kFALSE;
      else
         success = kTRUE;

      sprintf(gLine,"Test %2d: %s", gTestNum, title);
      const Int_t nch = strlen(gLine);
      if (success) {
         cout << gLine;
         for (Int_t i = nch; i < 67; i++) cout << ".";
         cout << " OK" << endl;
      } else {
         cout << gLine;
         for (Int_t i = nch; i < 63; i++) cout << ".";
         cout << " FAILED" << endl;
         cout << "         File Size = "  << fsize << endl;
         cout << "          Ref Size = "  << sizes[gTestNum] << endl;
      }
   } else {
      fprintf(sgref, "%5d%10d\n", gTestNum, fsize);
      success = kTRUE;
   }
   if (!gOptionKeep && success) gSystem->Unlink(filename);
   return success;
}

//______________________________________________________________________________
void ProcessFrame(TGFrame *f, const char *title)
{
   // Save a capture of frame f in a png file.

   gClient->HandleInput();
   gSystem->Sleep(50);
   gSystem->ProcessEvents();
   gErrorIgnoreLevel = 9999;

   if (gOptionRef)
      sprintf(outfile, "sgui_%02d_ref.png", gTestNum);
   else
      sprintf(outfile, "sgui_%02d.png", gTestNum);

   TImage *img = TImage::Create();
   f->RaiseWindow();
   img->FromWindow(f->GetId());
   img->WriteImage(outfile);

   if (!gOptionRef) {
      if (!strstr(title, "Pack Frames") &&
          !strstr(title, "HTML Browser")) {
         gSystem->RedirectOutput(gTmpfilename.Data(), "w", &gRH);
         ((TGMainFrame *)f)->SaveSource(Form("sgui_%02d.C", gTestNum));
         gSystem->Unlink(Form("sgui_%02d.C", gTestNum));
         gSystem->RedirectOutput(0, 0, &gRH);
      }
   }
   VerifySize(outfile, title);

   delete img;
   gErrorIgnoreLevel = 0;
   gTestNum++;
}

//______________________________________________________________________________
void ProcessMacro(const char *macro, const char *title)
{
   // Verify the size of a png file generated from a root macro.

   Int_t   nbpass = 1, npass = 0;
   TString capture = macro;
   capture.ReplaceAll(".C", "_0.png");
   if (strstr(macro, "games.C")) nbpass = 3;
   if (strstr(macro, "galaxy_image.C")) nbpass = 2;

   while (npass < nbpass) {
      ++npass;
      capture.ReplaceAll(TString::Format("_%d.png", npass-1),
                         TString::Format("_%d.png", npass));
      VerifySize(capture.Data(), title);
      gTestNum++;
   }
}

//______________________________________________________________________________
void CloseMainframes()
{
   TClass* clGMainFrame = TClass::GetClass("TGMainFrame");
   TGWindow* win = 0;
   TIter iWin(gClient->GetListOfWindows());
   while ((win = (TGWindow*)iWin())) {
      const TObject* winGetParent = win->GetParent();
      Bool_t winIsMapped = kFALSE;
      if (winGetParent == gClient->GetDefaultRoot())
         winIsMapped = win->IsMapped();
      if (winIsMapped && win->InheritsFrom(clGMainFrame)) {
         ((TGMainFrame *)win)->CloseWindow();
         gSystem->Sleep(100);
      }
      gSystem->ProcessEvents();
   }
   gSystem->Sleep(100);
}

////////////////////////////////////////////////////////////////////////////////
//                            GUI Test code
////////////////////////////////////////////////////////////////////////////////

class ButtonLayoutWindow : public TGMainFrame {

private:
   TGTextButton *test, *draw, *help, *ok, *cancel, *exit;

public:
   ButtonLayoutWindow(const TGWindow *p, UInt_t w, UInt_t h);

};

//______________________________________________________________________________
ButtonLayoutWindow::ButtonLayoutWindow(const TGWindow *p, UInt_t w, UInt_t h) :
   TGMainFrame(p, w, h)
{
   // Create a container frames containing buttons

   SetCleanup(kDeepCleanup);
   // one button is resized up to the parent width. Note! this width should be fixed!
   TGVerticalFrame *hframe1 = new TGVerticalFrame(this, 170, 50, kFixedWidth);
   test = new TGTextButton(hframe1, "&Test ");
   // to take whole space we need to use kLHintsExpandX layout hints
   hframe1->AddFrame(test, new TGLayoutHints(kLHintsTop | kLHintsLeft | kLHintsExpandX,2,0,2,2));
   AddFrame(hframe1, new TGLayoutHints(kLHintsCenterX, 2, 2, 5, 1));

   // two buttons are resized up to the parent width. Note! this width should be fixed!
   TGCompositeFrame *cframe1 = new TGCompositeFrame(this, 170, 20, kHorizontalFrame | kFixedWidth);
   draw = new TGTextButton(cframe1, "&Draw");
   // to share whole parent space we need to use kLHintsExpandX layout hints
   cframe1->AddFrame(draw, new TGLayoutHints(kLHintsTop | kLHintsLeft | kLHintsExpandX,2,2,2,2));

   // button background will be set to yellow
   ULong_t yellow;
   gClient->GetColorByName("yellow", yellow);
   help = new TGTextButton(cframe1, "&Help");
   help->ChangeBackground(yellow);
   cframe1->AddFrame(help, new TGLayoutHints(kLHintsTop | kLHintsLeft | kLHintsExpandX,2,2,2,2));
   AddFrame(cframe1, new TGLayoutHints(kLHintsCenterX, 2, 2, 5, 1));

   // three buttons are resized up to the parent width. Note! this width should be fixed!
   TGCompositeFrame *cframe2 = new TGCompositeFrame(this, 170, 20, kHorizontalFrame | kFixedWidth);
   ok = new TGTextButton(cframe2, "OK");
   ok->SetFont("-adobe-helvetica-bold-r-*-*-12-*-*-*-*-*-iso8859-1");
   ok->SetEnabled(kFALSE);
   // to share whole parent space we need to use kLHintsExpandX layout hints
   cframe2->AddFrame(ok, new TGLayoutHints(kLHintsTop | kLHintsLeft | kLHintsExpandX,3,2,2,2));

   TGGC myGC = *gClient->GetResourcePool()->GetFrameGC();
   //TGFont *myfont = gClient->GetFont("-adobe-helvetica-bold-r-*-*-12-*-*-*-*-*-iso8859-1");

   cancel = new TGTextButton(cframe2, "Cancel ");
   cancel->SetText("&Cancel ");
   //if (myfont) cancel->SetFont(myfont->GetFontHandle());
   ok->SetEnabled(kTRUE);
   cancel->SetTextColor(yellow);
   cancel->SetState(kButtonEngaged);
   cframe2->AddFrame(cancel, new TGLayoutHints(kLHintsTop | kLHintsLeft | kLHintsExpandX,3,2,2,2));

   exit = new TGTextButton(cframe2, "&Exit ","gApplication->Terminate(0)");
   cframe2->AddFrame(exit, new TGLayoutHints(kLHintsTop | kLHintsLeft | kLHintsExpandX,2,0,2,2));
   exit->SetText("&Exit ");

   AddFrame(cframe2, new TGLayoutHints(kLHintsCenterX, 2, 2, 5, 1));

   SetWindowName("Buttons' Layout");
   MapSubwindows();
   Layout();
   Resize(GetDefaultSize());
   SetWMPosition(0, 0);
   MapWindow();
}

//______________________________________________________________________________
void testLayout()
{
   // Test layout and different states of some buttons.

   ButtonLayoutWindow *f = new ButtonLayoutWindow(gClient->GetRoot(), 100, 100);
   ProcessFrame((TGMainFrame*)f, "Buttons 1 (layout)");
   f->CloseWindow();
}

////////////////////////////////////////////////////////////////////////////////

class TextMargin : public TGHorizontalFrame {

protected:
   TGNumberEntry *fEntry;

public:
   TextMargin(const TGWindow *p, const char *name) : TGHorizontalFrame(p)
   {
      fEntry = new TGNumberEntry(this, 0, 6, -1, TGNumberFormat::kNESInteger);
      AddFrame(fEntry, new TGLayoutHints(kLHintsLeft));
      TGLabel *label = new TGLabel(this, name);
      AddFrame(label, new TGLayoutHints(kLHintsLeft, 10));
   }
   TGTextEntry *GetEntry() const { return fEntry->GetNumberEntry(); }

};

class TextAlignWindow : public TGMainFrame {

protected:
   TGTextButton *fButton;   // button being tested

public:
   TextAlignWindow();
   void SetTextPosition(Int_t hid, Int_t vid);

};

//______________________________________________________________________________
void TextAlignWindow::SetTextPosition(Int_t hid, Int_t vid)
{
   // Set text position (alignment).

   Int_t tj = fButton->GetTextJustify();
   tj &= ~kTextCenterX;
   tj &= ~kTextLeft;
   tj &= ~kTextRight;
   tj &= ~kTextCenterY;
   tj &= ~kTextTop;
   tj &= ~kTextBottom;
   tj |= hid;
   tj |= vid;
   fButton->SetTextJustify(tj);
}

//______________________________________________________________________________
TextAlignWindow::TextAlignWindow() : TGMainFrame(gClient->GetRoot(), 10, 10, kHorizontalFrame)
{
   // Main test window.

   SetCleanup(kDeepCleanup);

   // Controls on right
   TGVerticalFrame *controls = new TGVerticalFrame(this);
   AddFrame(controls, new TGLayoutHints(kLHintsRight | kLHintsExpandY, 5, 5, 5, 5));

   // Separator
   TGVertical3DLine *separator = new TGVertical3DLine(this);
   AddFrame(separator, new TGLayoutHints(kLHintsRight | kLHintsExpandY));

   // Contents
   TGHorizontalFrame *contents = new TGHorizontalFrame(this);
   AddFrame(contents, new TGLayoutHints(kLHintsLeft | kLHintsExpandX | kLHintsExpandY, 5, 5));

   // The button for test
   fButton = new TGTextButton(contents,
                      "&This button has a multi-line label\nand shows features\navailable in the button classes");
   fButton->Resize(300, 200);
   fButton->ChangeOptions(fButton->GetOptions() | kFixedSize);
   fButton->SetToolTipText("The assigned tooltip\ncan be multi-line also", 200);
   contents->AddFrame(fButton, new TGLayoutHints(kLHintsCenterX | kLHintsCenterY, 20, 20, 20, 20));

   TGGroupFrame *group = new TGGroupFrame(controls, "Enable/Disable");
   group->SetTitlePos(TGGroupFrame::kCenter);
   TGCheckButton *disable = new TGCheckButton(group, "Switch state\nEnable/Disable");
   disable->SetOn();
   group->AddFrame(disable, new TGLayoutHints(kLHintsExpandX | kLHintsExpandY));
   controls->AddFrame(group, new TGLayoutHints(kLHintsExpandX));

   // control horizontal position of the text
   TGButtonGroup *horizontal = new TGButtonGroup(controls, "Horizontal Position");
   horizontal->SetTitlePos(TGGroupFrame::kCenter);
   new TGRadioButton(horizontal, "Center", kTextCenterX);
   new TGRadioButton(horizontal, "Left", kTextLeft);
   new TGRadioButton(horizontal, "Right", kTextRight);
   horizontal->SetButton(kTextCenterX);
   controls->AddFrame(horizontal, new TGLayoutHints(kLHintsExpandX));

   // control vertical position of the text
   TGButtonGroup *vertical = new TGButtonGroup(controls, "Vertical Position");
   vertical->SetTitlePos(TGGroupFrame::kCenter);
   new TGRadioButton(vertical, "Center", kTextCenterY);
   new TGRadioButton(vertical, "Top", kTextTop);
   new TGRadioButton(vertical, "Bottom", kTextBottom);
   vertical->SetButton(kTextCenterY);
   controls->AddFrame(vertical, new TGLayoutHints(kLHintsExpandX));

   // control margins of the text
   TGGroupFrame *margins = new TGGroupFrame(controls, "Text Margins");
   margins->SetTitlePos(TGGroupFrame::kCenter);

   TextMargin *left = new TextMargin(margins, "Left");
   margins->AddFrame(left, new TGLayoutHints(kLHintsExpandX, 0, 0, 2, 2));

   TextMargin *right = new TextMargin(margins, "Right");
   margins->AddFrame(right, new TGLayoutHints(kLHintsExpandX, 0, 0, 2, 2));

   TextMargin *top = new TextMargin(margins, "Top");
   margins->AddFrame(top, new TGLayoutHints(kLHintsExpandX, 0, 0, 2, 2));

   TextMargin *bottom = new TextMargin(margins, "Bottom");
   margins->AddFrame(bottom, new TGLayoutHints(kLHintsExpandX, 0, 0, 2, 2));

   controls->AddFrame(margins, new TGLayoutHints(kLHintsExpandX));

   TGTextButton *quit = new TGTextButton(controls, "Quit");
   controls->AddFrame(quit, new TGLayoutHints(kLHintsBottom | kLHintsExpandX, 0, 0, 0, 5));

   SetWindowName("Button Test");
   MapSubwindows();
   Layout();
   Resize(GetDefaultSize());
   SetWMPosition(0, 0);
   MapWindow();
}

//______________________________________________________________________________
void testTextAlign()
{
   // Test different text alignments in a TGTextButton.

   TextAlignWindow *f = new TextAlignWindow();
   ProcessFrame((TGMainFrame*)f, "Buttons 2 (text alignment)");
   f->SetTextPosition(kTextLeft, kTextTop);
   ProcessFrame((TGMainFrame*)f, "Buttons 3 (text alignment)");
   f->SetTextPosition(kTextCenterX, kTextTop);
   ProcessFrame((TGMainFrame*)f, "Buttons 4 (text alignment)");
   f->SetTextPosition(kTextRight, kTextTop);
   ProcessFrame((TGMainFrame*)f, "Buttons 5 (text alignment)");
   f->SetTextPosition(kTextRight, kTextCenterY);
   ProcessFrame((TGMainFrame*)f, "Buttons 6 (text alignment)");
   f->SetTextPosition(kTextRight, kTextBottom);
   ProcessFrame((TGMainFrame*)f, "Buttons 7 (text alignment)");
   f->SetTextPosition(kTextCenterX, kTextBottom);
   ProcessFrame((TGMainFrame*)f, "Buttons 8 (text alignment)");
   f->SetTextPosition(kTextLeft, kTextBottom);
   ProcessFrame((TGMainFrame*)f, "Buttons 9 (text alignment)");
   f->SetTextPosition(kTextLeft, kTextCenterY);
   ProcessFrame((TGMainFrame*)f, "Buttons 10 (text alignment)");
   f->CloseWindow();
}

////////////////////////////////////////////////////////////////////////////////

class GroupStateWindow : public TGMainFrame {

public:
   TGTextButton        *fExit;         // Exit text button
   TGVButtonGroup      *fButtonGroup;  // Button group
   TGCheckButton       *fCheckb[4];    // Check buttons
   TGRadioButton       *fRadiob[2];    // Radio buttons

public:
   GroupStateWindow(const TGWindow *p, UInt_t w, UInt_t h);
};

//______________________________________________________________________________
GroupStateWindow::GroupStateWindow(const TGWindow *p, UInt_t w, UInt_t h) :
   TGMainFrame(p, w, h)
{
   // Main window constructor.

   SetCleanup(kDeepCleanup);

   TGHorizontalFrame *fHL2 = new TGHorizontalFrame(this, 70, 100);
   fCheckb[0] = new TGCheckButton(fHL2, new TGHotString("Enable BG"), 100);
   fCheckb[0]->SetToolTipText("Enable/Disable the button group");
   fHL2->AddFrame(fCheckb[0], new TGLayoutHints(kLHintsCenterX | kLHintsCenterY, 1, 1, 1, 1));
   fButtonGroup = new TGVButtonGroup(fHL2, "My Button Group");
   fCheckb[1] = new TGCheckButton(fButtonGroup, new TGHotString("CB 2"), 101);
   fCheckb[2] = new TGCheckButton(fButtonGroup, new TGHotString("CB 3"), 102);
   fCheckb[3] = new TGCheckButton(fButtonGroup, new TGHotString("CB 4"), 103);
   fRadiob[0] = new TGRadioButton(fButtonGroup, new TGHotString("RB 1"), 104);
   fRadiob[1] = new TGRadioButton(fButtonGroup, new TGHotString("RB 2"), 105);
   fButtonGroup->Show();

   fHL2->AddFrame(fButtonGroup, new TGLayoutHints(kLHintsCenterX | kLHintsCenterY, 1, 1, 1, 1));
   AddFrame(fHL2);

   TGHorizontalFrame *fHL3 = new TGHorizontalFrame(this, 70, 100, kFixedWidth);
   fExit = new TGTextButton(fHL3, "&Exit", 106);
   fHL3->AddFrame(fExit, new TGLayoutHints(kLHintsExpandX));
   AddFrame(fHL3, new TGLayoutHints(kLHintsCenterX | kLHintsCenterY, 1, 1, 1, 1));

   //Default state
   fCheckb[0]->SetOn();
   fButtonGroup->SetState(kTRUE);

   SetWindowName("My Button Group");
   MapSubwindows();
   Layout();
   Resize(GetDefaultSize());
   SetWMPosition(0, 0);
   MapWindow();

   fButtonGroup->SetRadioButtonExclusive(kTRUE);
   fRadiob[1]->SetOn();
};

//______________________________________________________________________________
void testGroupState()
{
   // Test enabled/disabled state of button group.

   GroupStateWindow *f = new GroupStateWindow(gClient->GetRoot(), 100, 100);
   ProcessFrame((TGMainFrame*)f, "Buttons 11 (group state)");
   f->fCheckb[0]->SetOn(kFALSE);
   f->fButtonGroup->SetState(kFALSE);
   ProcessFrame((TGMainFrame*)f, "Buttons 12 (group state)");

   f->CloseWindow();
}

////////////////////////////////////////////////////////////////////////////////

class LabelsWindow : public TGMainFrame {

private:
   TGLabel       *fLbl1, *fLbl2, *fLbl3, *fLbl4;
public:
   LabelsWindow(const TGWindow *p, UInt_t w, UInt_t h);
   void SwitchState();
};

//______________________________________________________________________________
LabelsWindow::LabelsWindow(const TGWindow *p, UInt_t w, UInt_t h) :
  TGMainFrame(p, w, h)
{
   // Main window constructor.

   SetCleanup(kDeepCleanup);
   // label + horizontal line
   TGGC *fTextGC;
   const TGFont *font = gClient->GetFont("-*-times-bold-r-*-*-18-*-*-*-*-*-*-*");
   if (!font)
      font = gClient->GetResourcePool()->GetDefaultFont();
   FontStruct_t labelfont = font->GetFontStruct();
   GCValues_t   gval;
   gval.fMask = kGCBackground | kGCFont | kGCForeground;
   gval.fFont = font->GetFontHandle();
   gClient->GetColorByName("yellow", gval.fBackground);
   fTextGC = gClient->GetGC(&gval, kTRUE);

   ULong_t bcolor, ycolor;
   gClient->GetColorByName("yellow", ycolor);
   gClient->GetColorByName("blue", bcolor);

   // Create a main frame
   fLbl1 = new TGLabel(this, "OwnFont & Bck/ForgrColor", fTextGC->GetGC(), labelfont, kChildFrame, bcolor);
   AddFrame(fLbl1, new TGLayoutHints(kLHintsNormal, 5, 5, 3, 4));
   fLbl1->SetTextColor(ycolor);

   fLbl2 = new TGLabel(this, "Own Font & ForegroundColor", fTextGC->GetGC(), labelfont);
   AddFrame(fLbl2,  new TGLayoutHints(kLHintsCenterX, 5, 5, 3, 4));
   fLbl2->SetTextColor(ycolor);

   fLbl3 = new TGLabel(this, "Normal Label");
   AddFrame(fLbl3,  new TGLayoutHints(kLHintsCenterX, 5, 5, 3, 4));

   fLbl4 = new TGLabel(this, "Multi-line label, resized\nto 300x80 pixels",
                       fTextGC->GetGC(), labelfont, kChildFrame, bcolor);
   AddFrame(fLbl4, new TGLayoutHints(kLHintsCenterX, 5, 5, 3, 4));
   fLbl4->SetTextColor(ycolor);
   fLbl4->ChangeOptions(fLbl4->GetOptions() | kFixedSize);
   fLbl4->Resize(350, 80);

   // Create a horizontal frame containing two buttons
   TGTextButton *toggle = new TGTextButton(this, "&Toggle Labels");
   toggle->SetToolTipText("Click on the button to toggle label's state (enable/disable)");
   AddFrame(toggle, new TGLayoutHints(kLHintsExpandX, 5, 5, 3, 4));
   TGTextButton *exit = new TGTextButton(this, "&Exit ");
   AddFrame(exit, new TGLayoutHints(kLHintsExpandX, 5, 5, 3, 4));

   // Set a name to the main frame
   SetWindowName("Labels");
   MapSubwindows();
   Layout();
   Resize(GetDefaultSize());
   SetWMPosition(0, 0);
   MapWindow();
}

//______________________________________________________________________________
void LabelsWindow::SwitchState()
{
   // Switch state of the labels.

   if (fLbl1->IsDisabled()) {
      fLbl1->Enable();
      fLbl2->Enable();
      fLbl3->Enable();
      fLbl4->Enable();
   } else {
      fLbl1->Disable();
      fLbl2->Disable();
      fLbl3->Disable();
      fLbl4->Disable();
   }
}

//______________________________________________________________________________
void testLabels()
{
   // Test different styles and the enabled/disabled state of labels.

   LabelsWindow *f = new LabelsWindow(gClient->GetRoot(), 200, 200);
   ProcessFrame((TGMainFrame*)f, "Labels 1");
   f->SwitchState();
   ProcessFrame((TGMainFrame*)f, "Labels 2");
   f->CloseWindow();
}

////////////////////////////////////////////////////////////////////////////////

class SplitButtonWindow : public TGMainFrame {

public:
   TGCheckButton *fCButton;
   TGCheckButton *fEButton;
   TGSplitButton *fMButton;  // Split Button
   TGPopupMenu   *fPopMenu;  // TGpopupMenu that will be attached to
                             // the button.
public:
   SplitButtonWindow(const TGWindow *p, UInt_t w, UInt_t h);

};

//______________________________________________________________________________
SplitButtonWindow::SplitButtonWindow(const TGWindow *p, UInt_t w, UInt_t h) :
   TGMainFrame(p, w, h)
{
   // Main window constructor.

   SetCleanup(kDeepCleanup);

   TGVerticalFrame *fVL = new TGVerticalFrame(this, 100, 100);
   TGHorizontalFrame *fHL = new TGHorizontalFrame(fVL, 100, 40);

   // Create a popup menu.
   fPopMenu = new TGPopupMenu(gClient->GetRoot());
   fPopMenu->AddEntry("Button &1", 1001);
   fPopMenu->AddEntry("Button &2", 1002);
   fPopMenu->DisableEntry(1002);
   fPopMenu->AddEntry("Button &3", 1003);
   fPopMenu->AddSeparator();

   // Create a split button, the menu is adopted.
   fMButton = new TGSplitButton(fHL, new TGHotString("Button &Options"),
                                fPopMenu, 1101);

   // It is possible to add entries later
   fPopMenu->AddEntry("En&try with really really long name", 1004);
   fPopMenu->AddEntry("&Exit", 1005);

   fCButton = new TGCheckButton(fHL, new TGHotString("Split"), 1102);
   fCButton->SetState(kButtonDown);

   // Add frames to their parent for layout.
   fHL->AddFrame(fCButton, new TGLayoutHints(kLHintsCenterX | kLHintsCenterY,
                                             0, 10, 0, 0));
   fEButton = new TGCheckButton(fHL, new TGHotString("Enable"), 1103);
   fEButton->SetState(kButtonDown);

   // Add frames to their parent for layout.
   fHL->AddFrame(fEButton, new TGLayoutHints(kLHintsCenterX | kLHintsCenterY,
                                             0, 10, 0, 0));
   fHL->AddFrame(fMButton, new TGLayoutHints(kLHintsCenterX | kLHintsCenterY));
   fVL->AddFrame(fHL, new TGLayoutHints(kLHintsCenterX | kLHintsCenterY));
   AddFrame(fVL, new TGLayoutHints(kLHintsCenterX | kLHintsCenterY));

   SetWindowName("SplitButton Test");
   MapSubwindows();
   Layout();
   Resize(GetDefaultSize());
   SetWMPosition(0, 0);
   MapWindow();
}

//______________________________________________________________________________
void testSplitButton()
{
   // Test the different configurations/states of a split button.

   SplitButtonWindow *f = new SplitButtonWindow(gClient->GetRoot(),100,100);
   f->fCButton->SetState(kButtonDown);
   f->fEButton->SetState(kButtonDown);
   f->fMButton->SetState(kButtonUp);
   f->fMButton->SetSplit(kTRUE);
   ProcessFrame((TGMainFrame*)f, "Split Button 1");
   f->fCButton->SetState(kButtonUp);
   f->fEButton->SetState(kButtonDown);
   f->fMButton->SetState(kButtonUp);
   f->fMButton->SetSplit(kFALSE);
   ProcessFrame((TGMainFrame*)f, "Split Button 2");
   f->fCButton->SetState(kButtonDown);
   f->fEButton->SetState(kButtonUp);
   f->fMButton->SetState(kButtonDisabled);
   f->fMButton->SetSplit(kTRUE);
   ProcessFrame((TGMainFrame*)f, "Split Button 3");
   f->fCButton->SetState(kButtonUp);
   f->fEButton->SetState(kButtonUp);
   f->fMButton->SetState(kButtonDisabled);
   f->fMButton->SetSplit(kFALSE);
   ProcessFrame((TGMainFrame*)f, "Split Button 4");
   f->CloseWindow();
}

////////////////////////////////////////////////////////////////////////////////

class GroupBox : public TGGroupFrame {
private:
   TGComboBox  *fCombo; // combo box
   TGTextEntry *fEntry; // text entry

public:
   GroupBox(const TGWindow *p, const char *name, const char *title);
   TGTextEntry *GetEntry() const { return fEntry; }
   TGComboBox  *GetCombo() const { return fCombo; }
};

//______________________________________________________________________________
GroupBox::GroupBox(const TGWindow *p, const char *name, const char *title) :
   TGGroupFrame(p, name)
{
   // Group frame containing combobox and text entry.

   TGHorizontalFrame *horz = new TGHorizontalFrame(this);
   AddFrame(horz, new TGLayoutHints(kLHintsExpandX | kLHintsCenterY));
   TGLabel *label = new TGLabel(horz, title);
   horz->AddFrame(label, new TGLayoutHints(kLHintsLeft | kLHintsCenterY));

   fCombo = new TGComboBox(horz);
   horz->AddFrame(fCombo, new TGLayoutHints(kLHintsRight | kLHintsExpandY,
                                            5, 0, 5, 5));
   fCombo->Resize(100, 20);

   fEntry = new TGTextEntry(this);
   AddFrame(fEntry, new TGLayoutHints(kLHintsExpandX | kLHintsCenterY));
}

////////////////////////////////////////////////////////////////////////////////

class TextEntryWindow : public TGMainFrame {

public:
   GroupBox    *fEcho;     // echo mode (echo, password, no echo)
   GroupBox    *fAlign;    // alignment (left, right, center)
   GroupBox    *fAccess;   // read-only mode
   GroupBox    *fBorder;   // border mode

public:
   TextEntryWindow();
};

//______________________________________________________________________________
TextEntryWindow::TextEntryWindow() : TGMainFrame(gClient->GetRoot(), 10, 10,
                                                 kVerticalFrame)
{
   // Main window constructor.

   TGComboBox  *combo;
   TGTextEntry *entry;

   // recusively delete all subframes on exit
   SetCleanup(kDeepCleanup);

   fEcho = new GroupBox(this, "Echo", "Mode:");
   AddFrame(fEcho, new TGLayoutHints(kLHintsExpandX | kLHintsExpandY, 5, 5));
   combo = fEcho->GetCombo();
   entry = fEcho->GetEntry();
   entry->SetText("The Quick Brown Fox Jumps");
   // add entries
   combo->AddEntry("Normal", TGTextEntry::kNormal);
   combo->AddEntry("Password", TGTextEntry::kPassword);
   combo->AddEntry("No Echo", TGTextEntry::kNoEcho);
   combo->Select(TGTextEntry::kNormal);

   fAlign = new GroupBox(this, "Alignment", "Type:");
   AddFrame(fAlign, new TGLayoutHints(kLHintsExpandX | kLHintsExpandY, 5, 5));
   combo = fAlign->GetCombo();
   entry = fAlign->GetEntry();
   entry->SetText("Over The Lazy Dog");
   // add entries
   combo->AddEntry("Left", kTextLeft);
   combo->AddEntry("Centered", kTextCenterX);
   combo->AddEntry("Right", kTextRight);
   combo->Select(kTextLeft);

   fAccess = new GroupBox(this, "Access", "Read-only:");
   AddFrame(fAccess, new TGLayoutHints(kLHintsExpandX | kLHintsExpandY, 5, 5));
   combo = fAccess->GetCombo();
   entry = fAccess->GetEntry();
   entry->SetText("The Quick Brown Fox Jumps");
   // add entries
   combo->AddEntry("False", 1);
   combo->AddEntry("True", 0);
   combo->Select(1);

   fBorder = new GroupBox(this, "Border", "Drawn:");
   AddFrame(fBorder, new TGLayoutHints(kLHintsExpandX | kLHintsExpandY, 5, 5));
   combo = fBorder->GetCombo();
   entry = fBorder->GetEntry();
   entry->SetText("Over The Lazy Dog");
   // add entries
   combo->AddEntry("False", 0);
   combo->AddEntry("True", 1);
   combo->Select(1);

   SetWindowName("Text Entries");
   MapSubwindows();
   Layout();
   Resize(GetDefaultSize());
   SetWMPosition(0, 0);
   MapWindow();
}

//______________________________________________________________________________
void testTextEntries()
{
   // Test the different modes available for text entries.

   TGComboBox  *combo;
   TGTextEntry *entry;

   TextEntryWindow *f = new TextEntryWindow();
   ProcessFrame((TGMainFrame*)f, "Text Entries 1");

   combo = f->fEcho->GetCombo();
   entry = f->fEcho->GetEntry();
   combo->Select(TGTextEntry::kPassword);
   entry->SetEchoMode(TGTextEntry::kPassword);

   combo = f->fAlign->GetCombo();
   entry = f->fAlign->GetEntry();
   combo->Select(kTextCenterX);
   entry->SetAlignment(kTextCenterX);

   combo = f->fAccess->GetCombo();
   entry = f->fAccess->GetEntry();
   combo->Select(0);
   entry->SetEnabled(0);

   combo = f->fBorder->GetCombo();
   entry = f->fBorder->GetEntry();
   combo->Select(0);
   entry->SetFrameDrawn(0);

   ProcessFrame((TGMainFrame*)f, "Text Entries 2");

   combo = f->fEcho->GetCombo();
   entry = f->fEcho->GetEntry();
   combo->Select(TGTextEntry::kNoEcho);
   entry->SetEchoMode(TGTextEntry::kNoEcho);

   combo = f->fAlign->GetCombo();
   entry = f->fAlign->GetEntry();
   combo->Select(kTextRight);
   entry->SetAlignment(kTextRight);

   combo = f->fAccess->GetCombo();
   entry = f->fAccess->GetEntry();
   combo->Select(1);
   entry->SetEnabled(1);

   combo = f->fBorder->GetCombo();
   entry = f->fBorder->GetEntry();
   combo->Select(1);
   entry->SetFrameDrawn(1);

   ProcessFrame((TGMainFrame*)f, "Text Entries 3");

   f->CloseWindow();
}

////////////////////////////////////////////////////////////////////////////////

class ListTreeWindow : public TGMainFrame {

private:
   TGListTree    *fListTree;
   TGCanvas      *fCanvas;
   TGViewPort    *fViewPort;
   TList         *fNamesList;
   TGTextButton  *fTextButton;

public:
   ListTreeWindow(const TGWindow *p, UInt_t w, UInt_t h);
   void FillListTree();
   void SwitchState();
};

//______________________________________________________________________________
ListTreeWindow::ListTreeWindow(const TGWindow *p, UInt_t w, UInt_t h) :
   TGMainFrame(p, w, h, kVerticalFrame)
{
   // Main window constructor.

   SetCleanup(kDeepCleanup);

   // canvas widget
   fCanvas = new TGCanvas(this, 300, 300);

   // canvas viewport
   fViewPort = fCanvas->GetViewPort();

   // list tree
   fListTree = new TGListTree(fCanvas, kHorizontalFrame);
   fListTree->SetCheckMode(TGListTree::kRecursive);

   fListTree->AddItem(0, "rootNode");

   fNamesList = new TList();

   TString *s1 = new TString("P1D/pclhcb08_CC-PC_HSys/CCPCAlg/Phist1");
   fNamesList->Add((TObject*)s1);

   TString *s2 = new TString("H1D/pclhcb08_CC-PC_HSys/CCPCAlg/TELL1Mult_$T3/L1/Q0/myTell");
   fNamesList->Add((TObject*)s2);

   TString *s3 = new TString("H1D/pclhcb08_CC-PC_HSys/CCPCAlg/TELL1Mult_$T3/L2/Q1/myTell");
   fNamesList->Add((TObject*)s3);

   TString *s4 = new TString("H1D/pclhcb08_CC-PC_HSys/CCPCAlg/TELL1Mult_$T3/L2/Q0/myTell");
   fNamesList->Add((TObject*)s4);

   TString *s5 = new TString("H2D/pclhcb08_CC-PC_HSys/CCPCAlg/Hist7");
   fNamesList->Add((TObject*)s5);

   TString *s6 = new TString("P1D/sdf/GaudiExample/xyProfile");
   fNamesList->Add((TObject*)s6);

   TString *s7 = new TString("H2D/sdf/GaudiExample/xyPositionPlot");
   fNamesList->Add((TObject*)s7);

   TString *s8 = new TString("H1D/sdf/GaudiExample/Mass");
   fNamesList->Add((TObject*)s8);

   TString *s9 = new TString("H1D/sdf/GaudiExample/eventtype");
   fNamesList->Add((TObject*)s9);

   AddFrame(fCanvas, new TGLayoutHints(kLHintsLeft | kLHintsTop |
                                       kLHintsExpandX | kLHintsExpandY, 5, 5, 5, 3));
   fTextButton = new TGTextButton(this,"Text &Button...");
   AddFrame(fTextButton, new TGLayoutHints(kLHintsLeft | kLHintsTop, 5, 5, 2, 5));

   FillListTree();

   SetWindowName("List Tree Test");
   MapSubwindows();
   Layout();
   Resize(490, 350);
   SetWMPosition(0, 0);
   MapWindow();
}

//______________________________________________________________________________
void ListTreeWindow::FillListTree()
{
   // Fill the list tree with some hierarchical structures.

   TString *listItem = 0;
   TGListTreeItem *node = 0, *histoNode = 0;

   TIter NextName(fNamesList);
   while ((listItem = (TString*)NextName())) {
      TObject *nameItem = 0;
      TObjArray *nameItems = listItem->Tokenize("/");
      TIter Next(nameItems);
      node = fListTree->GetFirstItem();
      fListTree->OpenItem(node);
      while ((nameItem = Next())) {
         if (fListTree->FindChildByName(node, nameItem->GetName())) {
            node = fListTree->FindChildByName(node, nameItem->GetName());
         } else {
            node = fListTree->AddItem(node, nameItem->GetName());
            fListTree->SetCheckBox(node, kTRUE);
            fListTree->ToggleItem(node);
            if (strcmp(nameItem->GetName(), "TELL1Mult_$T3"))
               fListTree->OpenItem(node);
            else
               fListTree->HighlightItem(node);
         }
         node->SetUserData(0);
         if (nameItem == nameItems->At(nameItems->GetEntriesFast()-2)) {
            histoNode = fListTree->AddItem(node, nameItems->Last()->GetName());
            fListTree->SetCheckBox(histoNode, kTRUE);
            fListTree->ToggleItem(histoNode);
            histoNode->SetUserData(listItem);
            break;
         }
      }
   }
   fListTree->ClearViewPort();
}

//______________________________________________________________________________
void ListTreeWindow::SwitchState()
{
   // Switch status of a couple of entries, to verify the propagation to
   // parent/children list tree items.

   TGListTreeItem *root = 0, *node = 0;
   root = fListTree->GetFirstItem();
   node = fListTree->FindChildByName(root, "P1D");
   if (node) node = fListTree->FindChildByName(node, "pclhcb08_CC-PC_HSys");
      if (node) fListTree->CheckAllChildren(node, kTRUE);
   if (node && node->GetParent()) node->GetParent()->UpdateState();

   node = fListTree->FindChildByName(root, "H1D");
   if (node) {
      fListTree->CheckAllChildren(node, kTRUE);
      node = fListTree->FindChildByName(node, "sdf");
      if (node) node = fListTree->FindChildByName(node, "GaudiExample");
         if (node) node = fListTree->FindChildByName(node, "eventtype");
            if (node) fListTree->CheckItem(node, kFALSE);
      while (node) {
         node->UpdateState();
         node = node->GetParent();
      }
   }
   fListTree->ClearViewPort();
}

//______________________________________________________________________________
void testListTree()
{
   // Test TGListTree and TGListTreeItems.

   ListTreeWindow *f = new ListTreeWindow(gClient->GetRoot(), 100, 100);
   ProcessFrame((TGMainFrame*)f, "List Tree 1");
   f->SwitchState();
   ProcessFrame((TGMainFrame*)f, "List Tree 2");
   f->CloseWindow();
}

////////////////////////////////////////////////////////////////////////////////

struct shutterData_t {
   const char *pixmap_name;
   const char *tip_text;
   Int_t       id;
   TGButton   *button;
};

shutterData_t histo_data[] = {
{ "h1_s.xpm",        "TH1",      1001,  0 },
{ "h2_s.xpm",        "TH2",      1002,  0 },
{ "h3_s.xpm",        "TH3",      1003,  0 },
{ "profile_s.xpm",   "TProfile", 1004,  0 },
{ 0,                 0,          0,     0 }
};

shutterData_t function_data[] = {
{ "f1_s.xpm",        "TF1",      2001,  0 },
{ "f2_s.xpm",        "TF2",      2002,  0 },
{ 0,                 0,          0,     0 }
};

shutterData_t tree_data[] = {
{ "ntuple_s.xpm",    "TNtuple",  3001,  0 },
{ "tree_s.xpm",      "TTree",    3002,  0 },
{ "chain_s.xpm",     "TChain",   3003,  0 },
{ 0,                 0,          0,     0 }
};


class ShutterWindow : public TGMainFrame {

private:
   TGShutter        *fShutter;
   TGLayoutHints    *fLayout;
   const TGPicture  *fDefaultPic;

public:
   ShutterWindow(const TGWindow *p, UInt_t w, UInt_t h);

   void AddShutterItem(const char *name, shutterData_t *data);
   void ToggleShutterItem(const char *name);
};

//______________________________________________________________________________
ShutterWindow::ShutterWindow(const TGWindow *p, UInt_t w, UInt_t h) :
   TGMainFrame(p, w, h, kVerticalFrame)
{
   // Create transient frame containing a shutter widget.

   // use hierarchical cleaning
   SetCleanup(kDeepCleanup);

   fDefaultPic = gClient->GetPicture("folder_s.xpm");
   fShutter = new TGShutter(this, kSunkenFrame);

   AddShutterItem("Histograms", histo_data);
   AddShutterItem("Functions", function_data);
   AddShutterItem("Trees", tree_data);

   fLayout = new TGLayoutHints(kLHintsExpandX | kLHintsExpandY);
   AddFrame(fShutter, fLayout);

   SetWindowName("Shutter Test");
   MapSubwindows();
   Layout();
   Resize(80, 300);
   SetWMPosition(0, 0);
   MapWindow();
}

//______________________________________________________________________________
void ShutterWindow::AddShutterItem(const char *name, shutterData_t *data)
{
   // Add item in the shutter.

   TGShutterItem    *item;
   TGCompositeFrame *container;
   TGPictureButton  *button;
   const TGPicture  *buttonpic;
   static int id = 5001;

   TGLayoutHints *l = new TGLayoutHints(kLHintsTop | kLHintsCenterX,
                                        5, 5, 5, 0);

   item = new TGShutterItem(fShutter, new TGHotString(name), id++);
   container = (TGCompositeFrame *) item->GetContainer();

   for (int i=0; data[i].pixmap_name != 0; i++) {
      buttonpic = gClient->GetPicture(data[i].pixmap_name);
      if (!buttonpic) {
         printf("<ShutterWindow::AddShutterItem>: missing pixmap \"%s\", using default",
                data[i].pixmap_name);
         buttonpic = fDefaultPic;
      }

      button = new TGPictureButton(container, buttonpic, data[i].id);

      button->SetPicture(buttonpic);
      if (i == 0)
         button->SetState(kButtonEngaged);
      else if (i == 1)
         button->SetState(kButtonDisabled);
      else
         button->SetDisabledPicture(buttonpic);

      container->AddFrame(button, l);
      button->SetToolTipText(data[i].tip_text);
      data[i].button = button;
   }

   fShutter->AddItem(item);
}

//______________________________________________________________________________
void ShutterWindow::ToggleShutterItem(const char *name)
{

   Long_t id = fShutter->GetItem(name)->WidgetId();
   SendMessage(fShutter, MK_MSG(kC_COMMAND, kCM_BUTTON), id, 0);
   for (int i=0; i<20;i++) {
      gSystem->ProcessEvents();
      gSystem->Sleep(10);
   }
}

//______________________________________________________________________________
void testShutter()
{
   // Test TGShutter widget.

   ShutterWindow *f = new ShutterWindow(gClient->GetRoot(), 400, 200);
   ProcessFrame((TGMainFrame*)f, "Shutter 1");
   f->ToggleShutterItem("Functions");
   ProcessFrame((TGMainFrame*)f, "Shutter 2");
   f->ToggleShutterItem("Trees");
   ProcessFrame((TGMainFrame*)f, "Shutter 3");
   f->CloseWindow();
}

////////////////////////////////////////////////////////////////////////////////

class ProgressbarWindow : public TGMainFrame {

private:
   TGHorizontalFrame *fHframe1;
   TGVerticalFrame   *fVframe1;
   TGLayoutHints     *fHint1, *fHint2, *fHint3, *fHint4, *fHint5;
   TGHProgressBar    *fHProg1, *fHProg2, *fHProg3;
   TGVProgressBar    *fVProg1, *fVProg2;
   TGTextButton      *fGO;

public:
   ProgressbarWindow(const TGWindow *p, UInt_t w, UInt_t h);

   void SetValues(Int_t ver);
};

//______________________________________________________________________________
ProgressbarWindow::ProgressbarWindow(const TGWindow *p, UInt_t w, UInt_t h) :
   TGMainFrame(p, w, h, kHorizontalFrame)
{
   // Main window constructor.

   // use hierarchical cleaning
   SetCleanup(kDeepCleanup);

   fHframe1 = new TGHorizontalFrame(this, 0, 0, 0);

   fVProg1 = new TGVProgressBar(fHframe1, TGProgressBar::kFancy, 300);
   fVProg1->SetBarColor("purple");
   fVProg2 = new TGVProgressBar(fHframe1, TGProgressBar::kFancy, 300);
   fVProg2->SetFillType(TGProgressBar::kBlockFill);
   fVProg2->SetBarColor("green");

   fHframe1->Resize(300, 300);

   fVframe1 = new TGVerticalFrame(this, 0, 0, 0);

   fHProg1 = new TGHProgressBar(fVframe1, 300);
   fHProg1->ShowPosition();
   fHProg2 = new TGHProgressBar(fVframe1, TGProgressBar::kFancy, 300);
   fHProg2->SetBarColor("lightblue");
   fHProg2->ShowPosition(kTRUE, kFALSE, "%.0f events");
   fHProg3 = new TGHProgressBar(fVframe1, TGProgressBar::kStandard, 300);
   fHProg3->SetFillType(TGProgressBar::kBlockFill);

   fGO = new TGTextButton(fVframe1, "Go", 10);

   fVframe1->Resize(300, 300);

   fHint1 = new TGLayoutHints(kLHintsTop | kLHintsLeft | kLHintsExpandY, 5, 10, 5, 5);
   fHint2 = new TGLayoutHints(kLHintsTop | kLHintsLeft | kLHintsExpandX, 5, 5,  5, 10);
   fHint3 = new TGLayoutHints(kLHintsTop | kLHintsRight, 0, 50, 50, 0);
   fHint4 = new TGLayoutHints(kLHintsTop | kLHintsLeft | kLHintsExpandY, 0, 0, 0, 0);
   fHint5 = new TGLayoutHints(kLHintsTop | kLHintsLeft | kLHintsExpandX, 0, 0, 0, 0);

   fHframe1->AddFrame(fVProg1, fHint1);
   fHframe1->AddFrame(fVProg2, fHint1);

   fVframe1->AddFrame(fHProg1, fHint2);
   fVframe1->AddFrame(fHProg2, fHint2);
   fVframe1->AddFrame(fHProg3, fHint2);
   fVframe1->AddFrame(fGO,     fHint3);

   AddFrame(fHframe1, fHint4);
   AddFrame(fVframe1, fHint5);

   SetWindowName("Text Entries");
   MapSubwindows();
   Layout();
   Resize(GetDefaultSize());
   SetWMPosition(0, 0);
   MapWindow();
}

//______________________________________________________________________________
void ProgressbarWindow::SetValues(Int_t ver)
{
   // Set some values to our progress bars.

   fVProg1->Reset(); fVProg2->Reset();
   fHProg1->Reset(); fHProg2->Reset(); fHProg3->Reset();
   if (ver == 0) {
      fVProg2->SetBarColor("green");
      fVProg1->SetPosition(25.0);
      fVProg2->SetPosition(50.0);
      fHProg1->SetPosition(0.0);
      fHProg2->SetPosition(25.0);
      fHProg3->SetPosition(50.0);
   }
   else {
      fVProg2->SetBarColor("red");
      fVProg1->SetPosition(50.0);
      fVProg2->SetPosition(75.0);
      fHProg1->SetPosition(50.0);
      fHProg2->SetPosition(75.0);
      fHProg3->SetPosition(100.0);
   }
}

//______________________________________________________________________________
void testProgressBar()
{
   // Test several styles of progress bar.

   ProgressbarWindow *f = new ProgressbarWindow(gClient->GetRoot(), 600, 300);
   f->SetValues(0);
   ProcessFrame((TGMainFrame*)f, "Progress Bars 1");
   f->SetValues(1);
   ProcessFrame((TGMainFrame*)f, "Progress Bars 2");
   f->CloseWindow();
}

////////////////////////////////////////////////////////////////////////////////

class NumberEntryWindow : public TGMainFrame {

private:
   TGVerticalFrame      *fF1;
   TGVerticalFrame      *fF2;
   TGHorizontalFrame    *fF[13];
   TGLayoutHints        *fL1;
   TGLayoutHints        *fL2;
   TGLayoutHints        *fL3;
   TGLabel              *fLabel[13];
   TGNumberEntry        *fNumericEntries[13];
   TGCheckButton        *fLowerLimit;
   TGCheckButton        *fUpperLimit;
   TGNumberEntry        *fLimits[2];
   TGCheckButton        *fPositive;
   TGCheckButton        *fNonNegative;
   TGButton             *fSetButton;
   TGButton             *fExitButton;

public:
   NumberEntryWindow(const TGWindow *p);
};

const char *numlabel[] = {
   "Integer",
   "One digit real",
   "Two digit real",
   "Three digit real",
   "Four digit real",
   "Real",
   "Degree.min.sec",
   "Min:sec",
   "Hour:min",
   "Hour:min:sec",
   "Day/month/year",
   "Month/day/year",
   "Hex"
};

const Double_t numinit[] = {
   12345, 1.0, 1.00, 1.000, 1.0000, 1.2E-12,
   90 * 3600, 120 * 60, 12 * 60, 12 * 3600 + 15 * 60,
   19991121, 19991121, (Double_t) 0xDEADFACEU
};

//______________________________________________________________________________
NumberEntryWindow::NumberEntryWindow(const TGWindow *p) :
   TGMainFrame(p, 10, 10, kHorizontalFrame)
{
   // Main window constructor.

   // use hierarchical cleaning
   SetCleanup(kDeepCleanup);

   TGGC myGC = *gClient->GetResourcePool()->GetFrameGC();
   TGFont *myfont = gClient->GetFont("-adobe-helvetica-bold-r-*-*-12-*-*-*-*-*-iso8859-1");
   if (myfont) myGC.SetFont(myfont->GetFontHandle());

   fF1 = new TGVerticalFrame(this, 200, 300);
   fL1 = new TGLayoutHints(kLHintsTop | kLHintsLeft, 2, 2, 2, 2);
   AddFrame(fF1, fL1);
   fL2 = new TGLayoutHints(kLHintsCenterY | kLHintsLeft, 2, 2, 2, 2);
   for (int i = 0; i < 13; i++) {
      fF[i] = new TGHorizontalFrame(fF1, 200, 30);
      fF1->AddFrame(fF[i], fL2);
      fNumericEntries[i] = new TGNumberEntry(fF[i], numinit[i], 12, i + 20,
                                             (TGNumberFormat::EStyle) i);
      fF[i]->AddFrame(fNumericEntries[i], fL2);
      fLabel[i] = new TGLabel(fF[i], numlabel[i], myGC(), myfont->GetFontStruct());
      fF[i]->AddFrame(fLabel[i], fL2);
   }
   fF2 = new TGVerticalFrame(this, 200, 500);
   fL3 = new TGLayoutHints(kLHintsTop | kLHintsLeft, 2, 2, 2, 2);
   AddFrame(fF2, fL3);
   fLowerLimit = new TGCheckButton(fF2, "lower limit:", 4);
   fF2->AddFrame(fLowerLimit, fL3);
   fLimits[0] = new TGNumberEntry(fF2, 0, 12, 10);
   fLimits[0]->SetLogStep(kFALSE);
   fF2->AddFrame(fLimits[0], fL3);
   fUpperLimit = new TGCheckButton(fF2, "upper limit:", 5);
   fF2->AddFrame(fUpperLimit, fL3);
   fLimits[1] = new TGNumberEntry(fF2, 0, 12, 11);
   fLimits[1]->SetLogStep(kFALSE);
   fF2->AddFrame(fLimits[1], fL3);
   fPositive = new TGCheckButton(fF2, "Positive", 6);
   fF2->AddFrame(fPositive, fL3);
   fNonNegative = new TGCheckButton(fF2, "Non negative", 7);
   fF2->AddFrame(fNonNegative, fL3);
   fSetButton = new TGTextButton(fF2, " Set ", 2);
   fF2->AddFrame(fSetButton, fL3);
   fExitButton = new TGTextButton(fF2, " Close ", 1);
   fF2->AddFrame(fExitButton, fL3);

   // set dialog box title
   SetWindowName("Number Entry Test");
   MapSubwindows();
   Layout();
   Resize(GetDefaultSize());
   SetWMPosition(0, 0);
   MapWindow();
}

//______________________________________________________________________________
void testNumberEntry()
{
   // Test number entries in different formats.

   NumberEntryWindow *f = new NumberEntryWindow(gClient->GetRoot());
   ProcessFrame((TGMainFrame*)f, "Number Entries");
   f->CloseWindow();
}

////////////////////////////////////////////////////////////////////////////////

const char *editortxt1 =
"This is the ROOT text edit widget TGTextEdit. It is not intended as\n"
"a full developers editor, but it is relatively complete and can ideally\n"
"be used to edit scripts or to present users editable config files, etc.\n\n"
"The text edit widget supports standard emacs style ctrl-key navigation\n"
"in addition to the arrow keys. By default the widget has under the right\n"
"mouse button a popup menu giving access to several built-in functions.\n\n"
"Cut, copy and paste between different editor windows and any other\n"
"standard text handling application is supported.\n\n"
"Text can be selected with the mouse while holding the left button\n"
"or with the arrow keys while holding the shift key pressed. Use the\n"
"middle mouse button to paste text at the current mouse location."
;
const char *editortxt2 =
"Mice with scroll-ball are properly supported.\n\n"
"This are the currently defined key bindings:\n"
"Left Arrow\n"
"    Move the cursor one character leftwards.\n"
"    Scroll when cursor is out of frame.\n"
"Right Arrow\n"
"    Move the cursor one character rightwards.\n"
"    Scroll when cursor is out of frame.\n"
"Backspace\n"
"    Deletes the character on the left side of the text cursor and moves the\n"
"    cursor one position to the left. If a text has been marked by the user"
;
const char *editortxt3 =
"    (e.g. by clicking and dragging) the cursor will be put at the beginning\n"
"    of the marked text and the marked text will be removed.\n"
"Home\n"
"    Moves the text cursor to the left end of the line. If mark is TRUE text\n"
"    will be marked towards the first position, if not any marked text will\n"
"    be unmarked if the cursor is moved.\n"
"End\n"
"    Moves the text cursor to the right end of the line. If mark is TRUE text\n"
"    will be marked towards the last position, if not any marked text will\n"
"    be unmarked if the cursor is moved.\n"
;

class EditorWindow : public TGMainFrame {

private:
   TGTextEdit       *fEdit;   // text edit widget
   TGTextButton     *fOK;     // OK button
   TGLayoutHints    *fL1;     // layout of TGTextEdit
   TGLayoutHints    *fL2;     // layout of OK button

public:
   EditorWindow(const TGWindow *p, UInt_t w, UInt_t h);

   void   LoadBuffer(const char *buffer);
   void   AddBuffer(const char *buffer);

};

//______________________________________________________________________________
EditorWindow::EditorWindow(const TGWindow *p, UInt_t w, UInt_t h) :
   TGMainFrame(p, w, h)
{
   // Main window constructor.

   // use hierarchical cleaning
   SetCleanup(kDeepCleanup);

   fEdit = new TGTextEdit(this, w, h, kSunkenFrame | kDoubleBorder);
   fL1 = new TGLayoutHints(kLHintsExpandX | kLHintsExpandY, 3, 3, 3, 3);
   AddFrame(fEdit, fL1);

   // set selected text colors
   Pixel_t pxl;
   gClient->GetColorByName("#ccccff", pxl);
   fEdit->SetSelectBack(pxl);
   fEdit->SetSelectFore(TGFrame::GetBlackPixel());

   fOK = new TGTextButton(this, "  &OK  ");
   fL2 = new TGLayoutHints(kLHintsBottom | kLHintsCenterX, 0, 0, 5, 5);
   AddFrame(fOK, fL2);

   SetWindowName("Number Entry Test");
   MapSubwindows();
   Layout();
   Resize(GetDefaultSize());
   SetWMPosition(0, 0);
   LoadBuffer(editortxt1);
   AddBuffer(editortxt2);
   AddBuffer(editortxt3);
   MapWindow();
}

//______________________________________________________________________________
void EditorWindow::LoadBuffer(const char *buffer)
{
   // Load a text buffer in the editor.

   fEdit->LoadBuffer(buffer);
}

//______________________________________________________________________________
void EditorWindow::AddBuffer(const  char *buffer)
{
   // Add text to the editor.

   TGText txt;
   txt.LoadBuffer(buffer);
   fEdit->AddText(&txt);
}

//______________________________________________________________________________
void testEditor()
{
   // Very simple test of the TGTextEdit widget.

   EditorWindow *f = new EditorWindow(gClient->GetRoot(), 550, 400);
   ProcessFrame((TGMainFrame*)f, "Text Editor");
   f->CloseWindow();
}

////////////////////////////////////////////////////////////////////////////////

//______________________________________________________________________________
void testCanvas()
{
   // Test Simple Canvas...

   TCanvas *c = new TCanvas("c", "Test Canvas", 0, 0, 800, 600);
   TRootCanvas *rc = (TRootCanvas *)c->GetCanvasImp();
   ProcessFrame((TGMainFrame*)rc, "ROOT Canvas");
   c->Close();
   delete c;
}

////////////////////////////////////////////////////////////////////////////////

class MyColorDialog : public TGColorDialog {

public:
   MyColorDialog(const TGWindow *p = 0, const TGWindow *m = 0, Int_t *retc = 0,
                 Pixel_t *color = 0);

   void   Close() { CloseWindow(); }
   void   SwitchTab(Int_t pos);
};

//______________________________________________________________________________
MyColorDialog::MyColorDialog(const TGWindow *p, const TGWindow *m, Int_t *retc,
                             ULong_t *color) : TGColorDialog(p, m, retc, color,
                             kFALSE)
{
   // Constructor.

   SetWMPosition(0, 0);
   MapWindow();
}

//______________________________________________________________________________
void MyColorDialog::SwitchTab(Int_t pos)
{
   fTab->SetTab(pos, kFALSE);
}

//______________________________________________________________________________
void testColorDlg()
{
   // Test Color Selection Dialog.

   Int_t retc = 0;
   ULong_t color = 0xcfcfcf;
   MyColorDialog *dlg = new MyColorDialog(gClient->GetDefaultRoot(),
                                          gClient->GetDefaultRoot(),
                                          &retc, &color);
   ProcessFrame((TGMainFrame*)dlg, "Color Dialog 1");
   dlg->SwitchTab(1);
   ProcessFrame((TGMainFrame*)dlg, "Color Dialog 2");
   dlg->Close();
   delete dlg;
}

////////////////////////////////////////////////////////////////////////////////

//______________________________________________________________________________
void testFontDlg()
{
   // Test Font Selection Dialog.

   TGFontDialog::FontProp_t prop;
   TGFontDialog *dlg = new TGFontDialog(gClient->GetDefaultRoot(),
                                        gClient->GetDefaultRoot(),
                                        &prop, "", 0, kFALSE);
   dlg->SetWMPosition(0, 0);
   dlg->MapWindow();
   ProcessFrame((TGMainFrame*)dlg, "Font Dialog");
   delete dlg;
}

////////////////////////////////////////////////////////////////////////////////

//______________________________________________________________________________
void testSearchDlg()
{
   // Test Search Dialog.

   Int_t retc = 0;
   TGSearchType sstruct;
   sstruct.fClose = kFALSE;
   TGSearchDialog *dlg = new TGSearchDialog(gClient->GetDefaultRoot(),
                                            gClient->GetDefaultRoot(),
                                            1, 1, &sstruct, &retc);
   dlg->SetWMPosition(0, 0);
   dlg->MapWindow();
   ProcessFrame((TGMainFrame*)dlg, "Search Dialog");
   delete dlg;
}

////////////////////////////////////////////////////////////////////////////////

class LabelEntry : public TGCompositeFrame {
public:
   TGLabel * fLabel;
   TGNumberEntry * fNumberEntry;
   TGTextButton * fTextButton1, * fTextButton2;
   TGTableLayout * tabLayout;

public:
   LabelEntry(const TGWindow * parent, Int_t Width, Int_t Height);
};

//______________________________________________________________________________
LabelEntry::LabelEntry(const TGWindow * parent, Int_t Width, Int_t Height) :
   TGCompositeFrame(parent, Width, Height)
{

   tabLayout=new TGTableLayout(this, 2,5, kFALSE);
   SetLayoutManager(tabLayout);

   fLabel = new TGLabel(this, "Label");
   fLabel->ChangeOptions(fLabel->GetOptions() | kFixedWidth);
   fNumberEntry = new TGNumberEntry(this, 0., 30, 1);
   fTextButton1 = new TGTextButton(this, "TextButton");
   fTextButton2 = new TGTextButton(this, "TextButton2");

   AddFrame(fLabel, new TGTableLayoutHints(0,1,0,2,
            kLHintsExpandX | kLHintsExpandY |
            kLHintsCenterX | kLHintsCenterY |
            kLHintsFillX | kLHintsFillY,
            1, 1, 1, 1));
   AddFrame(fNumberEntry, new TGTableLayoutHints(1,2,0,2,
            kLHintsExpandX | kLHintsExpandY |
            kLHintsCenterX | kLHintsCenterY |
            kLHintsFillX|kLHintsFillY,
            1, 1, 1, 1));
   AddFrame(fTextButton1, new TGTableLayoutHints(2,3,0,1,
            kLHintsExpandX | kLHintsExpandY |
            kLHintsCenterX | kLHintsCenterY |
            kLHintsFillX | kLHintsFillY,
            1, 1, 1, 1));
   AddFrame(fTextButton2, new TGTableLayoutHints(2,3,1,2,
            kLHintsExpandX | kLHintsExpandY |
            kLHintsCenterX | kLHintsCenterY |
            kLHintsFillX | kLHintsFillY,
            1, 1, 1, 1));

   Layout();
   Resize(Width, Height);
   ChangeOptions(GetOptions() | kFixedWidth);
}

//______________________________________________________________________________
void testTableLayout()
{
   // Test table layout.

   LabelEntry *l1, *l2;
   TGMainFrame *mf = new TGMainFrame (gClient->GetRoot(), 700, 200);
   mf->SetCleanup(kDeepCleanup);

   l1= new LabelEntry(mf, 500, 60);
   l2= new LabelEntry(mf, 600, 70);
   mf->AddFrame(l1);
   mf->AddFrame(l2);
   mf->SetWindowName("Test Table Layout");
   mf->MapSubwindows();
   mf->Layout();
   mf->Resize(600, 130);
   mf->SetWMPosition(0, 0);
   mf->MapWindow();
   ProcessFrame((TGMainFrame*)mf, "Table Layout");
   mf->CloseWindow();
}

////////////////////////////////////////////////////////////////////////////////

//______________________________________________________________________________
void testPack()
{
   // Test the TGPack widget.

   TGPack *hp = 0;
   TGPack *vp = 0;
   TGTextButton* b = 0;

   TGMainFrame* mf = new TGMainFrame(0, 400, 300);
   mf->SetCleanup(kDeepCleanup);
   mf->SetWindowName("Foo");

   hp = new TGPack(mf, mf->GetWidth(), mf->GetHeight());
   hp->SetVertical(kFALSE);

   b = new TGTextButton(hp, "Ailaaha");  hp->AddFrame(b);

   vp = new TGPack(hp, hp->GetWidth(), hp->GetHeight());
   b = new TGTextButton(vp, "Blaaaaa");  vp->AddFrameWithWeight(b, 0, 5);
   b = new TGTextButton(vp, "Blooooo");  vp->AddFrameWithWeight(b, 0, 3);
   b = new TGTextButton(vp, "Bleeeee");  vp->AddFrameWithWeight(b, 0, 5);
   hp->AddFrame(vp, new TGLayoutHints(kLHintsExpandX | kLHintsExpandY));

   b = new TGTextButton(hp, "Cilnouk");  hp->AddFrame(b);

   mf->AddFrame(hp, new TGLayoutHints(kLHintsExpandX | kLHintsExpandY));

   mf->MapSubwindows();
   mf->Layout();
   mf->SetWMPosition(0, 0);
   mf->MapWindow();
   gSystem->ProcessEvents();
   gSystem->Sleep(10);
   ProcessFrame((TGMainFrame*)mf, "Pack Frames");
   mf->CloseWindow();
}

////////////////////////////////////////////////////////////////////////////////

enum ESlidersIds {
   VSId1,
   HSId1,
   VSId2,
   HSId2,
   VSId3,
   HSId3
};

class SliderWindow : public TGMainFrame {

private:
   TGVerticalFrame   *fVframe1, *fVframe2, *fVframe3;
   TGLayoutHints     *fBly, *fBfly1;
   TGHSlider         *fHslider1;
   TGVSlider         *fVslider1;
   TGDoubleVSlider   *fVslider2;
   TGDoubleHSlider   *fHslider2;
   TGTripleVSlider   *fVslider3;
   TGTripleHSlider   *fHslider3;

public:
   SliderWindow(const TGWindow *p, UInt_t w, UInt_t h);
};

SliderWindow::SliderWindow(const TGWindow *p, UInt_t w, UInt_t h) :
   TGMainFrame(p, w, h)
{
   // Dialog used to test the different supported sliders.

   // use hierarchical cleaning
   SetCleanup(kDeepCleanup);

   ChangeOptions((GetOptions() & ~kVerticalFrame) | kHorizontalFrame);

   fVframe1 = new TGVerticalFrame(this, 0, 0, 0);

   fHslider1 = new TGHSlider(fVframe1, 100, kSlider1 | kScaleBoth, HSId1);
   fHslider1->SetRange(0,50);

   fVslider1 = new TGVSlider(fVframe1, 100, kSlider2 | kScaleBoth, VSId1);
   fVslider1->SetRange(0,8);

   fVframe1->Resize(100, 100);

   fVframe2 = new TGVerticalFrame(this, 0, 0, 0);

   fHslider2 = new TGDoubleHSlider(fVframe2, 150, kDoubleScaleBoth, HSId2);
   fHslider2->SetRange(0,3);

   fVslider2 = new TGDoubleVSlider(fVframe2, 100, kDoubleScaleBoth, VSId2);

   fVslider2->SetRange(-10,10);
   fVframe2->Resize(100, 100);

   fVframe3 = new TGVerticalFrame(this, 0, 0, 0);

   fHslider3 = new TGTripleHSlider(fVframe3, 100, kDoubleScaleBoth, HSId3,
                                   kHorizontalFrame, GetDefaultFrameBackground(),
                                   kFALSE, kFALSE, kFALSE, kFALSE);
   fHslider3->SetRange(0.05,5.0);

   fVslider3 = new TGTripleVSlider(fVframe3, 100, kDoubleScaleBoth, VSId3,
                                   kVerticalFrame, GetDefaultFrameBackground(),
                                   kFALSE, kFALSE, kFALSE, kFALSE);
   fVslider3->SetRange(0.05,5.0);
   fVframe3->Resize(100, 100);

   //--- layout for buttons: top align, equally expand horizontally
   fBly = new TGLayoutHints(kLHintsTop | kLHintsLeft | kLHintsExpandX, 0, 0, 3, 0);

   //--- layout for the frame: place at bottom, right aligned
   fBfly1 = new TGLayoutHints(kLHintsTop | kLHintsRight, 20, 10, 15, 0);

   fVframe1->AddFrame(fHslider1, fBly);
   fVframe1->AddFrame(fVslider1, fBly);

   fVframe2->AddFrame(fHslider2, fBly);
   fVframe2->AddFrame(fVslider2, fBly);

   fVframe3->AddFrame(fHslider3, fBly);
   fVframe3->AddFrame(fVslider3, fBly);

   AddFrame(fVframe3, fBfly1);
   AddFrame(fVframe2, fBfly1);
   AddFrame(fVframe1, fBfly1);

   SetWindowName("Slider Test");
   TGDimension size = GetDefaultSize();
   Resize(size);

   fHslider3->SetPosition(0.15,1.5);
   fHslider3->SetPointerPosition(0.75);

   fVslider3->SetPosition(0.05,2.5);
   fVslider3->SetPointerPosition(1.0);

   SetWMSize(size.fWidth, size.fHeight);
   SetWMSizeHints(size.fWidth, size.fHeight, size.fWidth, size.fHeight, 0, 0);
   SetMWMHints(kMWMDecorAll | kMWMDecorResizeH  | kMWMDecorMaximize |
                                     kMWMDecorMinimize | kMWMDecorMenu,
                      kMWMFuncAll |  kMWMFuncResize    | kMWMFuncMaximize |
                                     kMWMFuncMinimize,
                      kMWMInputModeless);

   MapSubwindows();
   MapWindow();

}

//______________________________________________________________________________
void testSliders()
{
   // Test horizontal and vertical sliders.

   SliderWindow *f = new SliderWindow(gClient->GetRoot(), 400, 200);
   ProcessFrame((TGMainFrame*)f, "Sliders 1");
   f->CloseWindow();
}

////////////////////////////////////////////////////////////////////////////////

//______________________________________________________________________________
void testBrowsers()
{
   // Popup the GUI...
   gSystem->RedirectOutput(gTmpfilename.Data(), "w", &gRH);
   gEnv->SetValue("Browser.Name", "TRootBrowserLite");
   TBrowser *b = new TBrowser();
   gSystem->RedirectOutput(0, 0, &gRH);
   TGMainFrame *f = (TGMainFrame *)b->GetBrowserImp()->GetMainFrame();
   if (f) {
      ProcessFrame((TGMainFrame*)f, "Root Browser Lite");
      f->CloseWindow();
   }
   gSystem->RedirectOutput(gTmpfilename.Data(), "w", &gRH);
   gEnv->SetValue("Browser.Name", "TRootBrowser");
   b = new TBrowser();
   gSystem->RedirectOutput(0, 0, &gRH);
   f = (TGMainFrame *)b->GetBrowserImp()->GetMainFrame();
   if (f) {
      ProcessFrame((TGMainFrame*)f, "Root Browser");
      f->CloseWindow();
   }
}

////////////////////////////////////////////////////////////////////////////////

//______________________________________________________________________________
void testSplitFrame()
{
   // Test TGSplitFrame.

   TGMainFrame *mf = new TGMainFrame(gClient->GetDefaultRoot(), 200, 200);
   mf->SetCleanup(kDeepCleanup);
   TGSplitFrame *first = new TGSplitFrame(mf, 200, 200);
   mf->AddFrame(first, new TGLayoutHints(kLHintsExpandX | kLHintsExpandX, 0, 0, 0, 0));
   first->HSplit();
   first->GetFirst()->VSplit();
   first->GetSecond()->VSplit();
   first->GetSecond()->GetSecond()->SetEditable();
   new TGTextEditor("stressGUI.cxx", gClient->GetRoot());
   first->GetSecond()->GetSecond()->SetEditable(kFALSE);
   mf->MapSubwindows();
   mf->Resize(600, 400);
   mf->SetWMPosition(0, 0);
   mf->MapWindow();
   ProcessFrame(mf, "Split Frame 1");
   mf->CloseWindow();
}

////////////////////////////////////////////////////////////////////////////////

//______________________________________________________________________________
void testControlBars()
{
   // Test the ROOT control bar.

   TControlBar *bar = new TControlBar("vertical", "Demos",10,10);
   bar->AddButton("Help Demos",".x demoshelp.C",        "Click Here For Help on Running the Demos");
   bar->AddButton("browser",   "new TBrowser;",         "Start the ROOT Browser");
   bar->AddButton("framework", ".x graphics/framework.C","An Example of Object Oriented User Interface");
   bar->AddButton("first",     ".x graphics/first.C",   "An Example of Slide with Root");
   bar->AddButton("hsimple",   ".x hsimple.C",          "An Example Creating Histograms/Ntuples on File");
   bar->AddButton("hsum",      ".x hist/hsum.C",        "Filling Histograms and Some Graphics Options");
   bar->AddButton("formula1",  ".x graphics/formula1.C","Simple Formula and Functions");
   bar->AddButton("surfaces",  ".x graphs/surfaces.C",  "Surface Drawing Options");
   bar->AddButton("fillrandom",".x hist/fillrandom.C",  "Histograms with Random Numbers from a Function");
   bar->AddButton("fit1",      ".x fit/fit1.C",         "A Simple Fitting Example");
   bar->AddButton("multifit",  ".x fit/multifit.C",     "Fitting in Subranges of Histograms");
   bar->AddButton("h1draw",    ".x hist/h1draw.C",      "Drawing Options for 1D Histograms");
   bar->AddButton("graph",     ".x graphs/graph.C",     "Example of a Simple Graph");
   bar->AddButton("gerrors",   ".x graphs/gerrors.C",   "Example of a Graph with Error Bars");
   bar->AddButton("tornado",   ".x graphics/tornado.C", "Examples of 3-D PolyMarkers");
   bar->AddButton("shapes",    ".x geom/shapes.C",      "The Geometry Shapes");
   bar->AddButton("geometry",  ".x geom/geometry.C",    "Creation of the NA49 Geometry File");
   bar->AddButton("na49view",  ".x geom/na49view.C",    "Two Views of the NA49 Detector Geometry");
   bar->AddButton("file",      ".x io/file.C",          "The ROOT File Format");
   bar->AddButton("fildir",    ".x io/fildir.C",        "The ROOT File, Directories and Keys");
   bar->AddButton("tree",      ".x tree/tree.C",        "The Tree Data Structure");
   bar->AddButton("ntuple1",   ".x tree/ntuple1.C",     "Ntuples and Selections");
   bar->AddButton("rootmarks", ".x rootmarks.C",        "Prints an Estimated ROOTMARKS for Your Machine");
   bar->SetButtonWidth(90);
   bar->Show();
   TControlBarImp *imp = bar->GetControlBarImp();
   TGMainFrame *f = dynamic_cast<TGMainFrame*>(imp);
   if (f) {
      ProcessFrame(f, "Control Bar");
      f->CloseWindow();
   }
}

////////////////////////////////////////////////////////////////////////////////

//______________________________________________________________________________
void testHelpDialog()
{
   // Very simple test of the ROOT help dialog.

   TRootHelpDialog *hd = new TRootHelpDialog(gClient->GetRoot(), "About ROOT...", 600, 400);
   hd->SetText(gHelpAbout);
   hd->Popup();
   ProcessFrame((TGMainFrame *)hd, "Help Dialog");
   hd->CloseWindow();
}

////////////////////////////////////////////////////////////////////////////////

//______________________________________________________________________________
void testPaletteEditor()
{
   // Test the ASImage palette editor.

   const char *fname = "galaxy.root";
   TFile *gal = 0;
   if (!gSystem->AccessPathName(fname)) {
      gal = TFile::Open(fname);
   } else {
      gal = TFile::Open(Form("http://root.cern.ch/files/%s",fname));
   }
   if (!gal) return;
   TImage *img = (TImage*)gal->Get("n4254");
   //img->Draw();

   TASPaletteEditor *f = new TASPaletteEditor((TAttImage *)img, 80, 25);
   ProcessFrame((TGMainFrame*)f, "Palette Editor");
   f->CloseWindow();

   delete img;
}

////////////////////////////////////////////////////////////////////////////////

//______________________________________________________________________________
void testHtmlBrowser()
{
   // Test the HTML Browser.

   TGHtmlBrowser *b = new TGHtmlBrowser("http://bellenot.web.cern.ch/bellenot/Public/html_test/html_test.html");
   ProcessFrame((TGMainFrame*)b, "HTML Browser 1");
   b->Selected("http://bellenot.web.cern.ch/bellenot/Public/html_test/gallery/");
   ProcessFrame((TGMainFrame*)b, "HTML Browser 2");
   b->CloseWindow();
}

////////////////////////////////////////////////////////////////////////////////
//                             ROOT GUI tutorials
////////////////////////////////////////////////////////////////////////////////

// list of excluded macros
const char *excluded[] = {
   "_playback",
   "QtFileDialog",
   "QtMultiFileDialog",
   "QtPrintDialog",
   "calendar",
   "customTH1Fmenu",
   "exec_macro",
   "guitest0",
   0
};

//______________________________________________________________________________
Int_t bexec(TString &dir, const char *macro)
{
   // start a new ROOT process for the execution of the macro.

#ifdef WIN32
   return gSystem->Exec(TString::Format("set ROOT_HIST=0 & root.exe -l -q exec_macro.C(\\\"%s/%s\\\") >nul 2>&1", dir.Data(), macro));
#else
   return gSystem->Exec(TString::Format("ROOT_HIST=0 root.exe -l -q exec_macro.C\\(\\\"%s/%s\\\"\\) >&/dev/null", dir.Data(), macro));
#endif
}

//______________________________________________________________________________
void run_tutorials()
{
   // Run the macros available in $ROOTSYS/tutorials/gui

   gClient->HandleInput();
   gSystem->Sleep(50);
   gSystem->ProcessEvents();
   TString dir = gRootSys + "/tutorials/gui";
   TString savdir = gSystem->WorkingDirectory();
   TSystemDirectory sysdir(dir.Data(), dir.Data());
   TList *files = sysdir.GetListOfFiles();

   dir = gRootSys + "/tutorials";
   TString reqfile = dir + "/hsimple.root";
   if (gSystem->AccessPathName(reqfile, kFileExists)) {
      bexec(dir, "hsimple.C");
      gSystem->Unlink("hsimple_1.png");
   }
   dir += "/tree";
   reqfile = dir + "/cernstaff.root";
   if (gSystem->AccessPathName(reqfile, kFileExists)) {
      bexec(dir, "cernbuild.C");
   }
   dir = gRootSys + "/tutorials/gui";

   if (files) {
      TIter next(files);
      TSystemFile *file;
      TString fname;

      while ((file=(TSystemFile*)next())) {
         fname = file->GetName();
         if (!file->IsDirectory() && fname.EndsWith(".C")) {
            Bool_t skip = kFALSE;
            for (int i=0; excluded[i]; i++) {
               if (strstr(fname, excluded[i])) {
                  skip = kTRUE;
                  break;
               }
            }
            if (!skip) {
               bexec(dir, fname.Data());
               ProcessMacro(fname.Data(), fname.Data());
            }
         }
      }
      delete files;
   }
   dir = gRootSys + "/tutorials/image";
   bexec(dir, "galaxy_image.C");
   ProcessMacro("galaxy_image.C", "galaxy_image.C");

   gSystem->ChangeDirectory(savdir.Data());
}

////////////////////////////////////////////////////////////////////////////////
//                             Recorder sessions
////////////////////////////////////////////////////////////////////////////////

//______________________________________________________________________________
Int_t file_size(const char *filename)
{
   // count characters in the file, skipping cr/lf
   FILE *lunin;
   Int_t c, wc = 0;

   lunin = fopen(filename, "rb");
   if (lunin == 0) return -1;
   while (!feof(lunin)) {
      c = fgetc(lunin);
      if (c != 0x0d && c != 0x0a)
         wc++;
   }
   fclose(lunin);
   return wc;
}

//______________________________________________________________________________
void guitest_playback()
{
   Int_t i;
   Bool_t ret;
   TRecorder r;
   Int_t guitest_ref[11], guitest_err[11], guitest_size[11];

   printf("Guitest Playback..............................................");
   gSystem->RedirectOutput(gTmpfilename.Data(), "w", &gRH);
   TString savdir = gSystem->WorkingDirectory();
   TString dir = gRootSys + "/tutorials/gui";
   gSystem->ChangeDirectory(dir.Data());

   // first delete old files, if any
   for (i=0;i<11;++i) {
      gSystem->Unlink(TString::Format("%s/guitest%03d.C", dir.Data(), i+1));
   }
   TStopwatch sw;
   ret = r.Replay("http://root.cern.ch/files/guitest_playback.root");

   // wait for the recorder to finish the replay
   while (ret && r.GetState() == TRecorder::kReplaying) {
      gSystem->ProcessEvents();
      gSystem->Sleep(1);
      if (sw.RealTime() > 600.0) {
         r.ReplayStop();
         ret = kFALSE;
      }
      sw.Continue();
   }

   gSystem->RedirectOutput(0, 0, &gRH);
   if (ret) printf("... DONE\n");
   else printf(". FAILED\n");
   CloseMainframes();
   for (i=0;i<11;++i) {
      guitest_ref[i] = 0;
      guitest_err[i] = 100;
      guitest_size[i] = file_size(TString::Format("%s/guitest%03d.C",
                                  dir.Data(), i+1));
   }
   guitest_ref[0]  = 24957;
   guitest_ref[1]  = 6913;
   guitest_ref[2]  = 16402;
   guitest_ref[3]  = 10688;
   guitest_ref[4]  = 6554;
   guitest_ref[5]  = 24239;
   guitest_ref[6]  = 25069;
   guitest_ref[7]  = 25126;
   guitest_ref[8]  = 25175;
   guitest_ref[9]  = 25324;
   guitest_ref[10] = 68657;
   for (i=0;i<11;++i) {
      printf("guitest %02d: output............................................", i+1);
      if (TMath::Abs(guitest_ref[i] - guitest_size[i]) <= guitest_err[i]) {
         printf("..... OK\n");
         // delete successful tests, keep only the failing ones (for verification)
         gSystem->Unlink(TString::Format("%s/guitest%03d.C", dir.Data(), i+1));
      }
      else {
         printf(". FAILED\n");
         printf("         File Size = %d\n", guitest_size[i]);
         printf("          Ref Size = %d\n", guitest_ref[i]);
      }
   }
   gSystem->ChangeDirectory(savdir.Data());
}

////////////////////////////////////////////////////////////////////////////////

//______________________________________________________________________________
void dnd_playback()
{
   Bool_t ret;
   TRecorder r;
   printf("Drag and Drop Playback........................................");
   gSystem->RedirectOutput(gTmpfilename.Data(), "w", &gRH);
   TString savdir = gSystem->WorkingDirectory();
   TString filename = "http://bellenot.web.cern.ch/bellenot/recorder/dnd_playback";
#ifdef WIN32
   filename += "_win.root";
#else
   filename += "_x11.root";
#endif
   TString dir = gRootSys + "/tutorials/gui";
   gSystem->ChangeDirectory(dir.Data());

   TStopwatch sw;
   ret = r.Replay(filename.Data());

   // wait for the recorder to finish the replay
   while (ret && r.GetState() == TRecorder::kReplaying) {
      gSystem->ProcessEvents();
      gSystem->Sleep(1);
      // add timeout...
      if (sw.RealTime() > 180.0) {
         r.ReplayStop();
         ret = kFALSE;
      }
      sw.Continue();
   }
   gSystem->RedirectOutput(0, 0, &gRH);
   if (ret) printf("... DONE\n");
   else printf(". FAILED\n");
   CloseMainframes();
   gSystem->ChangeDirectory(savdir.Data());
}

////////////////////////////////////////////////////////////////////////////////

//______________________________________________________________________________
void mditest_playback()
{
   Bool_t ret;
   TRecorder r;
   printf("MDI Test Playback.............................................");
   gSystem->RedirectOutput(gTmpfilename.Data(), "w", &gRH);
   TString savdir = gSystem->WorkingDirectory();
   TString dir = gRootSys + "/tutorials/gui";
   gSystem->ChangeDirectory(dir.Data());

   TStopwatch sw;
   ret = r.Replay("http://bellenot.web.cern.ch/bellenot/recorder/mditest_playback.root");

   // wait for the recorder to finish the replay
   while (ret && r.GetState() == TRecorder::kReplaying) {
      gSystem->ProcessEvents();
      gSystem->Sleep(1);
      // add timeout...
      if (sw.RealTime() > 180.0) {
         r.ReplayStop();
         ret = kFALSE;
      }
      sw.Continue();
   }
   gSystem->RedirectOutput(0, 0, &gRH);
   if (ret) printf("... DONE\n");
   else printf(". FAILED\n");
   CloseMainframes();
   gSystem->ChangeDirectory(savdir.Data());
}

////////////////////////////////////////////////////////////////////////////////

//______________________________________________________________________________
void graph_edit_playback()
{
   Bool_t ret;
   TRecorder r;
   printf("Graphic Editors Playback......................................");
   gSystem->RedirectOutput(gTmpfilename.Data(), "w", &gRH);
   TString savdir = gSystem->WorkingDirectory();
   TString dir = gRootSys + "/tutorials/graphics";
   gSystem->ChangeDirectory(dir.Data());

   TStopwatch sw;
   ret = r.Replay("http://root.cern.ch/files/graphedit_playback.root");

   // wait for the recorder to finish the replay
   while (ret && r.GetState() == TRecorder::kReplaying) {
      gSystem->ProcessEvents();
      gSystem->Sleep(1);
      // add timeout...
      if (sw.RealTime() > 300.0) {
         r.ReplayStop();
         ret = kFALSE;
      }
      sw.Continue();
   }
   gSystem->RedirectOutput(0, 0, &gRH);
   if (ret) printf("... DONE\n");
   else printf(". FAILED\n");
   CloseMainframes();
   gSystem->ChangeDirectory(savdir.Data());
}

////////////////////////////////////////////////////////////////////////////////

//______________________________________________________________________________
void fitpanel_playback()
{
   Bool_t ret;
   TRecorder r;
   printf("Fit Panel Playback ...........................................");
   gSystem->RedirectOutput(gTmpfilename.Data(), "w", &gRH);
   TString savdir = gSystem->WorkingDirectory();
   TString dir = gRootSys + "/tutorials/fit";
   gSystem->ChangeDirectory(dir.Data());

   TStopwatch sw;
   ret = r.Replay("http://root.cern.ch/files/fitpanel_playback.root");

   // wait for the recorder to finish the replay
   while (ret && r.GetState() == TRecorder::kReplaying) {
      gSystem->ProcessEvents();
      gSystem->Sleep(1);
      // add timeout...
      if (sw.RealTime() > 300.0) {
         r.ReplayStop();
         ret = kFALSE;
      }
      sw.Continue();
   }
   gSystem->RedirectOutput(0, 0, &gRH);
   if (ret) printf("... DONE\n");
   else printf(". FAILED\n");
   CloseMainframes();
   gSystem->ChangeDirectory(savdir.Data());
}

