// Author: Bertrand Bellenot   22/08/02

/*************************************************************************
 * Copyright (C) 1995-2002, Bertrand Bellenot.                           *
 * All rights reserved.                                                  *
 *                                                                       *
 * For the licensing terms see the LICENSE file.                         *
 *************************************************************************/


#include <Riostream.h>

#include <TROOT.h>
#include <TStyle.h>
#include <TRint.h>
#include <TVirtualX.h>
#include <TEnv.h>
#include <KeySymbols.h>

#include <TFile.h>
#include <TTree.h>
#include <TFrame.h>
#include <TH1.h>
#include <TF1.h>

#include <TGMenu.h>
#include <TGFileDialog.h>
#include <TGTextEdit.h>
#include <TRootEmbeddedCanvas.h>
#include <TCanvas.h>
#include <TRandom.h>
#include <TSystem.h>
#include <TRootHelpDialog.h>
#include <TGStatusBar.h>
#include <TBrowser.h>
#include <TParticle.h>
#include "RootShower.h"
#include "MyParticle.h"
#include "GTitleFrame.h"
#include "GButtonFrame.h"
#include "RSMsgBox.h"
#include "RSAbout.h"
#include "SettingsDlg.h"
#include "RSHelpText.h"
#include "MyEvent.h"

#include <TGeoManager.h>
#include <TView.h>
#include <TGToolBar.h>
#include <TGSplitter.h>

#include <THtml.h>

#ifndef _CONSTANTS_H_
#include "constants.h"
#endif

enum RootShowerMessageTypes {
    M_FILE_OPEN,
    M_FILE_SAVEAS,
    M_FILE_HTML,
    M_FILE_EXIT,
    M_EVENT_NEXT,
    M_EVENT_SELECT,
    M_INTERRUPT_SIMUL,
    M_ZOOM_PLUS,
    M_ZOOM_MOINS,
    M_ZOOM_PLUS2,
    M_ZOOM_MOINS2,

    M_SHOW_PROCESS,
    M_ANIMATE_GIF,
    M_SETTINGS_DLG,
    M_SETTINGS_SAVE,
    M_SHOW_INFOS,
    M_SHOW_3D,
    M_SHOW_TRACK,

    M_VIEW_TOOLBAR,
    M_INSPECT_BROWSER,

    M_HELP_PHYSICS,
    M_HELP_SIMULATION,
    M_HELP_LICENSE,
    M_HELP_ABOUT
};

const char *xpm_names[] = {
    "open.xpm",
    "save.xpm",
    "",
    "settings.xpm",
    "",
    "infos.xpm",
    "view3d.xpm",
    "",
    "browser.xpm",
    "",
    "manual.xpm",
    "help.xpm",
    "license.xpm",
    "about.xpm",
    "",
    "quit.xpm",
    0
};

ToolBarData_t tb_data[] = {
  { "", "Open Root event file",     kFALSE, M_FILE_OPEN,        NULL },
  { "", "Save event in Root file",  kFALSE, M_FILE_SAVEAS,      NULL },
  { "",              0,             0,      -1,                 NULL },
  { "", "Event settings",           kFALSE, M_SETTINGS_DLG,     NULL },
  { "",              0,             0,      -1,                 NULL },
  { "", "Infos on current event",   kFALSE, M_SHOW_INFOS,       NULL },
  { "", "Open 3D viewer",           kFALSE, M_SHOW_3D,          NULL },
  { "",              0,             0,      -1,                 NULL },
  { "", "Start Root browser",       kFALSE, M_INSPECT_BROWSER,  NULL },
  { "",              0,             0,      -1,                 NULL },
  { "", "Physics recalls",          kFALSE, M_HELP_PHYSICS,     NULL },
  { "", "RootShower help",          kFALSE, M_HELP_SIMULATION,  NULL },
  { "", "Display license",          kFALSE, M_HELP_LICENSE,     NULL },
  { "", "About RootShower",         kFALSE, M_HELP_ABOUT,       NULL },
  { "",              0,             0,      -1,                 NULL },
  { "", "Exit Application",         kFALSE, M_FILE_EXIT,        NULL },
  { NULL,            NULL,          0,      0,                  NULL }
};

RootShower      *gRootShower;
Int_t            gColIndex;
TGListTree      *gEventListTree; // event selection TGListTree
TGListTreeItem  *gBaseLTI;
TGListTreeItem  *gTmpLTI;
TGListTreeItem  *gLTI[MAX_PARTICLE];

const TGPicture *bpic, *bspic;
const TGPicture *lpic, *lspic;

const Char_t *filetypes[] = {
    "ROOT files",    "*.root",
    "ROOT macros",   "*.C",
    "GIF  files",    "*.gif",
    "PS   files",    "*.ps",
    "EPS  files",    "*.eps",
    "All files",     "*",
    0,               0
};

enum EGeometrySettingsDialogMessageTypes {
    kM_BUTTON_OK,
    kM_BUTTON_CANCEL,
    kM_COMBOBOX_CHANNELID,
    kM_COMBOBOX_TDC
};

//_________________________________________________
// RootShower
//

Int_t RootShower::fgDefaultXPosition = 20;
Int_t RootShower::fgDefaultYPosition = 20;


