Universita' di GenovaINFN Sezione di Genova  
AIRWATCH / EUSO Genova

EClusterOfPrimitives - source file

// $Id: EGViewer.cc,v 1.38 2005/11/02 01:07:47 thea Exp $
// Author: Alessandro Thea   2005/05/23

/*****************************************************************************
 * ESAF: Euso Simulation and Analysis Framework                              *
 *                                                                           *
 *  Id: EGViewer                                                             *
 *  Package: <packagename>                                                   *
 *  Coordinator: <coordinator>                                               *
 *                                                                           *
 *****************************************************************************/

//_____________________________________________________________________________
//
// EGViewer
//
// <extensive class description>
//
//   Config file parameters
//   ======================
//
//   <parameter name>: <parameter description>
//   -Valid options: <available options>
//

#include "EGViewer.hh"
 
#include <iostream>
#include <fstream>

#include <TApplication.h>
#include <TCanvas.h>
#include <TFrame.h>
#include <TG3DLine.h>
#include <TGComboBox.h>
#include <TGListBox.h>
#include <TGLayout.h>
#include <TGMenu.h>
#include <TGProgressBar.h>
#include <TGStatusBar.h>
#include <TGTab.h>
#include <TLine.h>
#include <TMethodCall.h>
#include <TMutex.h>
#include <TPostScript.h>
#include <TPDF.h>
#include <TRootEmbeddedCanvas.h>
#include <TStyle.h>
#include <TText.h>
#include <TVirtualPS.h>
#include <TVirtualPadEditor.h>
#include <TGLabel.h>
#include <TGFileDialog.h>
#include <TH1.h>
#include <TGedEditor.h>
#include "KeySymbols.h"

// 28 and 19 used here to scale the canvas into a height of 28, such that the
// page title can be set above the canvas...
const Float_t kA4Width  = 29.7; // A4 - width (29.7)
const Float_t kA4Height = 21.0; // A4 - height (21.0)
const Float_t kA4PrintWidth  = 27.9; // A4 - width (29.7)
const Float_t kA4PrintHeight = 19.5; // A4 - height (21.0)
const Float_t kA4CanvasWHRatio = 1.5; // A4 - height (21.0)

enum EEGViewerCommands { 
                         kFileSaveAs,
                         kFileSaveAsPS,
                         kFileSaveAsPDF,
                         kFileSaveAsRoot,
                         kFileCloseViewer,
                         kFileExit,
                        
                         kViewEditor,
                         kViewCombo,
                         kViewX3D,
                         kViewOpenGL,
                        
                         kTabClonePad,

                         kOptionStatistics,
                         kOptionHistTitle,
                         kOptionFitParams,
                         kOptionCanEdit,

                         kSizeA4,
                         kSize640,
                         kSize800,
                         kSize960,
                         kSize1024,
                         kSize1280,

                         kW_COMBO_TABS,
                         kW_LIST_TABS
};


static const char *gSaveAsTypes[] = { "PostScript",   "*.ps",
                                //    "Encapsulated PostScript", "*.eps",
                                      "PDF",          "*.pdf",
                                //    "SVG",          "*.svg",
                                //    "GIF",          "*.gif",
                                //    "ROOT macros",  "*.C",
                                      "ROOT files",   "*.root",
                                //    "XML",          "*.xml",
                                //    "PNG",          "*.png",
                                //    "XPM",          "*.xpm",
                                //    "JPEG",         "*.jpg",
                                //    "TIFF",         "*.tiff",
                                //    "XCF",          "*.xcf",
                                      "All files",    "*",
                                      0,              0 };
using namespace std;
using namespace TMath;

ClassImp(EGViewer)

//_____________________________________________________________________________
EGViewer::EGViewer( const char* name, const char* title, Int_t w, Int_t h) : TGMainFrame(gClient->GetRoot(), w, h) {
    //
    // Constructor
    //

    TString wname = name ? name : "EGViewer";
    TString wtitle = title ? title : wname.Data();
    Constructor(wname,wtitle);

    Resize(w,h);

    // draw the window
    MapWindow();
    if ( !TThread::Self() )
        gSystem->ProcessEvents();
}

//_____________________________________________________________________________
EGViewer::EGViewer(Bool_t build, const char* name, Int_t w, Int_t h) : TGMainFrame(gClient->GetRoot(), w, h) {
    //
    // Protected constructor
    //

    if ( build ) {
        TString wname = name ? name : "EGViewer";

        Constructor( name , name);

        Resize(w,h);
    }
}

//______________________________________________________________________________
Bool_t EGViewer::Constructor(const char* name, const char* title) {
    //
    // Build the Viewer
    //

    fPadLookup = kFALSE;
    fOldPad = 0;
    fEditor = 0;

    gVirtualX->GrabKey(fId, gVirtualX->KeysymToKeycode(kKey_Left),
            kKeyControlMask, kTRUE);
    gVirtualX->GrabKey(fId, gVirtualX->KeysymToKeycode(kKey_Right),
            kKeyControlMask, kTRUE);
    gVirtualX->GrabKey(fId, gVirtualX->KeysymToKeycode(kKey_Tab),
            kKeyControlMask, kTRUE);

    fName = name ;
    fTitle = title ? title : name;

    fList = new TList;
    fList->SetOwner();

    // list of pointer to the tab canvases
    fCanvases = new TList;

    fMutex = new TMutex;

    //
    // Create the layout hint for the root embedded canavses
    //
    fLayCanvas = new TGLayoutHints(kLHintsExpandX|kLHintsExpandY);
    fList->Add(fLayCanvas);

    SetWindowName(fTitle);

    if ( gClient ) {
        AddMenuBar();
        AddUserFrame();
        AddTabs();
        AddStatusBar();
    }

    UpdateWMSizeHints();

    Layout();
    MapSubwindows();

    ShowTabList(kFALSE);
    ShowEditor(kFALSE);

    Resize(GetDefaultSize());

    return kTRUE;
}

//_____________________________________________________________________________
EGViewer::~EGViewer() {
    //
    // Destructor
    //

    SafeDelete(fEditor);
    delete fList;
    delete fCanvases;
}

//______________________________________________________________________________
void EGViewer::UpdateWMSizeHints() {
    //
    // Sets the WM min-max size of the window not to hide the tab list.
    // Sometime, if it is hidden a crash may occour. 
    //
    
    // 10 pixles left fo the canvases
    UInt_t minh = GetHeight()-GetTab()->GetHeight()+GetTab()->GetTabHeight()+10;
    UInt_t minw = 200;

    SetWMSizeHints(minw,minh,kMaxUShort,kMaxUShort,1,1);
}

//______________________________________________________________________________
void EGViewer::CloseWindow() {
    DeleteWindow();
}

//______________________________________________________________________________
void EGViewer::Clear( Option_t* opt ) {
    //
    //
    //
    
    RemoveTabs();
}

