Skip to content
Snippets Groups Projects
stressGUI.cxx 85.3 KiB
Newer Older
// @(#)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 <cstdlib>
#include <ctime>
#include <iostream>
#include <snprintf.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>
Sergey Linev's avatar
Sergey Linev committed
#include <TControlBarImp.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 <TVirtualX.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;

////////////////////////////////////////////////////////////////////////////////
/// Application main entry point.

int main(int argc, char *argv[])
{
   // 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;
}

////////////////////////////////////////////////////////////////////////////////
/// Run all stress GUI tests.

void stressGUI()
{
   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 {
Axel Naumann's avatar
Axel Naumann committed
      std::cout << "**********************************************************************" <<std::endl;
      std::cout << "*  Starting  GUI - S T R E S S suite                                 *" <<std::endl;
      std::cout << "**********************************************************************" <<std::endl;
   }
   gTestNum = 0;

   gBenchmark->Start("stressGUI");

   if (!gOptionRef) {
Axel Naumann's avatar
Axel Naumann committed
      std::cout << "*  Running macros in $ROOTSYS/tutorials/gui - S T R E S S            *" <<std::endl;
      std::cout << "**********************************************************************" <<std::endl;
Axel Naumann's avatar
Axel Naumann committed
      std::cout << "**********************************************************************" <<std::endl;
      std::cout << "*  Starting Basic GUI Widgets - S T R E S S                          *" <<std::endl;
      std::cout << "**********************************************************************" <<std::endl;
   }
   testLayout();
   testTextAlign();
   testGroupState();
   testLabels();
   testSplitButton();
   testTextEntries();
   testListTree();
   testShutter();
   testProgressBar();
   testNumberEntry();
   testTableLayout();
   if (!gOptionRef) {
Axel Naumann's avatar
Axel Naumann committed
      std::cout << "**********************************************************************" <<std::endl;
      std::cout << "*  Starting High Level GUI Widgets - S T R E S S                     *" <<std::endl;
      std::cout << "**********************************************************************" <<std::endl;
   }
   testPack();
   testSearchDlg();
   testFontDlg();
   testColorDlg();
   testEditor();
   testCanvas();
   testSliders();
   testBrowsers();
   testSplitFrame();
   testControlBars();
   testHelpDialog();
   testPaletteEditor();
Axel Naumann's avatar
Axel Naumann committed
         std::cout << "**********************************************************************" <<std::endl;
         std::cout << "*  Starting Drag and Drop playback - S T R E S S                     *" <<std::endl;
         std::cout << "**********************************************************************" <<std::endl;
Axel Naumann's avatar
Axel Naumann committed
         std::cout << "**********************************************************************" <<std::endl;
         std::cout << "*  Starting MDI test playback - S T R E S S                          *" <<std::endl;
         std::cout << "**********************************************************************" <<std::endl;
Axel Naumann's avatar
Axel Naumann committed
         std::cout << "**********************************************************************" <<std::endl;
         std::cout << "*  Starting guitest recorder playback - S T R E S S                  *" <<std::endl;
         std::cout << "**********************************************************************" <<std::endl;
Axel Naumann's avatar
Axel Naumann committed
         std::cout << "**********************************************************************" <<std::endl;
         std::cout << "*  Starting fit panel recorder playback - S T R E S S                *" <<std::endl;
         std::cout << "**********************************************************************" <<std::endl;
Axel Naumann's avatar
Axel Naumann committed
         std::cout << "**********************************************************************" <<std::endl;
         std::cout << "*  Starting graphic editors recorder playback - S T R E S S          *" <<std::endl;
         std::cout << "**********************************************************************" <<std::endl;
Axel Naumann's avatar
Axel Naumann committed
      std::cout << "**********************************************************************" <<std::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());
         }
         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
////////////////////////////////////////////////////////////////////////////////

////////////////////////////////////////////////////////////////////////////////
/// Return the size of the file "filename".

Int_t FileSize(const char *filename)
{
   FileStat_t fs;
   if (gSystem->GetPathInfo(filename, fs) == 0)
      return (Int_t)fs.fSize;
   return 0;
////////////////////////////////////////////////////////////////////////////////
/// Verify the file size.

Bool_t VerifySize(const char *filename, const char *title)
{
   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;

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

////////////////////////////////////////////////////////////////////////////////
/// Save a capture of frame f in a png file.

void ProcessFrame(TGFrame *f, const char *title)
{
   gSystem->ProcessEvents();
   gErrorIgnoreLevel = 9999;

   if (gOptionRef)
      snprintf(outfile,80, "sgui_%02d_ref.png", gTestNum);
      snprintf(outfile,80, "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++;
}

////////////////////////////////////////////////////////////////////////////////
/// Verify the size of a png file generated from a root macro.

void ProcessMacro(const char *macro, const char *title)
{
   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);

};

////////////////////////////////////////////////////////////////////////////////
/// Create a container frames containing buttons

ButtonLayoutWindow::ButtonLayoutWindow(const TGWindow *p, UInt_t w, UInt_t h) :
   TGMainFrame(p, w, h)
{
   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();
}

////////////////////////////////////////////////////////////////////////////////
/// Test layout and different states of some buttons.

void testLayout()
{
   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);

};

////////////////////////////////////////////////////////////////////////////////
/// Set text position (alignment).

void TextAlignWindow::SetTextPosition(Int_t hid, Int_t vid)
{
   Int_t tj = fButton->GetTextJustify();
   tj &= ~kTextCenterX;
   tj &= ~kTextLeft;
   tj &= ~kTextRight;
   tj &= ~kTextCenterY;
   tj &= ~kTextTop;
   tj &= ~kTextBottom;
   tj |= hid;
   tj |= vid;
   fButton->SetTextJustify(tj);
}

////////////////////////////////////////////////////////////////////////////////
/// Main test window.

TextAlignWindow::TextAlignWindow() : TGMainFrame(gClient->GetRoot(), 10, 10, kHorizontalFrame)
{
   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();
}

////////////////////////////////////////////////////////////////////////////////
/// Test different text alignments in a TGTextButton.

void testTextAlign()
{
   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);
};

////////////////////////////////////////////////////////////////////////////////
/// Main window constructor.

GroupStateWindow::GroupStateWindow(const TGWindow *p, UInt_t w, UInt_t h) :
   TGMainFrame(p, w, h)
{
   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();
};

////////////////////////////////////////////////////////////////////////////////
/// Test enabled/disabled state of button group.

void testGroupState()
{
   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();
};

////////////////////////////////////////////////////////////////////////////////
/// Main window constructor.

LabelsWindow::LabelsWindow(const TGWindow *p, UInt_t w, UInt_t h) :
  TGMainFrame(p, w, h)
{
   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();
}

////////////////////////////////////////////////////////////////////////////////
/// Switch state of the labels.

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

////////////////////////////////////////////////////////////////////////////////
/// Test different styles and the enabled/disabled state of labels.

void testLabels()
{
   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);

};

////////////////////////////////////////////////////////////////////////////////
/// Main window constructor.

SplitButtonWindow::SplitButtonWindow(const TGWindow *p, UInt_t w, UInt_t h) :
   TGMainFrame(p, w, h)
{
   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();
}

////////////////////////////////////////////////////////////////////////////////
/// Test the different configurations/states of a split button.

void testSplitButton()
{
   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