//______________________________________________________________________________
RootShower::RootShower(const TGWindow *p, UInt_t w, UInt_t h):
  TGMainFrame(p, w, h)
{
    // Create (the) Event Display.
    //
    // p = pointer to GMainFrame (not owner)
    // w = width of RootShower frame
    // h = width of RootShower frame
    fOk                 = kFALSE;
    fModified           = kFALSE;
    fSettingsModified   = kFALSE;
    fIsRunning          = kFALSE;
    fShowProcess        = kFALSE;
    fCreateGIFs         = kFALSE;
    fTimer              = 0;
    fPicIndex           = 1;

    fRootShowerEnv = new TEnv(".rootshowerrc");

    fFirstParticle = fRootShowerEnv->GetValue("RootShower.fFirstParticle", PHOTON);
    fE0            = fRootShowerEnv->GetValue("RootShower.fE0", 10.0);
    fB             = fRootShowerEnv->GetValue("RootShower.fB", 20.000);
    fPicNumber     = fRootShowerEnv->GetValue("RootShower.fPicNumber", 24);
    fPicDelay      = fRootShowerEnv->GetValue("RootShower.fPicDelay", 100);
    fPicReset      = fRootShowerEnv->GetValue("RootShower.fPicReset", 1);

    fEventNr = 0;
    fNRun    = 0;

    bpic = gClient->GetPicture("branch_t.xpm");
    bspic = gClient->GetPicture("branch_t.xpm");

    lpic = gClient->GetPicture("leaf_t.xpm");
    lspic = gClient->GetPicture("leaf_t.xpm");

    // Create menubar and popup menus.
    MakeMenuBarFrame();

    //---- toolbar

    int spacing = 8;
    fToolBar = new TGToolBar(this, 60, 20, kHorizontalFrame | kRaisedFrame);
    for (int i = 0; xpm_names[i]; i++) {
        TString iconname(gProgPath);
#ifdef R__WIN32
        iconname += "\\icons\\";
#else
        iconname += "/icons/";
#endif
        iconname += xpm_names[i];
        tb_data[i].fPixmap = iconname.Data();
        if (strlen(xpm_names[i]) == 0) {
            spacing = 8;
            continue;
        }
        fToolBar->AddButton(this, &tb_data[i], spacing);
        spacing = 0;
    }
    AddFrame(fToolBar, new TGLayoutHints(kLHintsTop | kLHintsExpandX, 0, 0, 0, 0));
    fToolBar->GetButton(M_SHOW_3D)->SetState(kButtonDisabled);
    fToolBar->GetButton(M_FILE_SAVEAS)->SetState(kButtonDisabled);
    
    // Layout hints
    fL1 = new TGLayoutHints(kLHintsTop | kLHintsLeft, 0, 0, 0, 0);
    fL2 = new TGLayoutHints(kLHintsCenterX | kLHintsExpandX, 0, 0, 0, 0);
    fL3 = new TGLayoutHints(kLHintsTop | kLHintsLeft | kLHintsExpandX | kLHintsExpandY,
                            0, 0, 0, 0);
    fL4 = new TGLayoutHints(kLHintsTop | kLHintsLeft | kLHintsExpandY, 5, 5, 2, 2);
    fL5 = new TGLayoutHints(kLHintsTop | kLHintsLeft | kLHintsExpandX | kLHintsExpandY,
                            2, 2, 2, 2);
    fL6 = new TGLayoutHints(kLHintsBottom| kLHintsExpandX, 0, 0, 0, 0);
    fL7 = new TGLayoutHints(kLHintsTop | kLHintsLeft | kLHintsExpandX | kLHintsExpandY,
                            5, 5, 2, 2);
    fL8 = new TGLayoutHints(kLHintsTop | kLHintsLeft | kLHintsExpandX, 0, 0, 0, 0);

    // CREATE TITLE FRAME
    fTitleFrame = new GTitleFrame(this, "ROOT Shower Monte Carlo", "Event Display", 100, 100);
    AddFrame(fTitleFrame, fL2);

    // CREATE MAIN FRAME
    fMainFrame = new TGCompositeFrame(this, 100, 100, kHorizontalFrame | kRaisedFrame);

    TGVerticalFrame *fV1 = new TGVerticalFrame(fMainFrame, 150, 10, kSunkenFrame | kFixedWidth);
    TGVerticalFrame *fV2 = new TGVerticalFrame(fMainFrame, 10, 10, kSunkenFrame);

    TGLayoutHints *lo;

    lo = new TGLayoutHints(kLHintsLeft | kLHintsExpandY,2,0,2,2);
    fMainFrame->AddFrame(fV1, lo);

    TGVSplitter *splitter = new TGVSplitter(fMainFrame, 5);
    splitter->SetFrame(fV1, kTRUE);
    lo = new TGLayoutHints(kLHintsLeft | kLHintsExpandY, 0, 0 ,0, 0);
    fMainFrame->AddFrame(splitter, lo);

    lo = new TGLayoutHints(kLHintsRight | kLHintsExpandX | kLHintsExpandY,0,2,2,2);
    fMainFrame->AddFrame(fV2, lo);


    // Create Selection frame (i.e. with buttons and geometry selection widgets)
    fSelectionFrame = new TGCompositeFrame(fV1, 100, 100, kVerticalFrame);
    // create button frame
    fButtonFrame = new GButtonFrame (fSelectionFrame, this, M_EVENT_NEXT,
                                     M_EVENT_SELECT, M_INTERRUPT_SIMUL);
    lo = new TGLayoutHints(kLHintsTop | kLHintsCenterX | kLHintsExpandX, 2, 5, 1, 2);
    fSelectionFrame->AddFrame(fButtonFrame, lo);

    fTreeView = new TGCanvas(fSelectionFrame, 150, 10, kSunkenFrame | kDoubleBorder);
    fEventListTree = new TGListTree(fTreeView->GetViewPort(), 10, 10, kHorizontalFrame);
    gEventListTree = fEventListTree;
    fEventListTree->SetCanvas(fTreeView);
    fEventListTree->Associate(this);
    BuildEventTree();
    fTreeView->SetContainer(fEventListTree);
    fSelectionFrame->AddFrame(fTreeView, fL5);

    lo = new TGLayoutHints(kLHintsExpandX | kLHintsExpandY);
    fV1->AddFrame(fSelectionFrame, lo);

    //__________________________________________________________________________________

    // Create Display frame
    fDisplayFrame = new TGTab(fV2, 580, 360);

    // Create Display Canvas Tab (where the actual main event is displayed)
    TGCompositeFrame *tFrame = fDisplayFrame->AddTab("Main Event (Shower)");

    // Create Layout hints
    fZoomButtonsLayout = new TGLayoutHints(kLHintsBottom | kLHintsLeft | kLHintsExpandX, 5, 2, 2, 2);

    fHFrame = new TGHorizontalFrame(tFrame,0,0,0);
    tFrame->AddFrame(fHFrame, new TGLayoutHints(kLHintsBottom | kLHintsLeft | kLHintsExpandX, 5, 5, 5, 5));
    // Create Zoom Buttons
    fZoomPlusButton = new TGTextButton(fHFrame, "&Zoom Forward", M_ZOOM_PLUS);
    fZoomPlusButton->Associate(this);
    fZoomPlusButton->SetToolTipText("Zoom forward event view");
    fHFrame->AddFrame(fZoomPlusButton, fZoomButtonsLayout);
    fZoomMoinsButton = new TGTextButton(fHFrame, "Zoom &Backward", M_ZOOM_MOINS);
    fZoomMoinsButton->Associate(this);
    fZoomMoinsButton->SetToolTipText("Zoom backward event view");
    fHFrame->AddFrame(fZoomMoinsButton, fZoomButtonsLayout);

    fEmbeddedCanvas = new TRootEmbeddedCanvas("fEmbeddedCanvas", tFrame, 580, 360);
    tFrame->AddFrame(fEmbeddedCanvas, fL5);
    fEmbeddedCanvas->GetCanvas()->SetBorderMode(0);
    fCA = fEmbeddedCanvas->GetCanvas();
    fCA->SetFillColor(1);

    // Create Display Canvas Tab (where the selected event is displayed)
    TGCompositeFrame *tFrame2 = fDisplayFrame->AddTab("Selected Track");

    fHFrame2 = new TGHorizontalFrame(tFrame2,0,0,0);
    tFrame2->AddFrame(fHFrame2, new TGLayoutHints(kLHintsBottom | kLHintsLeft | kLHintsExpandX, 5, 5, 5, 5));
    // Create Zoom Buttons
    fZoomPlusButton2 = new TGTextButton(fHFrame2, "&Zoom Forward", M_ZOOM_PLUS2);
    fZoomPlusButton2->Associate(this);
    fZoomPlusButton2->SetToolTipText("Zoom forward event view");
    fHFrame2->AddFrame(fZoomPlusButton2, fZoomButtonsLayout);
    fZoomMoinsButton2 = new TGTextButton(fHFrame2, "Zoom &Backward", M_ZOOM_MOINS2);
    fZoomMoinsButton2->Associate(this);
    fZoomMoinsButton2->SetToolTipText("Zoom backward event view");
    fHFrame2->AddFrame(fZoomMoinsButton2, fZoomButtonsLayout);

    fEmbeddedCanvas2 = new TRootEmbeddedCanvas("fEmbeddedCanvas2", tFrame2, 580, 360);
    tFrame2->AddFrame(fEmbeddedCanvas2, fL5);
    fEmbeddedCanvas2->GetCanvas()->SetBorderMode(0);
    fCB = fEmbeddedCanvas2->GetCanvas();
    fCB->SetFillColor(1);

    // Create Display Canvas Tab (where the histogram is displayed)
    TGCompositeFrame *tFrame3 = fDisplayFrame->AddTab("Statistics");

    fEmbeddedCanvas3 = new TRootEmbeddedCanvas("fEmbeddedCanvas3", tFrame3, 580, 360);
    tFrame3->AddFrame(fEmbeddedCanvas3, fL5);
    fEmbeddedCanvas3->GetCanvas()->SetBorderMode(0);
    fCC = fEmbeddedCanvas3->GetCanvas();
    fCC->SetFillColor(10);
    fCC->cd();
    fPadC = new TPad("fPadC","Histogram",0.0,0.0,1.0,1.0,10,3,1);
    fPadC->SetFillColor(10);
    fPadC->SetBorderMode(0);
    fPadC->SetBorderSize(0);
    fPadC->Draw();
    // Creation of histogram for particle's energy loss
    fHisto_dEdX = new TH1F("Statistics","Energy loss for each particle",100,0,0.025); // Max at 25 MeV
    fHisto_dEdX->SetFillColor(38);
    fHisto_dEdX->SetStats(kTRUE);
    fHisto_dEdX->SetXTitle("Energy Loss [GeV]");
    fHisto_dEdX->SetLabelFont(42,"X");
    fHisto_dEdX->SetLabelSize(0.03f, "X");
    fHisto_dEdX->GetXaxis()->SetTitleFont(42);
    fHisto_dEdX->SetYTitle("Number");
    fHisto_dEdX->SetLabelFont(42,"Y");
    fHisto_dEdX->SetLabelSize(0.03f, "Y");
    fHisto_dEdX->GetYaxis()->SetTitleFont(42);

    fCC->Update();

    // Create text display Tab
    tFrame = fDisplayFrame->AddTab("PDG Table");
    fTextView = new TGTextEdit(tFrame, 300, 100, kSunkenFrame | kDoubleBorder);
    tFrame->AddFrame(fTextView, fL5);
    TString pdgFilename = gSystem->Getenv("ROOTSYS");
    pdgFilename.Append("/etc/pdg_table.txt");

    fTextView->LoadFile(pdgFilename);

    lo = new TGLayoutHints(kLHintsExpandX | kLHintsExpandY);
    fV2->AddFrame(fDisplayFrame, lo);

    AddFrame(fMainFrame, lo);

    // Create status bar
    Int_t parts[] = {45, 45, 10};
    fStatusBar = new TGStatusBar(this, 50, 10, kHorizontalFrame);
    fStatusBar->SetParts(parts, 3);
    AddFrame(fStatusBar, fL6);
    fStatusBar->SetText("Waiting to start simulation...",0);

    // Finish RootShower for display...
    SetWindowName("Root Shower Event Display");
    SetIconName("Root Shower Event Display");
    MapSubwindows();
    Resize(GetDefaultSize()); // this is used here to init layout algoritme
    MapWindow();
    fEvent = new MyEvent();
    fEvent->GetDetector()->Init();
    fEvent->Init(0, fFirstParticle, fE0, fB);
    Initialize(1);
    gROOT->GetListOfBrowsables()->Add(fEvent,"RootShower Event");
    gSystem->Load("libTreeViewer");
    AddInput(kKeyPressMask | kKeyReleaseMask);
    gVirtualX->SetInputFocus(GetId());
    gRootShower = this;
}