//______________________________________________________________________________
void EGViewer::AddMenuBar() {
    //
    // File Menu
    //

    //
    // Horizontal frame
    //
    TGLayoutHints *lay = new TGLayoutHints( kLHintsNormal|kLHintsExpandX,0,0,0,0 );
    fList->Add(lay);

    fMenuFrame = new TGCompositeFrame(this, GetWidth() + 4, GetHeight() + 4,
            kHorizontalFrame);

    fList->Add(fMenuFrame);

    fFileSaveMenu = new TGPopupMenu(gClient->GetRoot());

    fFileSaveMenu->AddEntry(Form("%s.ps",GetName()),   kFileSaveAsPS);
    fFileSaveMenu->AddEntry(Form("%s.pdf",GetName()),   kFileSaveAsPDF);
    fFileSaveMenu->AddEntry(Form("%s.root",GetName()),   kFileSaveAsRoot);
    fFileSaveMenu->Associate(this);

    fFileMenu = new TGPopupMenu(gClient->GetRoot());

    fFileMenu->AddEntry("Save &As...",   kFileSaveAs);
    fFileMenu->AddPopup("&Save", fFileSaveMenu);
    fFileMenu->AddSeparator();
    fFileMenu->AddEntry("C&lose viewer", kFileCloseViewer);
    fFileMenu->AddEntry("E&xit",         kFileExit);
    fFileMenu->Associate(this);


    fViewMenu = new TGPopupMenu(gClient->GetRoot());
    fViewMenu->AddEntry("&Editor",kViewEditor);
    fViewMenu->AddEntry("&Tab list",kViewCombo);
    fViewMenu->AddSeparator();
    fViewMenu->AddEntry("&X3D",      kViewX3D);
    fViewMenu->AddEntry("&OpenGL",   kViewOpenGL);
    fViewMenu->Associate(this);

    fTabMenu = new TGPopupMenu(gClient->GetRoot());
    fTabMenu->AddEntry("&Clone pad", kTabClonePad);
    fTabMenu->Associate(this);
    
    fOptionMenu = new TGPopupMenu(gClient->GetRoot());
    fOptionMenu->AddEntry("&Statistics",          kOptionStatistics);
    fOptionMenu->AddEntry("Histogram &Title",     kOptionHistTitle);
    fOptionMenu->AddEntry("&Fit Parameters",      kOptionFitParams);
    fOptionMenu->AddEntry("Can Edit &Histograms", kOptionCanEdit);
    fOptionMenu->Associate(this);

    if (gStyle->GetOptStat())
        fOptionMenu->CheckEntry(kOptionStatistics);
    if (gStyle->GetOptTitle())
        fOptionMenu->CheckEntry(kOptionHistTitle);
    if (gStyle->GetOptFit())
        fOptionMenu->CheckEntry(kOptionFitParams);
    if (gROOT->GetEditHistograms())
        fOptionMenu->CheckEntry(kOptionCanEdit); 

    fSizePaperMenu = new TGPopupMenu(gClient->GetRoot());
    fSizePaperMenu->AddEntry("&A4 (640x497)",kSizeA4);

    fSizeMenu = new TGPopupMenu(gClient->GetRoot());
    fSizeMenu->AddEntry("Resize to &640x480",kSize640);
    fSizeMenu->AddEntry("Resize to &800x600",kSize800);
    fSizeMenu->AddEntry("Resize to &960x720",kSize960);
    fSizeMenu->AddEntry("Resize to &1024x768",kSize1024);
    fSizeMenu->AddEntry("Resize to 1&280x1024",kSize1280);
    fSizeMenu->AddPopup("Resize &To...",fSizePaperMenu);
    fSizeMenu->Associate(this);

    //
    // Menu Bar
    //
    TGLayoutHints *layitem = new TGLayoutHints(kLHintsNormal, 0, 4, 0, 0);
    fList->Add(layitem);


    fMenuBar = new TGMenuBar(fMenuFrame, 1, 1, kHorizontalFrame);
    fMenuBar->AddPopup("&File", fFileMenu, layitem);
    //    fMenuBar->AddPopup("Lo&g",  logmenu,  layitem);
    fMenuBar->AddPopup("&View", fViewMenu, layitem);
    fMenuBar->AddPopup("&Tab",  fTabMenu,  layitem);
    fMenuBar->AddPopup("&Options",  fOptionMenu,  layitem);
    fMenuBar->AddPopup("&Resize", fSizeMenu, layitem);
    //    fMenuBar->AddPopup("&Loop", floopMenu, layitem);
    // fMenuBar->BindKeys(this);
    fMenuFrame->AddFrame(fMenuBar);

    //
    // Add everything to autodel list
    //
    fList->Add(fFileMenu);
    fList->Add(fFileSaveMenu);
    fList->Add(fViewMenu);
    fList->Add(fTabMenu);
    fList->Add(fSizeMenu);
    fList->Add(fSizePaperMenu);


    //
    // Add the tab Combo box 
    //
    TGLayoutHints* laycombo = new TGLayoutHints(kLHintsTop | kLHintsRight, 0, 4, 2, 2);
    fList->Add(laycombo);
    fTabCombo = new TGComboBox(fMenuFrame, kW_COMBO_TABS);
    fTabCombo->Associate(this);
    fMenuFrame->AddFrame(fTabCombo, laycombo);

    fList->Add(fTabCombo); 

    fTabCombo->Resize(150,20);


    AddFrame(fMenuFrame,lay);

    //
    // Add a 3d line at the bottom of the bar
    //

    TGLayoutHints *lay3D = new TGLayoutHints(kLHintsExpandX);
    fList->Add(lay3D);

    fLine = new TGHorizontal3DLine(this);
    fList->Add(fLine);

    AddFrame(fLine, lay3D);

}


//______________________________________________________________________________
void EGViewer::AddUserFrame() {
    //
    // Adds an empty TGCompositeFrame which might be filled by the user
    //
    TGLayoutHints *lay = new TGLayoutHints(kLHintsExpandX);
    fList->Add(lay);

    fUserFrame = new TGVerticalFrame(this, 1, 1);
    AddFrame(fUserFrame, lay);
    fList->Add(fUserFrame);
}


//______________________________________________________________________________
void EGViewer::AddTabs() {
    //
    // Add Tabs frame
    //

    TGLayoutHints *lay = new TGLayoutHints( kLHintsNormal|kLHintsExpandX|kLHintsExpandY, 0, 0, 0, 0 );
    fList->Add(lay);
    fMainFrame = new TGHorizontalFrame(this, GetWidth() + 4, GetHeight() + 4);
    fList->Add(fMainFrame);
    

    TGLayoutHints *laylistframe = new TGLayoutHints( kLHintsNormal|kLHintsExpandY, 0, 0, 0, 0 );
    fList->Add(laylistframe);
    fTabListFrame = new TGVerticalFrame(fMainFrame, 125, fMainFrame->GetHeight()+4, kFixedWidth); 
    fList->Add(fTabListFrame);

    TGLayoutHints* laylbl = new TGLayoutHints(kLHintsLeft, 5, 2, 2, 2);
    fList->Add(laylbl);
    TGLabel* label = new TGLabel(fTabListFrame,"Tabs");
    fList->Add(label);
    fTabListFrame->AddFrame(label,laylbl);
    
    fTabList = new TGListBox(fTabListFrame,kW_LIST_TABS);
    fTabList->Associate(this);
    fList->Add(fTabList);

//    fTabList->Resize(125,20);
    
    TGLayoutHints *laylist = new TGLayoutHints(kLHintsNormal|kLHintsExpandY|kLHintsExpandX, 2, 1, 2, 2);
    fList->Add(laylist);
    
    fTabListFrame->AddFrame(fTabList, laylist);
    fMainFrame->AddFrame(fTabListFrame, laylistframe);
    
    fTab = new TGTab(fMainFrame, fMainFrame->GetWidth()+4,fMainFrame->GetHeight()+4);
    fTab->Associate(this);

    // Add fTab to Frame
    TGLayoutHints *laytabs = new TGLayoutHints(kLHintsNormal|kLHintsExpandX|kLHintsExpandY, 1, 2, 2, 2);
    fMainFrame->AddFrame(fTab, laytabs);

    TGLayoutHints *layeditframe = new TGLayoutHints( kLHintsNormal|kLHintsExpandY, 0, 0, 0, 0 );
    fList->Add(layeditframe);
    fEditorFrame = new TGCompositeFrame(fMainFrame, 175, fMainFrame->GetHeight()+4, kFixedWidth); 
    fList->Add(fEditorFrame);
    
    fMainFrame->AddFrame(fEditorFrame, layeditframe);

    fList->Add(fTab);
    fList->Add(laytabs);
    
    AddFrame(fMainFrame, lay);



}

//______________________________________________________________________________
void EGViewer::AddStatusBar() {
    //
    // Add the status bar
    //
    
    //
    // Horizontal frame
    //
    TGLayoutHints *lay = new TGLayoutHints( kLHintsNormal|kLHintsExpandX,0,0,0,0 );

    fStatusFrame = new TGCompositeFrame(this, GetWidth() + 4, GetHeight() + 4,
            kHorizontalFrame);

    fList->Add(fStatusFrame);
    fList->Add(lay);

    TGLayoutHints *layprog = new TGLayoutHints( kLHintsNormal,3,2,0,2 );
    
    fProgressBar = new TGHProgressBar(fStatusFrame,150,18);
    fProgressBar->SetBarColor("lightblue");
    fProgressBar->ShowPosition();
    fProgressBar->SetFillType(TGProgressBar::kSolidFill);
    fStatusFrame->AddFrame(fProgressBar, layprog);


    fList->Add(layprog);
    fList->Add(fProgressBar);

    fStatusBar = new TGStatusBar(fStatusFrame, 1, 1);

    Int_t parts[] = { 28,10, 62 }; 
    fStatusBar->SetParts(parts, 3);

    TGLayoutHints *layb = new TGLayoutHints(kLHintsNormal|kLHintsExpandX, 2, 3, 0, 2);
    fStatusFrame->AddFrame(fStatusBar, layb);

    fList->Add(fStatusBar);
    fList->Add(layb);

    AddFrame(fStatusFrame, lay);

}


//______________________________________________________________________________
void EGViewer::CreateEditor() {
    //
    //
    //

    if (TVirtualPadEditor::GetPadEditor(kFALSE) != 0) {
        TVirtualPadEditor::HideEditor();
    }
    fEditorFrame->SetEditable();

    // next two lines are related to the old editor
    fEditor = TVirtualPadEditor::LoadEditor();
    fEditor->SetGlobal(kFALSE);
    fEditorFrame->SetEditable(0);
}

//______________________________________________________________________________
void EGViewer::ShowEditor( Bool_t show ) {
    //
    //
    //

    UInt_t w = GetWidth();
    UInt_t e = fEditorFrame->GetWidth();
    UInt_t h = GetHeight();

    if (show) {
        if ( !fCanvases->GetEntries() ) return;
        if (!fEditor) CreateEditor();

        fViewMenu->CheckEntry(kViewEditor);
        fEditor->Show();
        fMainFrame->ShowFrame(fEditorFrame);

        w += e;

    } else {
        fViewMenu->UnCheckEntry(kViewEditor);
        if ( fEditor) fEditor->Hide();
        fMainFrame->HideFrame(fEditorFrame);

        // 
        // If the editor does not exist, do not resize the window.
        // Useful in the constructor of child classes.
        w -= e;
    }

    Resize(w,h);
}

//______________________________________________________________________________
void EGViewer::ToggleEditor() {
    //
    //
    //
    
    ShowEditor(!fViewMenu->IsEntryChecked(kViewEditor));
}

//______________________________________________________________________________
TGCompositeFrame* EGViewer::AddEmptyTab( const char* title  ) {
    //
    //
    //

    TGCompositeFrame* f = GetTab()->AddTab(title);

    //
    // Combo entries handling
    //
    fTabCombo->AddEntry(title, fTabCombo->GetListBox()->GetNumberOfEntries());
    fTabCombo->Select(GetTab()->GetCurrent());
    fTabList->AddEntry(title, fTabList->GetNumberOfEntries());
    fTabList->Select(GetTab()->GetCurrent());
    fTabList->Layout();
    fTabList->MapSubwindows();

    GetTab()->Layout();          // seems to layout the TGCompositeFrame
    GetTab()->MapSubwindows();   // maps the TGCompositeFrame

    // display new tab in the main frame
    // FIXME: Workaround because TApplication::Run is not thread safe in
    //        respect of ProcessEvents
    if ( !TThread::Self() )
        gClient->ProcessEventsFor(GetTab());

    return f;
}

//______________________________________________________________________________
TCanvas* EGViewer::AddTab( const char* name, const char* title  ) {
    //
    // Add new tab
    //

    if ( gROOT->IsBatch() ) {
        TCanvas* c = new TCanvas( name, title ? title : name );
        fList->Add(c);
        fCanvases->Add(c);
        return c;
        
    }
    

    TVirtualPad* padsave = gPad;

    TGCompositeFrame *f = AddEmptyTab(title ? title: name );

    // create root embedded canvas and add it to the tab
    TRootEmbeddedCanvas *ec = new TRootEmbeddedCanvas(name, f, f->GetWidth(), f->GetHeight(), 0);
    f->AddFrame(ec, fLayCanvas);
    fList->Add(ec);

    TCanvas *c = ec->GetCanvas();
    c->SetBorderMode(0);
    c->SetTitle(title ? title : name );

    if (TestBit(kNoContextMenu))
        c->SetBit(kNoContextMenu);

    c->Connect("ProcessedEvent(Int_t,Int_t,Int_t,TObject*)",
            "EGViewer",this,
            "EventInfo(Int_t,Int_t,Int_t,TObject*)");


    // layout and map new tab
    GetTab()->Layout();          // seems to layout the TGCompositeFrame
    GetTab()->MapSubwindows();   // maps the TGCompositeFrame
    GetTab()->Layout();          // layout the embedded canvas in the frame
    fTabListFrame->Layout();


    // display new tab in the main frame
    // FIXME: Workaround because TApplication::Run is not thread safe in
    //        respect of ProcessEvents
    if ( !TThread::Self() )
        gClient->ProcessEventsFor(GetTab());

    fCanvases->Add(c);

    gPad = padsave;

    return c;

}

//______________________________________________________________________________
TCanvas* EGViewer::FindAddTab( const char* name, const char* title  ) {
    //
    // Add new tab if it's not already in the list
    //

    TCanvas* c = FindCanvas(name);

    if (!c) c = AddTab(name, title);
    else c->SetTitle(title);

    return c;
}

//______________________________________________________________________________
void EGViewer::RemoveTab(Int_t i ) {
    //
    // Remove the i-th Tab
    //
    
    TGCompositeFrame *f = GetTab()->GetTabContainer(i);
    if (!f)
        return;
    
    TRootEmbeddedCanvas *ec = GetEmbeddedCanvas(f);
    if (ec) {

        TCanvas *c = ec->GetCanvas();
        if (c) {
            fCanvases->Remove(c);
            if ( fEditor) {
                TGedEditor* ged = dynamic_cast<TGedEditor*>(fEditor);
                if ( !fCanvases->GetEntries() ) {
#ifdef DEBUG
                    cout << "Last canvas, close editor" << endl;
#endif /* DEBUG */
                    ShowEditor(kFALSE);
                    SafeDelete(fEditor);
                } else {
                    ged->DisconnectEditors(c);
                }
            }
            
        }

        f->RemoveFrame(ec);

        delete fList->Remove(ec);
    }

    GetTab()->RemoveTab(i);
    
    //
    // Combo entries handling
    //
    fTabCombo->RemoveEntry(i);
    for (int j=i; j<fTabCombo->GetListBox()->GetNumberOfEntries(); j++)
    {
        TGTextLBEntry *entry = (TGTextLBEntry *)fTabCombo->GetListBox()->Select(j+1, kFALSE);
        fTabCombo->AddEntry(entry->GetText()->GetString(), j);
        fTabCombo->RemoveEntry(j+1);
    }
    fTabList->RemoveEntry(i);
    for (int j=i; j<fTabList->GetNumberOfEntries(); j++)
    {
        TGTextLBEntry *entry = (TGTextLBEntry *)fTabList->Select(j+1, kFALSE);
        fTabList->AddEntry(entry->GetText()->GetString(), j);
        fTabList->RemoveEntry(j+1);
    }
    //
    SelectTab(0);

    fTabList->Layout();
    fTabList->MapSubwindows();

    GetTab()->Layout();          // seems to layout the TGCompositeFrame
    GetTab()->MapSubwindows();   // maps the TGCompositeFrame
    GetTab()->Layout();          // layout the embedded canvas in the frame
    fTabListFrame->Layout();

    // display new tab in the main frame
    // FIXME: Workaround because TApplication::Run is not thread safe in
    //        respect of ProcessEvents
    if ( !TThread::Self() )
        gClient->ProcessEventsFor(GetTab());
}