//______________________________________________________________________________
void RootShower::MakeMenuBarFrame()
{
    // Create menubar and popup menus.

    // layout hint items
    fMenuBarLayout = new TGLayoutHints(kLHintsTop| kLHintsLeft | kLHintsExpandX,
                     0, 0, 0, 0);
    fMenuBarItemLayout = new TGLayoutHints(kLHintsTop | kLHintsLeft, 0, 4, 0, 0);
    fMenuBarHelpLayout = new TGLayoutHints(kLHintsTop | kLHintsRight);

    fMenuBar = new TGMenuBar(this, 1, 1, kHorizontalFrame | kRaisedFrame);

    // file popup menu
    fMenuFile = new TGPopupMenu(gClient->GetRoot());
    fMenuFile->AddEntry("&Open...       Ctrl+O", M_FILE_OPEN);
    fMenuFile->AddEntry("S&ave as...  Ctrl+A", M_FILE_SAVEAS);
    fMenuFile->AddEntry("&Close", -1);
    fMenuFile->AddSeparator();
    fMenuFile->AddEntry("&Print", -1);
    fMenuFile->AddEntry("P&rint setup...", -1);
    fMenuFile->AddSeparator();
    fMenuFile->AddEntry("E&xit             Ctrl+Q", M_FILE_EXIT);
    fMenuFile->DisableEntry(M_FILE_SAVEAS);
    fMenuFile->Associate(this);

    fMenuEvent = new TGPopupMenu(gClient->GetRoot());
    fMenuEvent->AddLabel("Simulation Settings...");
    fMenuEvent->AddSeparator();
    fMenuEvent->AddEntry("&Settings...", M_SETTINGS_DLG);
    fMenuEvent->AddEntry("Save &Parameters", M_SETTINGS_SAVE);
    fMenuEvent->AddEntry("Show &Process", M_SHOW_PROCESS);
    fMenuEvent->AddEntry("Animated &GIF", M_ANIMATE_GIF);
    fMenuEvent->AddEntry("&Infos...                   Ctrl+I", M_SHOW_INFOS);
    fMenuEvent->AddSeparator();
    fMenuEvent->AddEntry("&3D View", M_SHOW_3D);
    fMenuEvent->AddEntry("&Show Selected  Track", M_SHOW_TRACK);
    fMenuEvent->DisableEntry(M_SHOW_INFOS);
    fMenuEvent->DisableEntry(M_SHOW_3D);
    fMenuEvent->DisableEntry(M_SHOW_TRACK);

    fMenuEvent->DisableEntry(M_SHOW_PROCESS);
    fMenuEvent->DisableEntry(M_ANIMATE_GIF);

    fMenuEvent->Associate(this);

    fMenuTools = new TGPopupMenu(gClient->GetRoot());
    fMenuTools->AddLabel("Simulation Tools...");
    fMenuTools->AddSeparator();
    fMenuTools->AddEntry("Start &Browser          Ctrl+B", M_INSPECT_BROWSER);
    fMenuTools->AddEntry("&Create Html Doc", M_FILE_HTML);
    fMenuTools->Associate(this);

    fMenuView = new TGPopupMenu(gClient->GetRoot());
    fMenuView->AddEntry("&Toolbar", M_VIEW_TOOLBAR);
    fMenuView->Associate(this);
    fMenuView->CheckEntry(M_VIEW_TOOLBAR);

    fMenuHelp = new TGPopupMenu(gClient->GetRoot());
    fMenuHelp->AddEntry("&Physics", M_HELP_PHYSICS);
    fMenuHelp->AddEntry("&Simulation", M_HELP_SIMULATION);
    fMenuHelp->AddSeparator();
    fMenuHelp->AddEntry("&License...", M_HELP_LICENSE);
    fMenuHelp->AddEntry("&About...", M_HELP_ABOUT);
    fMenuHelp->Associate(this);

    fMenuBar->AddPopup("&File", fMenuFile, fMenuBarItemLayout);
    fMenuBar->AddPopup("&Event", fMenuEvent, fMenuBarItemLayout);
    fMenuBar->AddPopup("&Tools", fMenuTools, fMenuBarItemLayout);
    fMenuBar->AddPopup("&View", fMenuView, fMenuBarItemLayout);
    fMenuBar->AddPopup("&Help", fMenuHelp, fMenuBarHelpLayout);

    AddFrame(fMenuBar, fMenuBarLayout);
}


//______________________________________________________________________________
void RootShower::CloseMenuBarFrame()
{
    // Destroy menubar and popup menus.
    delete fMenuHelp;
    delete fMenuEvent;
    delete fMenuTools;
    delete fMenuFile;

    delete fMenuBarItemLayout;
    delete fMenuBarHelpLayout;
    delete fMenuBar;
    delete fMenuBarLayout;
}

//______________________________________________________________________________
void RootShower::ShowToolBar(Bool_t show)
{
   // Show or hide toolbar.

   if (show) {
      ShowFrame(fToolBar);
      fMenuView->CheckEntry(M_VIEW_TOOLBAR);
   } else {
      HideFrame(fToolBar);
      fMenuView->UnCheckEntry(M_VIEW_TOOLBAR);
   }
}

//______________________________________________________________________________
RootShower::~RootShower()
{
    // Destroy RootShower object. Delete all created widgets
    // GUI MEMBERS
    CloseMenuBarFrame();

    delete fZoomPlusButton2;
    delete fZoomMoinsButton2;
    delete fZoomPlusButton;
    delete fZoomMoinsButton;
    delete fHFrame;
    delete fHFrame2;
    delete fZoomButtonsLayout;

    delete fEmbeddedCanvas;
    delete fTextView;
    delete fDisplayFrame;
    delete fEventListTree;
    delete fTreeView;
    delete fButtonFrame;
    delete fSelectionFrame;
    delete fMainFrame;
    delete fTitleFrame;

    delete fL8;
    delete fL7;
    delete fL6;
    delete fL5;
    delete fL4;
    delete fL3;
    delete fL2;
    delete fL1;
}

//______________________________________________________________________________
void RootShower::setDefaultPosition(Int_t x, Int_t y)
{
    // Set the default position on the screen of new RootShower instances.
    fgDefaultXPosition = x;
    fgDefaultYPosition = y;
}

//______________________________________________________________________________
void RootShower::Layout()
{
    //
    //  Resize(GetDefaultSize());
    TGMainFrame::Layout();
}


//______________________________________________________________________________
void RootShower::CloseWindow()
{
    // Got close message for this RootShower. The EventDislay and the
    // application will be terminated.

    if (fModified) {
        new RootShowerMsgBox(gClient->GetRoot(),this, 400, 200);
        if ( fOk ) {
            fRootShowerEnv->SetValue("RootShower.fFirstParticle",fFirstParticle);
            fRootShowerEnv->SetValue("RootShower.fE0",fE0);
            fRootShowerEnv->SetValue("RootShower.fB",fB);
            fRootShowerEnv->SaveLevel(kEnvLocal);
            cout << " Saving stuff .... " << endl;
#ifdef R__WIN32
            gSystem->Exec("del .rootshowerrc");
            gSystem->Rename(".rootshowerrc.new",".rootshowerrc");
#endif
        }
    }
    cout << "Terminating RootShower" << endl;
    DeleteWindow();
    gApplication->Terminate(0);
}

//______________________________________________________________________________
Bool_t RootShower::HandleConfigureNotify(Event_t *event)
{
    // This event is generated when the frame is resized.
    TGFrame* f = (TGFrame*)this;
    if ((event->fWidth != f->GetWidth()) || (event->fHeight != f->GetHeight())) {
        UInt_t w = event->fWidth;
        UInt_t h = event->fHeight;
        f->Resize(w,h);
        f->Layout();
   }
   return kTRUE;
}