//______________________________________________________________________________
void EGViewer::SelectTab(Int_t i) const {

    GetTab()->SetTab(i);
    fTabCombo->Select(i);
    fTabList->Select(i);

    if ( TCanvas* c = FindCanvasByTab(i) ) { 
        c->cd(); 
        if ( fEditor ) {
            TGedEditor* ged = dynamic_cast<TGedEditor*>(fEditor);
            ged->SetCanvas(c);
#ifdef DEBUG
            cout << "Select tab " << i << " canvas  " << c << endl;
#endif /* DEBUG */
        }
    }

    // display new tab in the main frame
    // FIXME: Workaround because TApplication::Run is not thread safe in
    //        respect of ProcessEvents
    if ( !TThread::Self() )
        gClient->ProcessEventsFor(GetTab());
}

//______________________________________________________________________________
Int_t EGViewer::NextTab() const {
    //
    // Switch to the next tab
    //
    
    if ( !GetTab()->GetNumberOfTabs() )
        return -1;
            
    Int_t n = GetTab()->GetCurrent();

    if ( ++n == GetTab()->GetNumberOfTabs() ) n=0;
    SelectTab(n);
//    GetTab()->SetTab(n);
//    fTabCombo->Select(n);

    return n;
}

//______________________________________________________________________________
Int_t EGViewer::PrevTab() const {
    //
    // Switch to the next tab
    //
    
    if ( !GetTab()->GetNumberOfTabs() )
        return -1;
            
    Int_t n = GetTab()->GetCurrent();

    if ( --n == -1 ) n =GetTab()->GetNumberOfTabs()-1;
    SelectTab(n);

    return n;
}

//______________________________________________________________________________
void EGViewer::ShowTabList( Bool_t show) {
    //
    // Shows Tab Combo box
    //

    UInt_t w = GetWidth();
    UInt_t e = fTabListFrame->GetWidth();
    UInt_t h = GetHeight();

    if ( show ) {
        fViewMenu->CheckEntry( kViewCombo );
        fMenuFrame->ShowFrame(fTabCombo);
        fMainFrame->ShowFrame(fTabListFrame);

        w += e;
    } else {
        fViewMenu->UnCheckEntry( kViewCombo );
        fMenuFrame->HideFrame(fTabCombo);
        fMainFrame->HideFrame(fTabListFrame);

        w -= e;
    }

    Resize(w,h);
}

//______________________________________________________________________________
void EGViewer::ToggleTabList() {
    //
    // Toggles Tab Combo box.
    //

    ShowTabList( !fViewMenu->IsEntryChecked( kViewCombo ) );
}

//______________________________________________________________________________
Bool_t EGViewer::HandleEvent(Event_t* event) {

        return TGFrame::HandleEvent(event);

}

//______________________________________________________________________________
Bool_t EGViewer::HandleKey(Event_t* event) {
    //
    // Handle keybord commands
    //
    //

#ifdef DEBUG
    Printf("Event");
#endif
    if ((event->fType == kGKeyPress) && (event->fState & kKeyControlMask)) {
        UInt_t keysym;
        char str[2];

        gVirtualX->LookupString(event, str, sizeof(str), keysym);

        switch ( keysym ) {
            case kKey_Tab:
            case kKey_Right:
                NextTab();
                return kTRUE;
            case kKey_Left:
                PrevTab();
                return kTRUE;
        }
    }

    return TGMainFrame::HandleKey(event);
}

//______________________________________________________________________________
Bool_t EGViewer::ProcessMessage(Long_t msg, Long_t mp1, Long_t mp2 ) {
    //
    // Process the messages from the GUI
    //

    // Can be found in WidgetMessageTypes.h
#ifdef DEBUG
    //////cout << "Msg: " << GET_MSG(msg) << " Submsg:" << GET_SUBMSG(msg);
    //cout << " Mp1=" << mp1 << " Mp2=" << mp2 << endl;
#endif
    switch (GET_MSG(msg))
    {
        case kC_COMMAND:  // 1
            return ProcessMessageCommand(GET_SUBMSG(msg), mp1, mp2);

        case kC_TEXTVIEW: // 9
            return ProcessMessageTextview(GET_SUBMSG(msg), mp1, mp2);

        case kC_USER:     // 1001
            return ProcessMessageUser(GET_SUBMSG(msg), mp1, mp2);
    }
#ifdef DEBUG
    //cout << "Msg: " << GET_MSG(msg) << " Submsg:" << GET_SUBMSG(msg);
    //cout << " Mp1=" << mp1 << " Mp2=" << mp2 << endl;
#endif

    return kTRUE;
}

//______________________________________________________________________________
Bool_t EGViewer::ProcessMessageCommand(Long_t submsg, Long_t mp1, Long_t mp2) {
    //
    //
    //
    switch (submsg) {
        case kCM_MENU: // 1
            return ProcessMessageCommandMenu(mp1); // mp2=userdata
        case kCM_TAB:  // 8
            //            UpdateTab(GetTab()->GetTabContainer(mp1));
            //            Printf("kCM_TAB");
            SelectTab(mp1);
            return kTRUE;
        case kCM_COMBOBOX: // 7
            if (mp1==kW_COMBO_TABS)
                SelectTab(mp2);
            return kTRUE;
        case kCM_LISTBOX: // 7
            if (mp1==kW_LIST_TABS)
                SelectTab(mp2);
            return kTRUE;
    }

    return kTRUE;
}

//______________________________________________________________________________
Bool_t EGViewer::ProcessMessageCommandMenu(Long_t mp1) {
    //
    // Menu messages
    //

    switch (mp1) {
        case kFileSaveAs:
            {
                TGFileInfo fi;
                fi.fFileTypes   = gSaveAsTypes;
                fi.fFileTypeIdx = 0;
                fi.fOverwrite   = kFALSE;
                new TGFileDialog(gClient->GetRoot(), 0, kFDSave, &fi);

                if ( fi.fFilename ) {
                    TString name = fi.fFilename;

                    if ( name.EndsWith(".ps")) SaveAsPS(name);
                    if ( name.EndsWith(".pdf")) SaveAsPDF(name);
                    if ( name.EndsWith(".root")) SaveAsRoot(name);
                }
            }
            break;
        case kFileSaveAsPS:
            SaveAsPS();
            break;
        case kFileSaveAsPDF:
            SaveAsPDF();
            break;
        case kFileSaveAsRoot:
            SaveAsRoot();
            break;
        case kFileCloseViewer:
            SendCloseMessage();
            break;
        case kFileExit:
            gApplication->Terminate(0);
            break;

        case kViewEditor:
            ToggleEditor();
            break;
        case kViewCombo:
            ToggleTabList();
            break;
        case kViewX3D:
            gPad->GetViewer3D("x3d");
            break;
        case kViewOpenGL:
            gPad->GetViewer3D("ogl");
            break;

        case kTabClonePad:
            if ( IsPadLookup() )
                SetPadLookup(kFALSE);
            else
                SetPadLookup(kTRUE);
            break;
        case kOptionStatistics:
            if (gStyle->GetOptStat()) {
                gStyle->SetOptStat(0);
                delete gPad->FindObject("stats");
                fOptionMenu->UnCheckEntry(kOptionStatistics);
            } else {
                gStyle->SetOptStat(1);
                fOptionMenu->CheckEntry(kOptionStatistics);
            }
            gPad->Modified();
            gPad->Update();
            break;
        case kOptionHistTitle:
            if (gStyle->GetOptTitle()) {
                gStyle->SetOptTitle(0);
                delete gPad->FindObject("title");
                fOptionMenu->UnCheckEntry(kOptionHistTitle);
            } else {
                gStyle->SetOptTitle(1);
                fOptionMenu->CheckEntry(kOptionHistTitle);
            }
            gPad->Modified();
            gPad->Update();
            break;
        case kOptionFitParams:
            if (gStyle->GetOptFit()) {
                gStyle->SetOptFit(0);
                fOptionMenu->UnCheckEntry(kOptionFitParams);
            } else {
                gStyle->SetOptFit(1);
                fOptionMenu->CheckEntry(kOptionFitParams);
            }
            gPad->Modified();
            gPad->Update();
            break;
        case kOptionCanEdit:
            if (gROOT->GetEditHistograms()) {
                gROOT->SetEditHistograms(kFALSE);
                fOptionMenu->UnCheckEntry(kOptionCanEdit);
            } else {
                gROOT->SetEditHistograms(kTRUE);
                fOptionMenu->CheckEntry(kOptionCanEdit);
            }
            break;
        case kSizeA4:
            Resize(640,A4Height(640));
            break;
        case kSize640:
            Resize(640,480);
            break;
        case kSize800:
            Resize(800,600);
            break;
        case kSize960:
            Resize(960,720);
            break;
        case kSize1024:
            Resize(1024,768);
            break;
        case kSize1280:
            Resize(1280,1024);
            break;

    }
    return kTRUE;
}

//______________________________________________________________________________
Bool_t EGViewer::ProcessMessageTextview(Long_t submsg, Long_t mp1, Long_t mp2) {
    return kTRUE;
}

//______________________________________________________________________________
Bool_t EGViewer::ProcessMessageUser(Long_t submsg, Long_t mp1, Long_t mp2) {
    return kTRUE;
}

//______________________________________________________________________________
TRootEmbeddedCanvas *EGViewer::GetEmbeddedCanvas(TGCompositeFrame *cf) const {
    //
    // Takes a TGCompositeFrame as argument. Searches for the first
    // TRootEmbeddedCanvas which is contained by it and returns a pointer
    // to the corresponding TCanvas. If it isn't found NULL is returned.
    //

    TIter next(cf->GetList());

    TGFrameElement *f;
    while ((f=(TGFrameElement*)next()))
        if (f->fFrame->InheritsFrom(TRootEmbeddedCanvas::Class()))
            return (TRootEmbeddedCanvas*)f->fFrame;

    return NULL;
}


//______________________________________________________________________________
TCanvas* EGViewer::CurrentCanvas() const {
    //
    // Returns the canvas in the selected tab, otherwise 0
    //
    return FindCanvasByTab(GetTab()->GetCurrent());

}

//______________________________________________________________________________
TCanvas* EGViewer::FindCanvasByTab(int i) const {
    //
    // Returns GetCanvas of the i-th Tab.
    //

    //    if (gROOT->IsBatch())
    //        return (TCanvas*)fBatch->At(i-1);

    if (i<0 || i>=GetTab()->GetNumberOfTabs())
    {
        return NULL;
    }

    return FindCanvasByTab(GetTab()->GetTabContainer(i));
}

//______________________________________________________________________________
TCanvas* EGViewer::FindCanvasByTab(TGCompositeFrame *f) const {
    //
    // Takes a TGCompositeFrame as argument. Searches for the first
    // TRootEmbeddedCanvas which is contained by it and returns a pointer
    // to the corresponding TCanvas. If it isn't found NULL is returned.
    //

    TRootEmbeddedCanvas *ec = GetEmbeddedCanvas(f);
    return ec ? ec->GetCanvas() : NULL;
}

//______________________________________________________________________________
TCanvas* EGViewer::FindCanvas(const char* name) const {

    //if (gROOT->IsBatch())
    //    return (TCanvas*)fBatch->FindObject(name);
/*
    TGFrameElement *f;
    TIter next(GetTab()->GetList());
    while ((f=(TGFrameElement*)next()))
    {
        TObject *frame = f->fFrame;
        if (!frame->InheritsFrom(TGTabElement::Class()))
            continue;

        TGTabElement *tab = (TGTabElement*)frame;
        if (tab->GetString()==name)
            break;
    }

    // Search for the next TGCompositeFrame in the list
    while ((f=(TGFrameElement*)next()))
    {
        Printf("%s",f->GetName());
        TObject *frame = f->fFrame;
        if (frame->InheritsFrom(TGCompositeFrame::Class()))
            return FindCanvasByTab((TGCompositeFrame*)frame);
    }

    return NULL;
    */

    return (TCanvas*)fCanvases->FindObject(name);
}

//______________________________________________________________________________
void EGViewer::RemoveTab( const char* name ) {
    //
    // Find and remove the tab with name
    //

    Int_t count(0);
    
    TGFrameElement *f;
    TIter next(GetTab()->GetList());
    while ((f=(TGFrameElement*)next()))
    {
        TGTabElement *tab = dynamic_cast<TGTabElement*>(f->fFrame);
        if ( tab ) {
            if ( (*tab->GetText()) == name ) break;
            count++;
        }
        
    }

    if ( count == GetTab()->GetNumberOfTabs()) return;

    RemoveTab(count);
    
}

//______________________________________________________________________________
void EGViewer::RemoveTabs() {
    //
    // Find the tab with name
    //

    while(GetTab()->GetNumberOfTabs())
        RemoveTab(0);
}

//______________________________________________________________________________
void EGViewer::SetStatusText(const char *txt, Int_t partidx) {
    // 
    // Set text in status bar.
    //

    fStatusBar->SetText(txt, partidx);
    
    if ( !TThread::Self() )
        gClient->ProcessEventsFor(fStatusBar);
}

//______________________________________________________________________________
void EGViewer::SetStatusText(const char *txt, Int_t partidx) const {
    //
    // Const version of SetStatusText
    //

    ((EGViewer*)this)->SetStatusText(txt,partidx);
}
//______________________________________________________________________________
void EGViewer::UpdateTab(TGCompositeFrame *f) {
    //
    // Update a canvas in a tab, takes the corresponding TGCompositeFrame
    // as an argument. This is necessary, because not all functions
    // changing the contents of a canvas or pad can call SetModified()
    // for the corresponding tab. If this is not called correctly the
    // tab won't be updated calling TCanvas::Update(). So we simply
    // redraw it by our own (instead we could recursively call
    // TPad::Modified() for everything contained by the TCanvas and
    // call TCanvas::Update() afterwards)
    //

    if (!f)
        return;

    TCanvas *c=FindCanvasByTab(f);
    if (!c)
        return;

    //
    // If we are in a multithreaded environment (gThreadXAR) we
    // have to make sure, that thus function is called from
    // the main thread.
    //
    if (gThreadXAR)
    {
        // Tell the X-Requester how to call this method
        TString str = Form("%d", (ULong_t)f);

        TMethodCall call(IsA(), "UpdateTab", "NULL");
        void *arr[4] = { NULL, &call, this, (void*)(const char*)str };

        // If this is not the main thread return
        if (((*gThreadXAR)("METH", 4, arr, NULL)))
            return;
    }

    //
    // Secure calls to update the tabs against itself, at least
    // c->Paint() or c->Flush() may crash X (bad drawable).
    // This makes sure, that a X call is not interuppted by
    // another X-call which was started from an gui interrrupt
    // in the same thread
    //
    if (fMutex->TryLock())
        return;

    if (!c->IsBatch())
        c->FeedbackMode(kFALSE);  // Goto double buffer mode

    //
    // Doing this ourself gives us the possibility to repaint
    // the canvas in any case (Paint() instead of PaintModified())
    //
    c->Paint();                   // Repaint all pads
    c->Flush();                   // Copy all pad pixmaps to the screen

    fMutex->UnLock();
}