//______________________________________________________________________________
Bool_t RootShower::ProcessMessage(Long_t msg, Long_t parm1, Long_t parm2)
{
    // Handle messages send to the RootShower object.
    Window_t wdummy;
    int ax, ay;
    TRootHelpDialog *hd;
    TGListTreeItem *item;
    TGFileInfo fi;
    Char_t  strtmp[250];

    switch (GET_MSG(msg)) {

    case kC_COMMAND:

        switch (GET_SUBMSG(msg)) {

            case kCM_BUTTON:
            case kCM_MENU:
                switch (parm1) {

                    case M_EVENT_NEXT:
                        if (fDisplayFrame->GetCurrent() != 0)
                            fDisplayFrame->SetTab(0);
                        Initialize(0);
                        fStatusBar->SetText("Simulation running, please wait...",0);
                        fButtonFrame->SetState(GButtonFrame::kNoneActive);
                        fMenuEvent->DisableEntry(M_SETTINGS_DLG);
                        OnShowerProduce();
                        fClient->NeedRedraw(fEventListTree);
                        fButtonFrame->SetState(GButtonFrame::kAllActive);
                        fMenuEvent->EnableEntry(M_SETTINGS_DLG);
                        sprintf(strtmp,"Done - Total particles : %d - Waiting for next simulation",
                            fEvent->GetTotal());
                        fStatusBar->SetText(strtmp,0);
                        break;
                    case M_EVENT_SELECT:
                        if (fDisplayFrame->GetCurrent() != 1)
                            fDisplayFrame->SetTab(1);
                        if ((item = fEventListTree->GetSelected()) != 0)
                            OnShowSelected(item);
                        break;
                    case M_INTERRUPT_SIMUL:
                            Interrupt();
                        break;

                    case M_ZOOM_PLUS:
                            fCA->cd();
                            fCA->GetView()->ZoomView(0, 1.25);
                            fCA->Modified();
                            fCA->Update();
                        break;

                    case M_ZOOM_MOINS:
                            fCA->cd();
                            fCA->GetView()->UnzoomView(0, 1.25);
                            fCA->Modified();
                            fCA->Update();
                        break;

                    case M_ZOOM_PLUS2:
                            fCB->cd();
                            fCB->GetView()->ZoomView(0, 1.25);
                            fCB->Modified();
                            fCB->Update();
                        break;

                    case M_ZOOM_MOINS2:
                            fCB->cd();
                            fCB->GetView()->UnzoomView(0, 1.25);
                            fCB->Modified();
                            fCB->Update();
                        break;

                    case M_FILE_OPEN:
                        if (fIsRunning) break;
                        fi.fFileTypes = filetypes;
                        new TGFileDialog(fClient->GetRoot(), this, kFDOpen,&fi);
                        if (!fi.fFilename) return kTRUE;
                        OnOpenFile(fi.fFilename);
                        break;

                    case M_FILE_HTML:
                         {
                             THtml html;
                             html.SetSourceDir(gProgPath);
                             html.MakeClass("MyParticle");
                             html.MakeClass("MyDetector");
                             html.MakeClass("EventHeader");
                             html.MakeClass("MyEvent");
                             html.MakeIndex();
                         }
                        break;

                    case M_FILE_SAVEAS:
                        if (fIsRunning) break;
                        fi.fFileTypes = filetypes;
                        new TGFileDialog(fClient->GetRoot(), this, kFDSave,&fi);
                        if (!fi.fFilename) return kTRUE;
                        OnSaveFile(fi.fFilename);
                        break;

                    case M_FILE_EXIT:
                        CloseWindow();   // this also terminates theApp
                        break;

                    case M_SHOW_PROCESS:
                        if (fShowProcess) {
                            fMenuEvent->UnCheckEntry(M_SHOW_PROCESS);
                            fShowProcess = kFALSE;
                        }
                        else {
                            fMenuEvent->CheckEntry(M_SHOW_PROCESS);
                            fShowProcess = kTRUE;
                        }
                        break;

                    case M_ANIMATE_GIF:
                        if (fCreateGIFs) {
                            fMenuEvent->UnCheckEntry(M_ANIMATE_GIF);
                            fCreateGIFs = kFALSE;
                        }
                        else {
                            fMenuEvent->CheckEntry(M_ANIMATE_GIF);
                            fCreateGIFs = kTRUE;
                        }
                        break;

                    case M_SETTINGS_DLG:
                        if (fIsRunning) break;
                        new SettingsDialog(fClient->GetRoot(), this, 400, 200);
                        if (fSettingsModified) {
                            fEvent->Init(0, fFirstParticle, fE0, fB);
                            Initialize(0);
                            gRootShower->Modified();
                            gRootShower->SettingsModified(kFALSE);
                        }
                        break;

                    case M_SETTINGS_SAVE:
                        fRootShowerEnv->SetValue("RootShower.fFirstParticle",fFirstParticle);
                        fRootShowerEnv->SetValue("RootShower.fE0",fE0);
                        fRootShowerEnv->SetValue("RootShower.fB",fB);
                        fRootShowerEnv->SaveLevel(kEnvLocal);
#ifdef R__WIN32
                        gSystem->Exec("del .rootshowerrc");
                        gSystem->Rename(".rootshowerrc.new",".rootshowerrc");
#endif
                        gRootShower->Modified(kFALSE);
                        break;

                    case M_SHOW_INFOS:
                        if (fIsRunning) break;
                        ShowInfos();
                        break;

                    case M_INSPECT_BROWSER:
                        new TBrowser;
                        break;

                    case M_VIEW_TOOLBAR:
                        if (fMenuView->IsEntryChecked(M_VIEW_TOOLBAR))
                            ShowToolBar(kFALSE);
                        else
                            ShowToolBar();
                        break;

                    case M_HELP_PHYSICS:
#ifdef R__WIN32
                        sprintf(strtmp, "start winhlp32 %s\\Physics.hlp",gProgPath);
                        gSystem->Exec(strtmp);
#else
                        sprintf(strtmp, "Help on Physics");
                        hd = new TRootHelpDialog(this, strtmp, 620, 350);
                        hd->SetText(gPhysicsHelpText);
                        gVirtualX->TranslateCoordinates( GetId(), GetParent()->GetId(),
                                    (Int_t)(GetWidth() - 620) >> 1,
                                    (Int_t)(GetHeight() - 350) >> 1,
                                    ax, ay, wdummy);
                        hd->Move(ax, ay);
                        hd->Popup();
                        fClient->WaitFor(hd);
#endif
                        break;

                    case M_HELP_SIMULATION:
                        sprintf(strtmp, "Help on Simulation");
                        hd = new TRootHelpDialog(this, strtmp, 620, 350);
                        hd->SetText(gSimulationHelpText);
                        gVirtualX->TranslateCoordinates( GetId(), GetParent()->GetId(),
                                    (Int_t)(GetWidth() - 620) >> 1,
                                    (Int_t)(GetHeight() - 350) >> 1,
                                    ax, ay, wdummy);
                        hd->Move(ax, ay);
                        hd->Popup();
                        fClient->WaitFor(hd);
                        break;

                    case M_HELP_LICENSE:
                        sprintf(strtmp, "RootShower License");
                        hd = new TRootHelpDialog(this, strtmp, 640, 380);
                        hd->SetText(gHelpLicense);
                        gVirtualX->TranslateCoordinates( GetId(), GetParent()->GetId(),
                                    (Int_t)(GetWidth() - 640) >> 1,
                                    (Int_t)(GetHeight() - 380) >> 1,
                                    ax, ay, wdummy);
                        hd->Move(ax, ay);
                        hd->Popup();
                        fClient->WaitFor(hd);
                        break;

                    case M_HELP_ABOUT:
                        new RootShowerAbout(gClient->GetRoot(),this, 400, 200);
                        break;

                    case M_SHOW_3D:
                        if (fIsRunning) break;
                        fCA->cd();
                        fCA->GetViewer3D("ogl");
                        break;

                    case M_SHOW_TRACK:
                        if (fIsRunning) break;
                        if (fDisplayFrame->GetCurrent() != 1)
                            fDisplayFrame->SetTab(1);
                        if ((item = fEventListTree->GetSelected()) != 0)
                            OnShowSelected(item);
                        break;


                } // switch parm1
                break; // M_MENU

            } // switch submsg
            break; // case kC_COMMAND

        case kC_LISTTREE:

            switch (GET_SUBMSG(msg)) {

                case kCT_ITEMDBLCLICK:
                    if (parm1 == kButton1) {
                        if (fEventListTree->GetSelected()) {
                            fClient->NeedRedraw(fEventListTree);
                        }
                    }
                    break;

            } // switch submsg
            break; // case kC_LISTTREE
    } // switch msg

  return kTRUE;
}


//______________________________________________________________________________
TGListTreeItem* RootShower::AddToTree(const Text_t *name)
{
    // Add item to the TGListTree of the event display. It will be connected
    // to the current TGListTreeItem (i.e. fCurEventListItem)
    TGListTreeItem *e = 0;
    e = fEventListTree->AddItem(fCurListItem, name);
    return e;
}

//______________________________________________________________________________
void RootShower::BuildEventTree()
{
    // add recursively stations and layers (and cells) in TGListTree
    fCurListItem = 0;
    TGListTreeItem *eventLTItem = AddToTree("Event");
    fCurListItem = eventLTItem;
    gBaseLTI = eventLTItem;
}