//______________________________________________________________________________
Bool_t EGViewer::CloneToCanvas(TVirtualPad* pad) {
    //
    //
    //

    if (!pad) return kFALSE;

    TCanvas *nc = new TCanvas("c_clone_canvas",pad->GetTitle());
    DrawClonePad(nc,pad);

    return kTRUE;

}


//______________________________________________________________________________
void EGViewer::AddPadToClean(TVirtualPad* pad) const {
    //
    //
    //
    TListIter next(pad->GetListOfPrimitives());

    while( TObject *obj = next()) {
        obj->SetBit(kCanDelete|kMustCleanup);

        if ( dynamic_cast<TVirtualPad*>(obj) )
            AddPadToClean((TVirtualPad*)obj);
    }
    
}
//______________________________________________________________________________
void EGViewer::DrawClonePad(TVirtualPad *newp, TVirtualPad *oldp) const
{
    if (!newp || !oldp) 
        return;

    TVirtualPad* savepad = gPad;
    const Bool_t store = TH1::AddDirectoryStatus();
    TH1::AddDirectory(kFALSE);

//    if ( dynamic_cast<TPad*>(newp) )
//        gROOT->GetListOfCleanups()->Add(newp);

    newp->cd();
    newp->Range(oldp->GetUxmin(),oldp->GetUymin(),oldp->GetUxmax(),oldp->GetUymax());
    oldp->TAttFill::Copy(*newp);
    oldp->TAttLine::Copy(*newp);
    oldp->TAttPad::Copy(*newp);

    newp->SetLogx(oldp->GetLogx());
    newp->SetLogy(oldp->GetLogy());
    newp->SetLogz(oldp->GetLogz());
    newp->SetTickx(oldp->GetTickx());
    newp->SetTicky(oldp->GetTicky());
    newp->SetGridx(oldp->GetGridx());
    newp->SetGridy(oldp->GetGridy());
    newp->SetBorderSize(oldp->GetBorderSize());
    newp->SetBorderMode(oldp->GetBorderMode());

    TListIter next(oldp->GetListOfPrimitives());

    TObject *newobj;
    while( TObject *obj = next()) {
        newobj = obj->Clone();
        if (!newobj) continue;

        // the following lines are the same as in DrawClonePad
        // Clone also important bits (FIXME: Is this correct)
        newobj->SetBit(obj->TestBits(kCannotPick|kNoContextMenu));

        // Clone also important bits (FIXME: Is this correct)
        newobj->SetBit(kCanDelete|kMustCleanup);

        // FIXME: This is a workaround for the problem with the MAstroCatalog in
        // MHFalseSource. It doesn't harm. We'll still try to find the reason
        if (newobj->IsA()==TPad::Class()) {
            gROOT->GetListOfCleanups()->Add(newobj);
            AddPadToClean((TVirtualPad*)newobj);
        }

        newobj->Draw(next.GetOption());

    }

    newp->Modified();
    newp->Update();

    TH1::AddDirectory(store);

    savepad->cd();

}

//______________________________________________________________________________
void EGViewer::SetPadLookup( Bool_t lookup ) {

    fPadLookup = lookup;
    if ( fPadLookup ) {
        fTabMenu->CheckEntry( kTabClonePad );
    } else {
        fTabMenu->UnCheckEntry( kTabClonePad );
    }
}

//______________________________________________________________________________
void EGViewer::EventInfo(Int_t event, Int_t px, Int_t py, TObject *selected) {
    //
    //    This function is called when the option "Event Status"
    //    in the canvas menu "Options" is selected.
    //

    const Int_t kTMAX=256;
    static char atext[kTMAX];

    TVirtualPad* savepad = gPad;
    
    TCanvas *c = (TCanvas*)gTQSender;
//    if (!c) return;  delete

    if ( IsPadLookup() ) {
        TVirtualPad* pad = c->GetSelectedPad();
        if ( c->GetEvent() == kButton1Up ) {
            CloneToCanvas(pad);
            SetPadLookup(kFALSE);
            c->FeedbackMode(kFALSE);
        }

        if ( pad && fOldPad != pad) {
            gVirtualX->SetLineWidth(2);
            c->FeedbackMode(kTRUE);
//            gVirtualX->SetDrawMode(TVirtualX::kCopy);

            if ( fOldPad ) {
                UInt_t px1old, py1old, px2old, py2old;
                px1old = fOldPad->XtoAbsPixel(fOldPad->GetX1());
                py1old = fOldPad->YtoAbsPixel(fOldPad->GetY1());
                px2old = fOldPad->XtoAbsPixel(fOldPad->GetX2());
                py2old = fOldPad->YtoAbsPixel(fOldPad->GetY2());

                gVirtualX->DrawBox(px1old-2,py1old-2,px2old+2,py2old+2,TVirtualX::kHollow);
            }

            UInt_t px1, py1, px2, py2;
            px1 = pad->XtoAbsPixel(pad->GetX1());
            py1 = pad->YtoAbsPixel(pad->GetY1());
            px2 = pad->XtoAbsPixel(pad->GetX2());
            py2 = pad->YtoAbsPixel(pad->GetY2());
            gVirtualX->DrawBox(px1-2,py1-2,px2+2,py2+2,TVirtualX::kHollow);
//            Printf("Box");
        }

        fOldPad = pad;
        
        sprintf(atext, "Select the pad to Clone");
        SetStatusText(atext,2);
        return;
    }
    
    if (!selected) return;

    gPad = c->GetSelectedPad();

    SetStatusText(selected->GetName(),0);
    if (event == kKeyPress)
        sprintf(atext, "%c", (char) px);
    else
        sprintf(atext, "%d,%d", px, py);
    SetStatusText(atext,1);
    SetStatusText(selected->GetObjectInfo(px,py),2);

    gPad = savepad;
}

//______________________________________________________________________________
void EGViewer::SetPadFillColor(TVirtualPad &p, Int_t col) const {
    //
    // Set the background color in a canvas
    //

    TObject *obj;

    // See also TPad::UseCurrentStyle
    TIter next(p.GetListOfPrimitives());
    while ((obj=next()))
    {
        if (obj->InheritsFrom(TPad::Class()))
            SetPadFillColor(*(TPad*)obj, col);
        if (obj->InheritsFrom(TFrame::Class()))
            ((TFrame*)obj)->SetFillColor(col);
    }

    p.SetFillColor(col);
}

//______________________________________________________________________________
void EGViewer::UpdatePSHeader(const TString &name) const {
//
// Insert the following two lines into the postscript header:
//
//   %%DocumentPaperSizes: a4
//   %%Orientation: Landscape
//

    const TString newstr("%%DocumentPaperSizes: a4n%%Orientation: Landscapen");

    ifstream fin(name);
    ofstream fout(name+".$$$");

    char c;

    TString str;
    fin >> str >> c;                // Read "%!PS-Adobe-2.0n"
    fout << str << endl << newstr;

    // Doing it in blocks seems not to gain much for small (MB) files
    while (fin)
    {
        fin.read(&c, 1);
        fout.write(&c, 1);
    }

    gSystem->Unlink(name);
    gSystem->Rename(name+".$$$", name);
}