//______________________________________________________________________________
void RootShower::Initialize(Int_t set_angles)
{
    Interrupt(kFALSE);
    fEventListTree->DeleteChildren(fCurListItem);
    fClient->NeedRedraw(fEventListTree);

    fCB->cd();
    fCB->SetFillColor(1);
    fCB->Clear();
    gGeoManager->GetTopVolume()->Draw();
    fCB->GetView()->SetPerspective();
    if (set_angles)
        fCB->GetView()->SideView();
    gGeoManager->GetTopVolume()->Draw();
    fCB->cd();
    fCB->Update();

    fCA->cd();
    fCA->SetFillColor(1);
    fCA->Clear();
    gGeoManager->GetTopVolume()->Draw();
    fCA->GetView()->SetPerspective();
    if (set_angles)
        fCA->GetView()->SideView();
    gGeoManager->GetTopVolume()->Draw();
    fCA->cd();
    fCA->Update();
    fStatusBar->SetText("",1);
}

//______________________________________________________________________________
void RootShower::produce()
{
    Int_t     local_num,local_last,local_end;
    Int_t     old_num;
    Bool_t    first_pass;
    Char_t    strtmp[80];

    // Check if some Event parameters have changed
    if ((fEvent->GetHeader()->GetDate() != fEventTime) ||
       (fEvent->GetHeader()->GetPrimary() != fFirstParticle) ||
       (fEvent->GetHeader()->GetEnergy() != fE0) ||
       (fEvent->GetB() != fB)) {
        fEventNr++;
        fNRun = 0;
    }
    fEvent->SetHeader(fEventNr, fNRun++, fEventTime, fFirstParticle, fE0);
    fEvent->Init(0, fFirstParticle, fE0, fB);

    fMenuFile->DisableEntry(M_FILE_SAVEAS);
    fMenuEvent->DisableEntry(M_SHOW_3D);
    fToolBar->GetButton(M_SHOW_3D)->SetState(kButtonDisabled);
    fToolBar->GetButton(M_FILE_SAVEAS)->SetState(kButtonDisabled);
    Interrupt(kFALSE);
    first_pass = kTRUE;
    old_num = -1;
    // loop events until user interrupt or until all particles are dead
    while ((!IsInterrupted()) && (fEvent->GetNAlives() > 0)) {
        gSystem->ProcessEvents();  // handle GUI events
        if (first_pass && fEvent->GetTotal() > 1) {
            fEventListTree->OpenItem(gBaseLTI);
            fEventListTree->OpenItem(gLTI[0]);
            fClient->NeedRedraw(fEventListTree);
            first_pass = kFALSE;
        }
        if (fEvent->GetTotal() > old_num) {
            sprintf(strtmp,"Simulation running, particles : %4d, please wait...",fEvent->GetTotal());
            old_num = fEvent->GetTotal();
            fStatusBar->SetText(strtmp,0);
            // Update display here to not slow down too much...
        }
        local_last = fEvent->GetLast();
        local_num = 0;
        local_end = kFALSE;
        while ((!IsInterrupted()) && (local_end == kFALSE) && (local_num < (local_last + 1))) {
            gSystem->ProcessEvents();  // handle GUI events
            // Update display here if fast machine...
            if (fEvent->GetParticle(local_num)->GetStatus() != DEAD) {
                if (fEvent->Action(local_num) == DEAD)
                    local_end = kTRUE;
                if (fEvent->GetParticle(local_num)->GetStatus() == CREATED)
                    fEvent->GetParticle(local_num)->SetStatus(ALIVE);
            }
            local_num ++;
        }
    }
    fMenuEvent->EnableEntry(M_SHOW_INFOS);
    if (!IsInterrupted()) {
       fMenuEvent->EnableEntry(M_SHOW_3D);
       fToolBar->GetButton(M_SHOW_3D)->SetState(kButtonUp);
       fToolBar->GetButton(M_FILE_SAVEAS)->SetState(kButtonUp);
       fMenuFile->EnableEntry(M_FILE_SAVEAS);
    }
}

//______________________________________________________________________________
void RootShower::OnShowerProduce()
{
    Int_t     i,j,gifindex;
    Char_t    gifname[80];
    fStatusBar->SetText("",1);

    SetWindowName("Root Shower Event Display");

    // animation logo handling
    if (fPicReset > 0) fPicIndex = 1;
    // animation timer
    if (!fTimer) fTimer = new TTimer(this, fPicDelay);
    fTimer->Reset();
    fTimer->TurnOn();

    fIsRunning = kTRUE;
    fHisto_dEdX->Reset();
    produce();
    Interrupt(kFALSE);
    gifindex = 0;
    for (i=0;i<=fEvent->GetTotal();i++) {
        gSystem->ProcessEvents();  // handle GUI events
        if (IsInterrupted()) break;
        // if particle has no child, represent it by a leaf,
        // otherwise by a branch
        if (fEvent->GetParticle(i)->GetChildId(0) == 0) {
            lpic = gClient->GetPicture("leaf_t.xpm");
            lspic = gClient->GetPicture("leaf_t.xpm");
            gLTI[i]->SetPictures(lpic, lspic);
        }
        else {
            bpic = gClient->GetPicture("branch_t.xpm");
            bspic = gClient->GetPicture("branch_t.xpm");
            gLTI[i]->SetPictures(bpic, bspic);
        }
        // Show only charged and massive particles...
        if ((fEvent->GetParticle(i)->GetPdgCode() != PHOTON) &&
           (fEvent->GetParticle(i)->GetPdgCode() != NEUTRINO_E) &&
           (fEvent->GetParticle(i)->GetPdgCode() != NEUTRINO_MUON) &&
           (fEvent->GetParticle(i)->GetPdgCode() != NEUTRINO_TAU) &&
           (fEvent->GetParticle(i)->GetPdgCode() != ANTINEUTRINO_E) &&
           (fEvent->GetParticle(i)->GetPdgCode() != ANTINEUTRINO_MUON) &&
           (fEvent->GetParticle(i)->GetPdgCode() != ANTINEUTRINO_TAU) ) {
            // Fill histogram for particle's energy loss
            fHisto_dEdX->Fill(fEvent->GetParticle(i)->GetELoss());
            for (j=0;j<fEvent->GetParticle(i)->GetNTracks();j++)
               fEvent->GetParticle(i)->GetTrack(j)->Draw();
            // show track by track if "show process" has been choosen
            // into the menu
            if (fShowProcess) {
                fCA->Modified();
                fCA->Update();
                // create one gif image by step if "Animated GIF"
                // has been choosen into the menu
                if (fCreateGIFs) {
                    sprintf(gifname,"event_%04d.gif",gifindex);
                    fCA->SaveAs(gifname);
                    gifindex++;
                }
            }
        }
    }
    AppendPad();
    fCA->GetView()->SetPerspective();
    fCA->cd();
    fCA->Modified();
    fCA->Update();
    fPadC->cd();
    // do not fit if not enough particles
    if (fHisto_dEdX->GetEntries() > 10) {
       fHisto_dEdX->Fit("landau","L");
       TF1 *f1 = fHisto_dEdX->GetFunction("landau");
       //delete fit function is fit is a non sense
       if (f1 && f1->GetNDF() > 0) {
          f1->SetLineColor(kRed);
          f1->SetLineWidth(1);
       } else {
          delete f1;
       }
    }
    fHisto_dEdX->Draw();
    fPadC->Modified();
    fPadC->Update();
    fCC->Update();
    fPadC->cd();
    fPadC->SetFillColor(16);
    fPadC->GetFrame()->SetFillColor(10);
    fPadC->Draw();
    fPadC->Update();

    // Open first list tree items
    fEventListTree->OpenItem(gBaseLTI);
    fEventListTree->OpenItem(gLTI[0]);
    fTimer->TurnOff();
    fIsRunning = kFALSE;
    if (fPicReset > 0)
        fTitleFrame->ChangeRightLogo(1);
}