////______________________________________________________________________________
//Int_t EGViewer::SaveAsPS( const char* name ) {
//    //
//    // Save all tabs in a PS File
//    //
//    
//    Int_t npages = fCanvases->GetEntries();
//    if ( !npages ) return 0;
//
//    if ( !name ) name = GetName();
//    
//    TString psname(name);
//    if ( !psname.EndsWith(".ps") ) psname+=".ps";
//    
//
//    TVirtualPad* padsave = gPad;
//    TVirtualPS* pssave = gVirtualPS;
//
//    TPostScript ps(psname, 112);
//    ps.SetBit(TPad::kPrintingPS);
//    ps.PrintFast(13, "/nan {1} def ");
//
//    gVirtualPS = &ps;
//
//    // Create a list to delete the canvas clones
//    TList l;
//    l.SetOwner();
//
//    Int_t page = 0 ;
//
//    TIter next(fCanvases);
//
//    while( TCanvas* c=(TCanvas*)next()) {
//        ps.NewPage();
//
//        SetStatusText("Printing..",0);
//        SetStatusText(Form("Canvas %s on page %d",c->GetTitle(),++page),2);
//        
//        TCanvas *clone = (TCanvas*)c->Clone();
//        SetPadFillColor(*clone, kWhite);
//        l.Add(clone);
//
//        clone->SetBatch(kTRUE);
//        // test
//        clone->Size(.9*kA4Width, .9*kA4Height);
//
//        ps.Range(0.925*kA4Width,0.90*kA4Height); // A4
//
//        clone->Paint();
//
//        gPad=clone;
//
//        //
//        // Create some GUI elements for a page legend
//        //
//        TLine line;
//        //
//        // Print overlaying text (NDC = %)
//        //
//        ps.SetTextColor(kBlack);
//        ps.SetTextSize(0.025);
//        ps.SetTextFont(62);
//        ps.SetTextAlign(11); // left top
//        ps.TextNDC(0, 1.015, TString("  ")+clone->GetTitle());
//        ps.SetTextAlign(21); // cent top
//        ps.TextNDC(0.5, 1.015, "ESAF");
//        ps.SetTextAlign(31); // right top
//        ps.TextNDC(1, 1.015, Form("Page No.%i (%i)  ", page, npages));
//        line.PaintLineNDC(0, 1.01, 1, 1.01);
//
//        line.PaintLineNDC(0, -0.01, 1, -0.01);
//        ps.SetTextAlign(13); // left top
//        if ( !fTitle.IsNull() ) ps.TextNDC(0, -0.015, TString("  ")+fTitle);
//        ps.SetTextAlign(33); // right top
//        ps.TextNDC(1, -0.015, "Comment");
//
//        clone->SetBatch(kFALSE);
//    }
//    gPad=NULL;
//    l.Delete();
//    ps.Close();
//
//    UpdatePSHeader(psname);
//    
//    gVirtualPS = pssave;
//    if (padsave)
//        padsave->cd();
//
//        SetStatusText(Form("Done (%d pages)",page),0);
//    return page;
//
//}

//______________________________________________________________________________
Int_t EGViewer::SaveAsPS( const char* name ) {
    //
    // Save all tabs in a PDF File.
    // FIXME: the behaviour is not well understood, use SaveAsPS instead
    //

    Int_t npages = fCanvases->GetEntries();
    if ( !npages ) return 0;

    if ( !name ) name = GetName();

    TString psname(name);
    if ( !psname.EndsWith(".ps") ) psname+=".ps";


    TVirtualPad* padsave = gPad;
    TVirtualPS* pssave = gVirtualPS;

    // change to the target canvas before the first image
    TCanvas* first = ((TCanvas*)fCanvases->First());
    first->cd();

    TPostScript *ps = new TPostScript;
    ps->Range(0.9*kA4Width,0.9*kA4Height);
    ps->Open(psname, 112);
    ps->SetBit(TPad::kPrintingPS);

    gVirtualPS = ps;

    // Create a list to delete the canvas clones
    Int_t page = 0 ;

    TIter next(fCanvases);

    while( TCanvas* c=(TCanvas*)next() ) {
        // suspend writhing while arranging the canvas
        ps->Off();
        gPad = 0;
        c->cd();
        
        Float_t xmin = 0.03;
        Float_t xmax = 0.97;
        Float_t ymin = 0.06;
        Float_t ymax = 0.94;

        SetStatusText("Printing..",0);
        SetStatusText(Form("Canvas %s on page %d",c->GetTitle(),++page),2);

        TCanvas *clone = new TCanvas("", c->GetTitle());
        TPad* newpad = new TPad("backgroud","backgroud",xmin,ymin,xmax,ymax,kWhite,0);
        newpad->Draw();
        newpad->cd();
        TList* oldl = c->GetListOfPrimitives();
        TListIter next(oldl);
        while( TObject *obj = next()) {
            TObject* newobj = obj->Clone();
            newobj->SetBit(kCanDelete);
            newobj->Draw();
        }
        clone->Size(kA4Width, kA4Height);
        clone->cd();
        clone->Modified();
        clone->PaintModified();

        SetPadFillColor(*clone, kWhite);
        ps->Range(0.925*kA4Width,0.925*kA4Height);
        ps->NewPage();

        // write to file from now.
        ps->On();

        clone->Paint();

        gPad=clone;

        //
        // Create some GUI elements for a page legend
        //
        TLine line;
        //
        // Print overlaying text (NDC = %)
        //
        ps->SetTextColor(kBlack);
        ps->SetTextSize(0.025);
        ps->SetTextFont(62);
        ps->SetTextAlign(13); // left top
        ps->TextNDC(xmin, ymax+0.05, TString("  ")+clone->GetTitle());
        ps->SetTextAlign(23); // cent top
        ps->TextNDC(0.5, ymax+0.05, "ESAF");
        ps->SetTextAlign(33); // right top
        ps->TextNDC(xmax, ymax+0.05, Form("Page No.%i (%i)  ", page, npages));
        line.PaintLineNDC(xmin, ymax+0.01, xmax, ymax+0.01);

        line.PaintLineNDC(xmin, ymin-0.01, xmax, ymin-0.01);
        ps->SetTextAlign(11); // left top
        if ( !fTitle.IsNull() ) ps->TextNDC(xmin, ymin-0.04, TString("  ")+fTitle);
        ps->SetTextAlign(31); // right top
        ps->TextNDC(xmax, ymin-0.04, "Comment");

        delete clone;
    }
        
    gPad=NULL;
    ps->Close();
    delete ps;

    UpdatePSHeader(psname);

    gVirtualPS = pssave;
    if (padsave)
        padsave->cd();

    SetStatusText(Form("Done (%d pages)",page),0);
    return page;

}
//______________________________________________________________________________
Int_t EGViewer::SaveAsPDF( const char* name ) {
    //
    // Save all tabs in a PDF File.
    // FIXME: the behaviour is not well understood, use SaveAsPS instead
    //

    Int_t npages = fCanvases->GetEntries();
    if ( !npages ) return 0;

    if ( !name ) name = GetName();

    TString pdfname(name);
    if ( !pdfname.EndsWith(".pdf") ) pdfname+=".pdf";


    TVirtualPad* padsave = gPad;
    TVirtualPS* pssave = gVirtualPS;

    // change to the target canvas before the first image
    TCanvas* first = ((TCanvas*)fCanvases->First());
    first->cd();

    TPDF *pdf = new TPDF;
    pdf->Open(pdfname, 112);
    pdf->SetBit(TPad::kPrintingPS);

    gVirtualPS = pdf;

    // Create a list to delete the canvas clones
    Int_t page = 0 ;

    TIter next(fCanvases);

    while( TCanvas* c=(TCanvas*)next() ) {
        // suspend writhing while arranging the canvas
        pdf->Off();
        gPad = 0;
        c->cd();
        
        Float_t xmin = 0.03;
        Float_t xmax = 0.97;
        Float_t ymin = 0.06;
        Float_t ymax = 0.94;

        SetStatusText("Printing..",0);
        SetStatusText(Form("Canvas %s on page %d",c->GetTitle(),page+1),2);

        //______________________________________________________________________________
        TCanvas *clone = new TCanvas("", c->GetTitle());
        TPad* newpad = new TPad("backgroud","backgroud",xmin,ymin,xmax,ymax,kWhite,0);
        newpad->Draw();
        newpad->cd();
        TList* oldl = c->GetListOfPrimitives();
        TListIter next(oldl);
        while( TObject *obj = next()) {
            TObject* newobj = obj->Clone();
            newobj->SetBit(kCanDelete);
            newobj->Draw();
        }
        clone->cd();

        SetPadFillColor(*clone, kWhite);
        if ( page++ ) {
            // use first as template
            pdf->NewPage();
        }
        // write to file from now.
        pdf->On();

        clone->Paint();

        gPad=clone;

        //
        // Create some GUI elements for a page legend
        //
        TLine line;
        //
        // Print overlaying text (NDC = %)
        //
        pdf->SetTextColor(kBlack);
        pdf->SetTextSize(0.025);
        pdf->SetTextFont(62);
        pdf->SetTextAlign(13); // left top
        pdf->TextNDC(xmin, ymax+0.05, TString("  ")+clone->GetTitle());
        pdf->SetTextAlign(23); // cent top
        pdf->TextNDC(0.5, ymax+0.05, "ESAF");
        pdf->SetTextAlign(33); // right top
        pdf->TextNDC(xmax, ymax+0.05, Form("Page No.%i (%i)  ", page, npages));
        line.PaintLineNDC(xmin, ymax+0.01, xmax, ymax+0.01);

        line.PaintLineNDC(xmin, ymin-0.01, xmax, ymin-0.01);
        pdf->SetTextAlign(11); // left top
        if ( !fTitle.IsNull() ) pdf->TextNDC(xmin, ymin-0.04, TString("  ")+fTitle);
        pdf->SetTextAlign(31); // right top
        pdf->TextNDC(xmax, ymin-0.04, "Comment");

        delete clone;
    }
        
    gPad=NULL;
    pdf->Close();
    delete pdf;


    gVirtualPS = pssave;
    if (padsave)
        padsave->cd();

    SetStatusText(Form("Done (%d pages)",page),0);
    return page;

}