//______________________________________________________________________________
void RootShower::HighLight(TGListTreeItem *item)
{
}

//______________________________________________________________________________
void RootShower::OnShowSelected(TGListTreeItem *item)
{
    // Shows track which has been selected into the list tree
    Int_t i,j,retval;

    fCB->cd();
    fCB->SetFillColor(1);
    fCB->SetBorderMode(0);
    fCB->SetBorderSize(0);
    fCB->Clear();
    fCB->cd();
    // draw geometry
    gGeoManager->GetTopVolume()->Draw();
    fCB->GetView()->SetPerspective();
    fCB->cd();
    fCB->Update();
    retval = -1;
    for (i=0;i<=fEvent->GetTotal();i++) {
        if (gLTI[i] == item) {
            retval = i;
            break;
        }
    }
    if ((retval > -1) &&
       (fEvent->GetParticle(i)->GetPdgCode() != PHOTON) &&
       (fEvent->GetParticle(i)->GetPdgCode() != NEUTRINO_E) &&
       (fEvent->GetParticle(i)->GetPdgCode() != NEUTRINO_MUON) &&
       (fEvent->GetParticle(i)->GetPdgCode() != NEUTRINO_TAU) &&
       (fEvent->GetParticle(i)->GetPdgCode() != ANTINEUTRINO_E) &&
       (fEvent->GetParticle(i)->GetPdgCode() != ANTINEUTRINO_MUON) &&
       (fEvent->GetParticle(i)->GetPdgCode() != ANTINEUTRINO_TAU) ) {
        for (j=0;j<fEvent->GetParticle(retval)->GetNTracks();j++)
           fEvent->GetParticle(retval)->GetTrack(j)->Draw();
    }
    fCB->GetView()->SetPerspective();
    fCB->cd();
    fCB->Modified();
    fCB->Update();
}

//______________________________________________________________________________
void RootShower::OnOpenFile(const Char_t *filename)
{
    // Opens a root file into which a previous event
    // has been saved.
    char   strtmp[256];
    Int_t  i,j;
    TFile *f = new TFile(filename);
    TTree *tree;
    TBranch *branch;
    fStatusBar->SetText("",1);

    fEvent->Init(0, fFirstParticle, fE0, fB);
    fHisto_dEdX->Reset();
    tree = (TTree *)f->Get("RootShower");
    if (tree == NULL) return;
    branch = tree->GetBranch("Event");
    branch->SetAddress(&fEvent);
    tree->GetEntry(0, 1);
    f->Close();

    // take back detector dimensions for selection geometry
    gGeoManager->Import(filename, "detector");
    Initialize(1);

    for (i=0;i<=fEvent->GetTotal();i++) {
        gTmpLTI = fEventListTree->AddItem(gBaseLTI, fEvent->GetParticle(i)->GetName());
        sprintf(strtmp,"%1.2f GeV",fEvent->GetParticle(i)->Energy());
        fEventListTree->SetToolTipItem(gTmpLTI, strtmp);
        gLTI[i] = gTmpLTI;

        if (fEvent->GetParticle(i)->GetChildId(0) == 0) {
            lpic = gClient->GetPicture("leaf_t.xpm");
            lspic = gClient->GetPicture("leaf_t.xpm");
            gLTI[i]->SetPictures(lpic, lspic);
        }
        else {
            bpic = gClient->GetPicture("branch_t.xpm");
            bspic = gClient->GetPicture("branch_t.xpm");
            gLTI[i]->SetPictures(bpic, bspic);
        }

        if ((fEvent->GetParticle(i)->GetPdgCode() != PHOTON) &&
           (fEvent->GetParticle(i)->GetPdgCode() != NEUTRINO_E) &&
           (fEvent->GetParticle(i)->GetPdgCode() != NEUTRINO_MUON) &&
           (fEvent->GetParticle(i)->GetPdgCode() != NEUTRINO_TAU) &&
           (fEvent->GetParticle(i)->GetPdgCode() != ANTINEUTRINO_E) &&
           (fEvent->GetParticle(i)->GetPdgCode() != ANTINEUTRINO_MUON) &&
           (fEvent->GetParticle(i)->GetPdgCode() != ANTINEUTRINO_TAU) ) {
            // Fill histogram for particle's energy loss
            fHisto_dEdX->Fill(fEvent->GetParticle(i)->GetELoss());
            for (j=0;j<fEvent->GetParticle(i)->GetNTracks();j++)
               fEvent->GetParticle(i)->GetTrack(j)->Draw();
        }
    }
    // Reparent each list tree item regarding the
    // corresponding particle relations
    for (i=1;i<=fEvent->GetTotal();i++) {
        fEventListTree->Reparent(gLTI[i],
            gLTI[fEvent->GetParticle(i)->GetFirstMother()]);
    }
    fEventListTree->OpenItem(gBaseLTI);
    fEventListTree->OpenItem(gLTI[0]);
    fClient->NeedRedraw(fEventListTree);
    AppendPad();

    sprintf(strtmp,"Done - Total particles : %d - Waiting for next simulation",
                    fEvent->GetTotal());
    fStatusBar->SetText(strtmp,0);
    fPadC->cd();
    // do not fit if not enough particles
    if (fHisto_dEdX->GetEntries() > 10) {
       fHisto_dEdX->Fit("landau","L");
       TF1 *f1 = fHisto_dEdX->GetFunction("landau");
       //delete fit function is fit is a non sense
       if (f1 && f1->GetNDF() > 0) {
          f1->SetLineColor(kRed);
          f1->SetLineWidth(1);
       } else {
          delete f1;
       }
    }
    fHisto_dEdX->Draw();
    fPadC->Modified();
    fPadC->Update();
    fCC->Update();
    fPadC->cd();
    fPadC->SetFillColor(16);
    fPadC->GetFrame()->SetFillColor(10);
    fPadC->Draw();
    fPadC->Update();

    fCA->cd();
    fCA->Modified();
    fCA->Update();
    fMenuEvent->EnableEntry(M_SHOW_INFOS);
    fMenuEvent->EnableEntry(M_SHOW_3D);
    fToolBar->GetButton(M_SHOW_3D)->SetState(kButtonUp);
    fToolBar->GetButton(M_FILE_SAVEAS)->SetState(kButtonUp);
    fMenuFile->EnableEntry(M_FILE_SAVEAS);
    fButtonFrame->SetState(GButtonFrame::kAllActive);
    sprintf(strtmp,"Root Shower Event Display - %s",filename);
    SetWindowName(strtmp);
}

//______________________________________________________________________________
void RootShower::OnSaveFile(const Char_t *filename)
{
    // Saves current event into a Root file
    TFile *hfile;
    char  strtmp[256];
    gGeoManager->Export(filename, "detector");
    hfile = new TFile(filename,"UPDATE","Root Shower file");
    hfile->SetCompressionLevel(9);
    TTree *hTree = new TTree("RootShower","Root Shower tree");
    hTree->Branch("Event", "MyEvent", &fEvent, 8000, 2);
    hTree->Fill();  //fill the tree
    hTree->Write();
    hTree->Print();
    hfile->Close();
    sprintf(strtmp,"Root Shower Event Display - %s",filename);
    SetWindowName(strtmp);
}

//______________________________________________________________________________
void RootShower::ShowInfos()
{
    // Gives infos on current event
    Window_t wdummy;
    int ax, ay;
    TRootHelpDialog *hd;
    Char_t str[32];
    Char_t Msg[500];
    Double_t dimx,dimy,dimz;

    fEvent->GetDetector()->GetDimensions(&dimx, &dimy, &dimz);

    sprintf(Msg, "  Some information about the current shower\n");
    sprintf(Msg, "%s  Dimensions of the target\n", Msg);
    sprintf(Msg, "%s  X .................... : %1.2e [cm]    \n", Msg, dimx);
    sprintf(Msg, "%s  Y .................... : %1.2e [cm]    \n", Msg, dimy);
    sprintf(Msg, "%s  Z .................... : %1.2e [cm]    \n", Msg, dimz);
    sprintf(Msg, "%s  Magnetic field ....... : %1.2e [kGauss]\n", Msg,
            fEvent->GetB());
    sprintf(Msg, "%s  Initial particle ..... : %s \n", Msg,
            fEvent->GetParticle(0)->GetName());
    sprintf(Msg, "%s  Initial energy ....... : %1.2e [GeV] \n", Msg,
            fEvent->GetHeader()->GetEnergy());
    sprintf(Msg, "%s  Total Energy loss .... : %1.2e [GeV]", Msg,
            fEvent->GetDetector()->GetTotalELoss());

    sprintf(str, "Infos on current shower");
    hd = new TRootHelpDialog(this, str, 420, 155);
    hd->SetText(Msg);
    gVirtualX->TranslateCoordinates( GetId(), GetParent()->GetId(),
              (Int_t)(GetWidth() - 420) >> 1,(Int_t)(GetHeight() - 155) >> 1,
              ax, ay, wdummy);
    hd->Move(ax, ay);
    hd->Popup();
    fClient->WaitFor(hd);
}

//______________________________________________________________________________
Bool_t RootShower::HandleKey(Event_t *event)
{
   char   input[10];
   Int_t  n;
   UInt_t keysym;

   if (event->fType == kGKeyPress) {
      gVirtualX->LookupString(event, input, sizeof(input), keysym);
      n = strlen(input);

      switch ((EKeySym)keysym) {   // ignore these keys
         case kKey_Shift:
         case kKey_Control:
         case kKey_Meta:
         case kKey_Alt:
         case kKey_CapsLock:
         case kKey_NumLock:
         case kKey_ScrollLock:
            return kTRUE;
         case kKey_F1:
            SendMessage(this, MK_MSG(kC_COMMAND, kCM_MENU),
                        M_HELP_SIMULATION, 0);
            return kTRUE;
         default:
            break;
      }
      if (event->fState & kKeyControlMask) {   // Cntrl key modifier pressed
         switch ((EKeySym)keysym & ~0x20) {   // treat upper and lower the same
            case kKey_A:
               SendMessage(this, MK_MSG(kC_COMMAND, kCM_MENU),
                           M_FILE_SAVEAS, 0);
               return kTRUE;
            case kKey_B:
               SendMessage(this, MK_MSG(kC_COMMAND, kCM_MENU),
                           M_INSPECT_BROWSER, 0);
               return kTRUE;
            case kKey_I:
               SendMessage(this, MK_MSG(kC_COMMAND, kCM_MENU),
                           M_SHOW_INFOS, 0);
               return kTRUE;
            case kKey_O:
               SendMessage(this, MK_MSG(kC_COMMAND, kCM_MENU),
                           M_FILE_OPEN, 0);
               return kTRUE;
            case kKey_Q:
               SendMessage(this, MK_MSG(kC_COMMAND, kCM_MENU),
                           M_FILE_EXIT, 0);
               return kTRUE;
            default:
               break;
         }
      }
   }
   return TGMainFrame::HandleKey(event);
}

//______________________________________________________________________________
Bool_t RootShower::HandleTimer(TTimer *)
{
   // Logo animation timer handling.

   if (fPicIndex > fPicNumber) fPicIndex = 1;
   fTitleFrame->ChangeRightLogo(fPicIndex);
   fPicIndex++;
   fTimer->Reset();
   return kTRUE;
}

//______________________________________________________________________________
Int_t RootShower::DistancetoPrimitive(Int_t px, Int_t py)
{
    // Compute distance from point px,py to objects in event
    Int_t i,j;
    Int_t dist = 9999;

    if (fEvent->GetTotal() <= 0) return 0;
    // Browse every track and get related particle infos.
    for (i=0;i<fEvent->GetTotal();i++) {
        for (j=0;j<fEvent->GetParticle(i)->GetNTracks();j++) {
           dist = fEvent->GetParticle(i)->GetTrack(j)->DistancetoPrimitive(px, py);
           if (dist < 2) {
               gPad->SetSelected((TObject*)fEvent->GetParticle(i));
               fStatusBar->SetText(fEvent->GetParticle(i)->GetObjectInfo(px, py),1);
               gPad->SetCursor(kPointer);
               return 0;
           }
        }
    }
    gPad->SetSelected((TObject*)gPad->GetView());
    return gPad->GetView()->DistancetoPrimitive(px,py);
}

//______________________________________________________________________________
int main(int argc, char **argv)
{
    Bool_t rint = kFALSE;
    for (int i = 0; i < argc; i++) {
       if (!strcmp(argv[i], "-d")) rint = kTRUE;
       if (!strcmp(argv[i], "-h") || !strcmp(argv[i], "-?")) {
          printf("Usage: %s [-d] [-h | -?]\n", argv[0]);
          printf("  -d:     debug and inspect mode via ROOT prompt\n");
          printf("  -h, -?: this message\n");
          return 0;
       }
    }

    TApplication *theApp;
    if (rint)
       theApp = new TRint("App", &argc, argv);
    else
       theApp = new TApplication("App", &argc, argv);

    gStyle->SetOptStat(1111);
    gStyle->SetOptFit(1111);
    gStyle->SetStatFont(42);

    gRandom->SetSeed( (UInt_t)time( NULL ) );
    const Int_t NRGBs = 5;
    Double_t Stops[NRGBs] = { 0.00, 0.50, 0.75, 0.875, 1.00 };
    Double_t Red[NRGBs] = { 1.00, 1.00, 1.00, 1.00, 1.00 };
    Double_t Green[NRGBs] = { 1.00, 0.75, 0.50, 0.25, 0.00 };
    Double_t Blue[NRGBs] = { 0.00, 0.00, 0.00, 0.00, 0.00 };
    gColIndex = gStyle->CreateGradientColorTable(NRGBs, Stops, Red, Green, Blue, 17);

    // Create RootShower
    RootShower theShower(gClient->GetRoot(), 400, 200);

    // run ROOT application
    theApp->Run();

    // pro forma, never reached
    delete theApp;

    return 0;
}