//______________________________________________________________________________
Int_t EGViewer::SaveAsRoot(const char* name) {
    //
    //
    //

    Int_t npages = fCanvases->GetEntries();
    if ( !npages ) return 0;

    if ( !name ) name = GetName();

    TString rootname(name);
    if ( !rootname.EndsWith(".root") ) rootname+=".root";

    TFile f(rootname,"RECREATE");

    Write();
    f.Close();

    SetStatusText(Form("%s saved", rootname.Data()),0);
    return fCanvases->GetEntries();
}

//______________________________________________________________________________
Int_t EGViewer::A4Height( Int_t w ) {

    Int_t bw = GetWidth()-GetTab()->GetWidth()+4; // border width
    Int_t bh = GetHeight()-GetTab()->GetHeight()+GetTab()->GetTabHeight()+4; // canvas height

    Int_t cw = w-bw;
    Int_t ch = (Int_t)(cw/kA4CanvasWHRatio);

    return ch+bh;
    
}

//______________________________________________________________________________
void EGViewer::ShowProgressBarPosition(Bool_t set, Bool_t percent, const char* format) {
    fProgressBar->ShowPosition( set, percent, format);
}


//______________________________________________________________________________
Int_t EGViewer::Write(const char *name, Int_t option, Int_t bufsize) const {
    //
    //
    //

    return fCanvases->Write(name ? name : GetName(), kSingleKey);
    
}

//______________________________________________________________________________
Int_t EGViewer::Read(const char *name) {
    //
    //
    //
    
    TList list;
    if ( !gFile )
        return 0;

    Int_t bytes = list.Read(name);

    TIter next(&list);

    while( TCanvas* c = dynamic_cast<TCanvas*>(next())) {
        if (!c) continue;

        TString name = c->GetName();
        TString title = c->GetTitle();

        TCanvas *nc = AddTab( name, !title.IsNull() ? title : name );
        DrawClonePad(nc, c);
    }

    return bytes;
}

ClassImp(EClusterOfPrimitives)

//______________________________________________________________________________
//
//   EClusterOfPrimitives
//


//______________________________________________________________________________
 EClusterOfPrimitives::EClusterOfPrimitives() : TList() {
    //
    // Constructor
    //

}

//______________________________________________________________________________
 EClusterOfPrimitives::EClusterOfPrimitives( const char* name, const char* title)
    : TList(), fName(name), fTitle(title) {
    //
    // Constructor
    //

}


//______________________________________________________________________________
 EClusterOfPrimitives::~EClusterOfPrimitives() {
    //
    // Destructor
    //

}

//______________________________________________________________________________
 void EClusterOfPrimitives::Draw(Option_t *option) {
    //
    // Draw all the objects in the list according their sequence
    //

    TString opt(option);

    if ( opt.Contains("paint") ) {
        TObject::Draw(opt);
    } else {
        TObjLink *lnk = FirstLink();
        while (lnk) {
            lnk->GetObject()->Draw(lnk->GetOption());
            lnk = lnk->Next();
        }
    }
}


//______________________________________________________________________________
 void EClusterOfPrimitives::Paint(Option_t *option) {
    //
    //
    //

    TObjLink *lnk = FirstLink();
    while (lnk) {
        lnk->GetObject()->Paint(lnk->GetOption());
        lnk = lnk->Next();
    }
}

//______________________________________________________________________________
 Int_t EClusterOfPrimitives::DistancetoPrimitive(Int_t px, Int_t py) {
    //
    //
    //

    Int_t dist = 999999;
    TObject* obj = 0;
    TObjLink *lnk = LastLink();
    while (lnk) {
        Int_t newdist = lnk->GetObject()->DistancetoPrimitive(px, py);
        if ( newdist < dist ) {
            dist = newdist;
            obj = lnk->GetObject();
        } 
        lnk = lnk->Prev();
    }

//    if ( obj ) gPad->SetSelected(obj);
    return dist;
}

//______________________________________________________________________________
 void EClusterOfPrimitives::ExecuteEvent(Int_t event, Int_t px, Int_t py) {
    //
    //
    //
    
    TObject *obj = Locate(px,py);

    if ( obj ) {
        Printf("Located %s",obj->GetName());
        obj->ExecuteEvent(event,px,py);
    }
    
}

//______________________________________________________________________________
 TObject* EClusterOfPrimitives::Locate(Int_t px, Int_t py) const {
    //
    // Locate the closest object
    //
    //
    
    TObject *obj = 0;
    Int_t dist = 999999;
    
    TObjLink *lnk = FirstLink();
    while (lnk) {
        Int_t objdist = lnk->GetObject()->DistancetoPrimitive(px, py);
        if ( objdist < dist ) {
            dist = objdist;
            obj = lnk->GetObject();
        }
        
        lnk = lnk->Next();
    }

    return obj; 
}

//______________________________________________________________________________
 char* EClusterOfPrimitives::GetObjectInfo(Int_t px, Int_t py) const {
    //
    //
    //

    TObject *obj = Locate(px,py);

    if ( obj ) {
        Printf("GetObjectInfo %s",obj->GetName());
        return obj->GetObjectInfo(px,py);
    }

    return "";

}

About Us | EUSO Official Website | Web pages created by Roberto Pesce and Alessandro Thea - Last Update Wed Nov 16 16:57:39 2005 Wed Nov 16 16:29:22 2005