source: JEM-EUSO/esaf_lal/tags/v1_r0/esaf/packages/common/eventviewer/src/EGViewer.cc @ 117

Last change on this file since 117 was 117, checked in by moretto, 11 years ago

ESAF version compilable on mac OS

File size: 60.1 KB
Line 
1// $Id: EGViewer.cc 2924 2011-06-12 20:22:13Z mabl $
2// Author: Alessandro Thea   2005/05/23
3
4/*****************************************************************************
5 * ESAF: Euso Simulation and Analysis Framework                              *
6 *                                                                           *
7 *  Id: EGViewer                                                             *
8 *  Package: <packagename>                                                   *
9 *  Coordinator: <coordinator>                                               *
10 *                                                                           *
11 *****************************************************************************/
12
13//_____________________________________________________________________________
14//
15// EGViewer
16//
17// <extensive class description>
18//
19//   Config file parameters
20//   ======================
21//
22//   <parameter name>: <parameter description>
23//   -Valid options: <available options>
24//
25
26#include "EGViewer.hh"
27 
28#include <iostream>
29#include <fstream>
30
31#include <TApplication.h>
32#include <TFile.h>
33#include <TCanvas.h>
34#include <TFrame.h>
35#include <TG3DLine.h>
36#include <TGComboBox.h>
37#include <TGListBox.h>
38#include <TGLayout.h>
39#include <TGMenu.h>
40#include <TGProgressBar.h>
41#include <TGStatusBar.h>
42#include <TGTab.h>
43#include <TLine.h>
44#include <TMethodCall.h>
45#include <TMutex.h>
46#include <TPostScript.h>
47#include <TPDF.h>
48#include <TRootEmbeddedCanvas.h>
49#include <TStyle.h>
50#include <TText.h>
51#include <TVirtualPS.h>
52#include <TVirtualPadEditor.h>
53#include <TGLabel.h>
54#include <TGFileDialog.h>
55#include <TH1.h>
56#include <TGedEditor.h>
57#include "KeySymbols.h"
58#include <TROOT.h>
59// 28 and 19 used here to scale the canvas into a height of 28, such that the
60// page title can be set above the canvas...
61const Float_t kA4Width  = 29.7; // A4 - width (29.7)
62const Float_t kA4Height = 21.0; // A4 - height (21.0)
63const Float_t kA4PrintWidth  = 27.9; // A4 - width (29.7)
64const Float_t kA4PrintHeight = 19.5; // A4 - height (21.0)
65const Float_t kA4CanvasWHRatio = 1.5; // A4 - height (21.0)
66
67enum EEGViewerCommands { 
68                         kFileSaveAs,
69                         kFileSaveAsPS,
70                         kFileSaveAsPDF,
71                         kFileSaveAsRoot,
72                         kFileCloseViewer,
73                         kFileExit,
74                       
75                         kViewEditor,
76                         kViewCombo,
77                         kViewX3D,
78                         kViewOpenGL,
79                       
80                         kPadExpandOnce,
81                         kPadExpandLoop,
82                         kPadUseMultiWin,
83                         kPadOwnCanvas,
84
85                         kOptionStatistics,
86                         kOptionHistTitle,
87                         kOptionFitParams,
88                         kOptionCanEdit,
89
90                         kSizeA4,
91                         kSize640,
92                         kSize800,
93                         kSize960,
94                         kSize1024,
95                         kSize1280,
96
97                         kW_COMBO_TABS,
98                         kW_LIST_TABS
99};
100
101
102static const char *gSaveAsTypes[] = { "PostScript",   "*.ps",
103                                //    "Encapsulated PostScript", "*.eps",
104                                      "PDF",          "*.pdf",
105                                //    "SVG",          "*.svg",
106                                //    "GIF",          "*.gif",
107                                //    "ROOT macros",  "*.C",
108                                      "ROOT files",   "*.root",
109                                //    "XML",          "*.xml",
110                                //    "PNG",          "*.png",
111                                //    "XPM",          "*.xpm",
112                                //    "JPEG",         "*.jpg",
113                                //    "TIFF",         "*.tiff",
114                                //    "XCF",          "*.xcf",
115                                      "All files",    "*",
116                                      0,              0 };
117using namespace std;
118using namespace TMath;
119
120ClassImp(EGViewer)
121
122//_____________________________________________________________________________
123EGViewer::EGViewer( const char* name, const char* title, Int_t w, Int_t h) : TGMainFrame(gClient->GetRoot(), w, h) {
124    //
125    // Constructor
126    //
127
128    TString wname = name ? name : "EGViewer";
129    TString wtitle = title ? title : wname.Data();
130    Constructor(wname,wtitle);
131
132    Resize(w,h);
133
134    // draw the window
135    MapWindow();
136    if ( !TThread::Self() )
137        gSystem->ProcessEvents();
138}
139
140//_____________________________________________________________________________
141EGViewer::EGViewer(Bool_t build, const char* name, Int_t w, Int_t h) : TGMainFrame(gClient->GetRoot(), w, h) {
142    //
143    // Protected constructor
144    //
145
146    if ( build ) {
147        TString wname = name ? name : "EGViewer";
148
149        Constructor( name , name);
150
151        Resize(w,h);
152    }
153}
154
155//______________________________________________________________________________
156Bool_t EGViewer::Constructor(const char* name, const char* title) {
157    //
158    // Build the Viewer
159    //
160
161    delete gROOT->GetListOfSpecials()->FindObject(name);
162    gROOT->GetListOfSpecials()->Add(this);
163
164    fPadSeekMode = kPadSeekOff;
165    fMultiWinExpand = kFALSE;
166    fOwnCanvasExpand = kTRUE;
167    fOldPad = 0;
168    fEditor = 0;
169
170    gVirtualX->GrabKey(fId, gVirtualX->KeysymToKeycode(kKey_Left),
171            kKeyControlMask, kTRUE);
172    gVirtualX->GrabKey(fId, gVirtualX->KeysymToKeycode(kKey_Right),
173            kKeyControlMask, kTRUE);
174    gVirtualX->GrabKey(fId, gVirtualX->KeysymToKeycode(kKey_Tab),
175            kKeyControlMask, kTRUE);
176
177    fName = name ;
178    fTitle = title ? title : name;
179
180    fList = new TList;
181    fList->SetOwner();
182
183    // list of pointer to the tab canvases
184    fCanvases = new TList;
185
186    // list of ancillary canvases.
187    fExtCanvases = new TList;
188
189    fMutex = new TMutex;
190
191    //
192    // Create the layout hint for the root embedded canavses
193    //
194    fLayCanvas = new TGLayoutHints(kLHintsExpandX|kLHintsExpandY);
195    fList->Add(fLayCanvas);
196
197    SetWindowName(fTitle);
198
199    if ( gClient ) {
200        AddMenuBar();
201        AddUserFrame();
202        AddTabs();
203        AddStatusBar();
204    }
205
206    UpdateWMSizeHints();
207
208    Layout();
209    MapSubwindows();
210
211    ShowTabList(kFALSE);
212    ShowEditor(kFALSE);
213
214    Resize(GetDefaultSize());
215
216    return kTRUE;
217}
218
219//_____________________________________________________________________________
220EGViewer::~EGViewer() {
221    //
222    // Destructor
223    //
224
225    gROOT->GetListOfSpecials()->Remove(this);
226
227    // delete canvases one by one not to have interference.
228    TIter next(fExtCanvases);
229    while( TCanvas* c = (TCanvas*)next() ) 
230        c->Disconnect("Closed()",this,"RemoveCanvas()");   
231
232    fExtCanvases->Delete();
233    delete fExtCanvases;
234
235   
236    SafeDelete(fEditor);
237    delete fList;
238    delete fCanvases;
239}
240
241//______________________________________________________________________________
242void EGViewer::UpdateWMSizeHints() {
243    //
244    // Sets the WM min-max size of the window not to hide the tab list.
245    // Sometime, if it is hidden a crash may occour.
246    //
247   
248    // 10 pixles left fo the canvases
249    UInt_t minh = GetHeight()-GetTab()->GetHeight()+GetTab()->GetTabHeight()+10;
250    UInt_t minw = 200;
251
252    SetWMSizeHints(minw,minh,kMaxUShort,kMaxUShort,1,1);
253}
254
255//______________________________________________________________________________
256void EGViewer::CloseWindow() {
257    DeleteWindow();
258}
259
260//______________________________________________________________________________
261void EGViewer::Clear( Option_t* opt ) {
262    //
263    //
264    //
265   
266    RemoveTabs();
267}
268
269//______________________________________________________________________________
270void EGViewer::AddMenuBar() {
271    //
272    // File Menu
273    //
274
275    //
276    // Horizontal frame
277    //
278    TGLayoutHints *lay = new TGLayoutHints( kLHintsNormal|kLHintsExpandX,0,0,0,0 );
279    fList->Add(lay);
280
281    fMenuFrame = new TGCompositeFrame(this, GetWidth() + 4, GetHeight() + 4,
282            kHorizontalFrame);
283
284    fList->Add(fMenuFrame);
285
286    fFileSaveMenu = new TGPopupMenu(gClient->GetRoot());
287
288    fFileSaveMenu->AddEntry(Form("%s.ps",GetName()),   kFileSaveAsPS);
289    fFileSaveMenu->AddEntry(Form("%s.pdf",GetName()),   kFileSaveAsPDF);
290    fFileSaveMenu->AddEntry(Form("%s.root",GetName()),   kFileSaveAsRoot);
291    fFileSaveMenu->Associate(this);
292
293    fFileMenu = new TGPopupMenu(gClient->GetRoot());
294
295    fFileMenu->AddEntry("Save &As...",   kFileSaveAs);
296    fFileMenu->AddPopup("&Save", fFileSaveMenu);
297    fFileMenu->AddSeparator();
298    fFileMenu->AddEntry("C&lose viewer", kFileCloseViewer);
299    fFileMenu->AddEntry("E&xit",         kFileExit);
300    fFileMenu->Associate(this);
301
302
303    fViewMenu = new TGPopupMenu(gClient->GetRoot());
304    fViewMenu->AddEntry("&Editor",kViewEditor);
305    fViewMenu->AddEntry("&Tab list",kViewCombo);
306    fViewMenu->AddSeparator();
307    fViewMenu->AddEntry("&X3D",      kViewX3D);
308    fViewMenu->AddEntry("&OpenGL",   kViewOpenGL);
309    fViewMenu->Associate(this);
310
311    fTabMenu = new TGPopupMenu(gClient->GetRoot());
312    fTabMenu->AddEntry("&Expand",               kPadExpandOnce);
313    fTabMenu->AddEntry("&Loop Expand",          kPadExpandLoop);
314    fTabMenu->AddSeparator();
315    fTabMenu->AddEntry("Use Multiple &Windows", kPadUseMultiWin);
316    fTabMenu->AddEntry("Private &Canvases",     kPadOwnCanvas);
317    fTabMenu->Associate(this);
318   
319    fOptionMenu = new TGPopupMenu(gClient->GetRoot());
320    fOptionMenu->AddEntry("&Statistics",          kOptionStatistics);
321    fOptionMenu->AddEntry("Histogram &Title",     kOptionHistTitle);
322    fOptionMenu->AddEntry("&Fit Parameters",      kOptionFitParams);
323    fOptionMenu->AddEntry("Can Edit &Histograms", kOptionCanEdit);
324    fOptionMenu->Associate(this);
325
326    if (gStyle->GetOptStat())
327        fOptionMenu->CheckEntry(kOptionStatistics);
328    if (gStyle->GetOptTitle())
329        fOptionMenu->CheckEntry(kOptionHistTitle);
330    if (gStyle->GetOptFit())
331        fOptionMenu->CheckEntry(kOptionFitParams);
332    if (gROOT->GetEditHistograms())
333        fOptionMenu->CheckEntry(kOptionCanEdit); 
334
335    fSizePaperMenu = new TGPopupMenu(gClient->GetRoot());
336    fSizePaperMenu->AddEntry("&A4 (640x497)",kSizeA4);
337
338    fSizeMenu = new TGPopupMenu(gClient->GetRoot());
339    fSizeMenu->AddEntry("Resize to &640x480",kSize640);
340    fSizeMenu->AddEntry("Resize to &800x600",kSize800);
341    fSizeMenu->AddEntry("Resize to &960x720",kSize960);
342    fSizeMenu->AddEntry("Resize to &1024x768",kSize1024);
343    fSizeMenu->AddEntry("Resize to 1&280x1024",kSize1280);
344    fSizeMenu->AddPopup("Resize &To...",fSizePaperMenu);
345    fSizeMenu->Associate(this);
346
347    //
348    // Menu Bar
349    //
350    TGLayoutHints *layitem = new TGLayoutHints(kLHintsNormal, 0, 4, 0, 0);
351    fList->Add(layitem);
352
353
354    fMenuBar = new TGMenuBar(fMenuFrame, 1, 1, kHorizontalFrame);
355    fMenuBar->AddPopup("&File", fFileMenu, layitem);
356    //    fMenuBar->AddPopup("Lo&g",  logmenu,  layitem);
357    fMenuBar->AddPopup("&View", fViewMenu, layitem);
358    fMenuBar->AddPopup("&Tab",  fTabMenu,  layitem);
359    fMenuBar->AddPopup("&Options",  fOptionMenu,  layitem);
360    fMenuBar->AddPopup("&Resize", fSizeMenu, layitem);
361    //    fMenuBar->AddPopup("&Loop", floopMenu, layitem);
362    // fMenuBar->BindKeys(this);
363    fMenuFrame->AddFrame(fMenuBar);
364
365    //
366    // Add everything to autodel list
367    //
368    fList->Add(fFileMenu);
369    fList->Add(fFileSaveMenu);
370    fList->Add(fViewMenu);
371    fList->Add(fTabMenu);
372    fList->Add(fSizeMenu);
373    fList->Add(fSizePaperMenu);
374
375
376    //
377    // Add the tab Combo box
378    //
379    TGLayoutHints* laycombo = new TGLayoutHints(kLHintsTop | kLHintsRight, 0, 4, 2, 2);
380    fList->Add(laycombo);
381    fTabCombo = new TGComboBox(fMenuFrame, kW_COMBO_TABS);
382    fTabCombo->Associate(this);
383    fMenuFrame->AddFrame(fTabCombo, laycombo);
384
385    fList->Add(fTabCombo); 
386
387    fTabCombo->Resize(150,20);
388
389
390    AddFrame(fMenuFrame,lay);
391
392    //
393    // Add a 3d line at the bottom of the bar
394    //
395
396    TGLayoutHints *lay3D = new TGLayoutHints(kLHintsExpandX);
397    fList->Add(lay3D);
398
399    fLine = new TGHorizontal3DLine(this);
400    fList->Add(fLine);
401
402    AddFrame(fLine, lay3D);
403    SetMultiWinExpand(fMultiWinExpand);
404    SetOwnCanvasExpand(fOwnCanvasExpand);
405}
406
407
408//______________________________________________________________________________
409void EGViewer::AddUserFrame() {
410    //
411    // Adds an empty TGCompositeFrame which might be filled by the user
412    //
413    TGLayoutHints *lay = new TGLayoutHints(kLHintsExpandX);
414    fList->Add(lay);
415
416    fUserFrame = new TGVerticalFrame(this, 1, 1);
417    AddFrame(fUserFrame, lay);
418    fList->Add(fUserFrame);
419}
420
421
422//______________________________________________________________________________
423void EGViewer::AddTabs() {
424    //
425    // Add Tabs frame
426    //
427
428    TGLayoutHints *lay = new TGLayoutHints( kLHintsNormal|kLHintsExpandX|kLHintsExpandY, 0, 0, 0, 0 );
429    fList->Add(lay);
430    fMainFrame = new TGHorizontalFrame(this, GetWidth() + 4, GetHeight() + 4);
431    fList->Add(fMainFrame);
432   
433
434    TGLayoutHints *laylistframe = new TGLayoutHints( kLHintsNormal|kLHintsExpandY, 0, 0, 0, 0 );
435    fList->Add(laylistframe);
436    fTabListFrame = new TGVerticalFrame(fMainFrame, 125, fMainFrame->GetHeight()+4, kFixedWidth); 
437    fList->Add(fTabListFrame);
438
439    TGLayoutHints* laylbl = new TGLayoutHints(kLHintsLeft, 5, 2, 2, 2);
440    fList->Add(laylbl);
441    TGLabel* label = new TGLabel(fTabListFrame,"Tabs");
442    fList->Add(label);
443    fTabListFrame->AddFrame(label,laylbl);
444   
445    fTabList = new TGListBox(fTabListFrame,kW_LIST_TABS);
446    fTabList->Associate(this);
447    fList->Add(fTabList);
448
449//    fTabList->Resize(125,20);
450   
451    TGLayoutHints *laylist = new TGLayoutHints(kLHintsNormal|kLHintsExpandY|kLHintsExpandX, 2, 1, 2, 2);
452    fList->Add(laylist);
453   
454    fTabListFrame->AddFrame(fTabList, laylist);
455    fMainFrame->AddFrame(fTabListFrame, laylistframe);
456   
457    fTab = new TGTab(fMainFrame, fMainFrame->GetWidth()+4,fMainFrame->GetHeight()+4);
458    fTab->Associate(this);
459
460    // Add fTab to Frame
461    TGLayoutHints *laytabs = new TGLayoutHints(kLHintsNormal|kLHintsExpandX|kLHintsExpandY, 1, 2, 2, 2);
462    fMainFrame->AddFrame(fTab, laytabs);
463
464    TGLayoutHints *layeditframe = new TGLayoutHints( kLHintsNormal|kLHintsExpandY, 0, 0, 0, 0 );
465    fList->Add(layeditframe);
466    fEditorFrame = new TGCompositeFrame(fMainFrame, 175, fMainFrame->GetHeight()+4, kFixedWidth); 
467    fList->Add(fEditorFrame);
468   
469    fMainFrame->AddFrame(fEditorFrame, layeditframe);
470
471    fList->Add(fTab);
472    fList->Add(laytabs);
473   
474    AddFrame(fMainFrame, lay);
475
476
477
478}
479
480//______________________________________________________________________________
481void EGViewer::AddStatusBar() {
482    //
483    // Add the status bar
484    //
485   
486    //
487    // Horizontal frame
488    //
489    TGLayoutHints *lay = new TGLayoutHints( kLHintsNormal|kLHintsExpandX,0,0,0,0 );
490
491    fStatusFrame = new TGCompositeFrame(this, GetWidth() + 4, GetHeight() + 4,
492            kHorizontalFrame);
493
494    fList->Add(fStatusFrame);
495    fList->Add(lay);
496
497    TGLayoutHints *layprog = new TGLayoutHints( kLHintsNormal,3,2,0,2 );
498   
499    fProgressBar = new TGHProgressBar(fStatusFrame,150,18);
500    fProgressBar->SetBarColor("lightblue");
501    fProgressBar->ShowPosition();
502    fProgressBar->SetFillType(TGProgressBar::kSolidFill);
503    fStatusFrame->AddFrame(fProgressBar, layprog);
504
505
506    fList->Add(layprog);
507    fList->Add(fProgressBar);
508
509    fStatusBar = new TGStatusBar(fStatusFrame, 1, 1);
510
511    Int_t parts[] = { 28,10, 62 }; 
512    fStatusBar->SetParts(parts, 3);
513
514    TGLayoutHints *layb = new TGLayoutHints(kLHintsNormal|kLHintsExpandX, 2, 3, 0, 2);
515    fStatusFrame->AddFrame(fStatusBar, layb);
516
517    fList->Add(fStatusBar);
518    fList->Add(layb);
519
520    AddFrame(fStatusFrame, lay);
521
522}
523
524
525//______________________________________________________________________________
526void EGViewer::CreateEditor() {
527    //
528    //
529    //
530
531    if (TVirtualPadEditor::GetPadEditor(kFALSE) != 0) {
532        TVirtualPadEditor::HideEditor();
533    }
534    fEditorFrame->SetEditable();
535
536    // next two lines are related to the old editor
537    fEditor = TVirtualPadEditor::LoadEditor();
538    fEditor->SetGlobal(kFALSE);
539    fEditorFrame->SetEditable(kEditDisable);
540}
541
542//______________________________________________________________________________
543void EGViewer::ShowEditor( Bool_t show ) {
544    //
545    //
546    //
547
548    UInt_t w = GetWidth();
549    UInt_t e = fEditorFrame->GetWidth();
550    UInt_t h = GetHeight();
551
552    if (show) {
553        if ( !fCanvases->GetEntries() ) return;
554        if (!fEditor) CreateEditor();
555
556        fViewMenu->CheckEntry(kViewEditor);
557        fEditor->Show();
558        fMainFrame->ShowFrame(fEditorFrame);
559
560        w += e;
561
562    } else {
563        fViewMenu->UnCheckEntry(kViewEditor);
564        if ( fEditor) fEditor->Hide();
565        fMainFrame->HideFrame(fEditorFrame);
566
567        //
568        // If the editor does not exist, do not resize the window.
569        // Useful in the constructor of child classes.
570        w -= e;
571    }
572
573    Resize(w,h);
574}
575
576//______________________________________________________________________________
577void EGViewer::ToggleEditor() {
578    //
579    //
580    //
581   
582    ShowEditor(!fViewMenu->IsEntryChecked(kViewEditor));
583}
584
585//______________________________________________________________________________
586TGCompositeFrame* EGViewer::AddEmptyTab( const char* title  ) {
587    //
588    //
589    //
590
591    TGCompositeFrame* f = GetTab()->AddTab(title);
592
593    //
594    // Combo entries handling
595    //
596    fTabCombo->AddEntry(title, fTabCombo->GetListBox()->GetNumberOfEntries());
597    fTabCombo->Select(GetTab()->GetCurrent());
598    fTabList->AddEntry(title, fTabList->GetNumberOfEntries());
599    fTabList->Select(GetTab()->GetCurrent());
600    fTabList->Layout();
601    fTabList->MapSubwindows();
602
603    GetTab()->Layout();          // seems to layout the TGCompositeFrame
604    GetTab()->MapSubwindows();   // maps the TGCompositeFrame
605
606    // display new tab in the main frame
607    // FIXME: Workaround because TApplication::Run is not thread safe in
608    //        respect of ProcessEvents
609    if ( !TThread::Self() )
610        gClient->ProcessEventsFor(GetTab());
611
612    return f;
613}
614
615//______________________________________________________________________________
616TCanvas* EGViewer::AddTab( const char* name, const char* title  ) {
617    //
618    // Add new tab
619    //
620
621    if ( gROOT->IsBatch() ) {
622        TCanvas* c = new TCanvas( name, title ? title : name );
623        fList->Add(c);
624        fCanvases->Add(c);
625        return c;
626       
627    }
628   
629
630    TVirtualPad* padsave = gPad;
631
632    TGCompositeFrame *f = AddEmptyTab(title ? title: name );
633
634    // create root embedded canvas and add it to the tab
635    TRootEmbeddedCanvas *ec = new TRootEmbeddedCanvas(name, f, f->GetWidth(), f->GetHeight(), 0);
636    f->AddFrame(ec, fLayCanvas);
637    fList->Add(ec);
638
639    TCanvas *c = ec->GetCanvas();
640    c->SetBorderMode(0);
641    c->SetTitle(title ? title : name );
642
643    if (TestBit(kNoContextMenu))
644        c->SetBit(kNoContextMenu);
645
646    c->Connect("ProcessedEvent(Int_t,Int_t,Int_t,TObject*)",
647            "EGViewer",this,
648            "EventInfo(Int_t,Int_t,Int_t,TObject*)");
649
650
651    // layout and map new tab
652    GetTab()->Layout();          // seems to layout the TGCompositeFrame
653    GetTab()->MapSubwindows();   // maps the TGCompositeFrame
654    GetTab()->Layout();          // layout the embedded canvas in the frame
655    fTabListFrame->Layout();
656
657
658    // display new tab in the main frame
659    // FIXME: Workaround because TApplication::Run is not thread safe in
660    //        respect of ProcessEvents
661    if ( !TThread::Self() )
662        gClient->ProcessEventsFor(GetTab());
663
664    fCanvases->Add(c);
665
666    gPad = padsave;
667
668    return c;
669
670}
671
672//______________________________________________________________________________
673TCanvas* EGViewer::FindAddTab( const char* name, const char* title  ) {
674    //
675    // Add new tab if it's not already in the list
676    //
677
678    TCanvas* c = FindCanvas(name);
679
680    if (!c) c = AddTab(name, title);
681    else c->SetTitle(title);
682
683    return c;
684}
685
686//______________________________________________________________________________
687void EGViewer::RemoveTab(Int_t i ) {
688    //
689    // Remove the i-th Tab
690    //
691   
692    TGCompositeFrame *f = GetTab()->GetTabContainer(i);
693    if (!f)
694        return;
695   
696    TRootEmbeddedCanvas *ec = GetEmbeddedCanvas(f);
697    if (ec) {
698
699        TCanvas *c = ec->GetCanvas();
700        if (c) {
701            fCanvases->Remove(c);
702            if ( fEditor) {
703                TGedEditor* ged = dynamic_cast<TGedEditor*>(fEditor);
704                (void) ged;
705
706                if ( !fCanvases->GetEntries() ) {
707#ifdef DEBUG
708                    cout << "Last canvas, close editor" << endl;
709#endif /* DEBUG */
710                    ShowEditor(kFALSE);
711                    SafeDelete(fEditor);
712//                } else {
713//                    ged->DisconnectEditors(c);
714                }
715            }
716           
717        }
718
719        f->RemoveFrame(ec);
720
721        delete fList->Remove(ec);
722    }
723
724    GetTab()->RemoveTab(i);
725   
726    //
727    // Combo entries handling
728    //
729    fTabCombo->RemoveEntry(i);
730    for (int j=i; j<fTabCombo->GetListBox()->GetNumberOfEntries(); j++)
731    {
732        TGTextLBEntry *entry = (TGTextLBEntry *)fTabCombo->GetListBox()->Select(j+1, kFALSE);
733        fTabCombo->AddEntry(entry->GetText()->GetString(), j);
734        fTabCombo->RemoveEntry(j+1);
735    }
736    fTabList->RemoveEntry(i);
737    for (int j=i; j<fTabList->GetNumberOfEntries(); j++)
738    {
739        TGTextLBEntry *entry = (TGTextLBEntry *)fTabList->Select(j+1, kFALSE);
740        fTabList->AddEntry(entry->GetText()->GetString(), j);
741        fTabList->RemoveEntry(j+1);
742    }
743    //
744    SelectTab(0);
745
746    fTabList->Layout();
747    fTabList->MapSubwindows();
748
749    GetTab()->Layout();          // seems to layout the TGCompositeFrame
750    GetTab()->MapSubwindows();   // maps the TGCompositeFrame
751    GetTab()->Layout();          // layout the embedded canvas in the frame
752    fTabListFrame->Layout();
753
754    // display new tab in the main frame
755    // FIXME: Workaround because TApplication::Run is not thread safe in
756    //        respect of ProcessEvents
757    if ( !TThread::Self() )
758        gClient->ProcessEventsFor(GetTab());
759}
760
761//______________________________________________________________________________
762void EGViewer::SelectTab(Int_t i) const {
763
764    GetTab()->SetTab(i);
765    fTabCombo->Select(i);
766    fTabList->Select(i);
767
768    if ( TCanvas* c = FindCanvasByTab(i) ) { 
769        c->cd(); 
770        if ( fEditor ) {
771            TGedEditor* ged = dynamic_cast<TGedEditor*>(fEditor);
772            ged->SetCanvas(c);
773#ifdef DEBUG
774            cout << "Select tab " << i << " canvas  " << c << endl;
775#endif /* DEBUG */
776        }
777    }
778
779    // display new tab in the main frame
780    // FIXME: Workaround because TApplication::Run is not thread safe in
781    //        respect of ProcessEvents
782    if ( !TThread::Self() )
783        gClient->ProcessEventsFor(GetTab());
784}
785
786//______________________________________________________________________________
787Int_t EGViewer::NextTab() const {
788    //
789    // Switch to the next tab
790    //
791   
792    if ( !GetTab()->GetNumberOfTabs() )
793        return -1;
794           
795    Int_t n = GetTab()->GetCurrent();
796
797    if ( ++n == GetTab()->GetNumberOfTabs() ) n=0;
798    SelectTab(n);
799//    GetTab()->SetTab(n);
800//    fTabCombo->Select(n);
801
802    return n;
803}
804
805//______________________________________________________________________________
806Int_t EGViewer::PrevTab() const {
807    //
808    // Switch to the next tab
809    //
810   
811    if ( !GetTab()->GetNumberOfTabs() )
812        return -1;
813           
814    Int_t n = GetTab()->GetCurrent();
815
816    if ( --n == -1 ) n =GetTab()->GetNumberOfTabs()-1;
817    SelectTab(n);
818
819    return n;
820}
821
822//______________________________________________________________________________
823void EGViewer::ShowTabList( Bool_t show) {
824    //
825    // Shows Tab Combo box
826    //
827
828    UInt_t w = GetWidth();
829    UInt_t e = fTabListFrame->GetWidth();
830    UInt_t h = GetHeight();
831
832    if ( show ) {
833        fViewMenu->CheckEntry( kViewCombo );
834        fMenuFrame->ShowFrame(fTabCombo);
835        fMainFrame->ShowFrame(fTabListFrame);
836
837        w += e;
838    } else {
839        fViewMenu->UnCheckEntry( kViewCombo );
840        fMenuFrame->HideFrame(fTabCombo);
841        fMainFrame->HideFrame(fTabListFrame);
842
843        w -= e;
844    }
845
846    Resize(w,h);
847}
848
849//______________________________________________________________________________
850void EGViewer::ToggleTabList() {
851    //
852    // Toggles Tab Combo box.
853    //
854
855    ShowTabList( !fViewMenu->IsEntryChecked( kViewCombo ) );
856}
857
858//______________________________________________________________________________
859Bool_t EGViewer::HandleEvent(Event_t* event) {
860
861        return TGFrame::HandleEvent(event);
862
863}
864
865//______________________________________________________________________________
866Bool_t EGViewer::HandleKey(Event_t* event) {
867    //
868    // Handle keybord commands
869    //
870    //
871
872#ifdef DEBUG
873    Printf("Event");
874#endif
875    if ((event->fType == kGKeyPress) && (event->fState & kKeyControlMask)) {
876        UInt_t keysym;
877        char str[2];
878
879        gVirtualX->LookupString(event, str, sizeof(str), keysym);
880
881        switch ( keysym ) {
882            case kKey_Tab:
883            case kKey_Right:
884                NextTab();
885                return kTRUE;
886            case kKey_Left:
887                PrevTab();
888                return kTRUE;
889        }
890    }
891
892    return TGMainFrame::HandleKey(event);
893}
894
895//______________________________________________________________________________
896Bool_t EGViewer::ProcessMessage(Long_t msg, Long_t mp1, Long_t mp2 ) {
897    //
898    // Process the messages from the GUI
899    //
900
901    // Can be found in WidgetMessageTypes.h
902#ifdef DEBUG
903    //////cout << "Msg: " << GET_MSG(msg) << " Submsg:" << GET_SUBMSG(msg);
904    //cout << " Mp1=" << mp1 << " Mp2=" << mp2 << endl;
905#endif
906    switch (GET_MSG(msg))
907    {
908        case kC_COMMAND:  // 1
909            return ProcessMessageCommand(GET_SUBMSG(msg), mp1, mp2);
910
911        case kC_TEXTVIEW: // 9
912            return ProcessMessageTextview(GET_SUBMSG(msg), mp1, mp2);
913
914        case kC_USER:     // 1001
915            return ProcessMessageUser(GET_SUBMSG(msg), mp1, mp2);
916    }
917#ifdef DEBUG
918    //cout << "Msg: " << GET_MSG(msg) << " Submsg:" << GET_SUBMSG(msg);
919    //cout << " Mp1=" << mp1 << " Mp2=" << mp2 << endl;
920#endif
921
922    return kTRUE;
923}
924
925//______________________________________________________________________________
926Bool_t EGViewer::ProcessMessageCommand(Long_t submsg, Long_t mp1, Long_t mp2) {
927    //
928    //
929    //
930    switch (submsg) {
931        case kCM_MENU: // 1
932            return ProcessMessageCommandMenu(mp1); // mp2=userdata
933        case kCM_TAB:  // 8
934            //            UpdateTab(GetTab()->GetTabContainer(mp1));
935            //            Printf("kCM_TAB");
936            SelectTab(mp1);
937            return kTRUE;
938        case kCM_COMBOBOX: // 7
939            if (mp1==kW_COMBO_TABS)
940                SelectTab(mp2);
941            return kTRUE;
942        case kCM_LISTBOX: // 7
943            if (mp1==kW_LIST_TABS)
944                SelectTab(mp2);
945            return kTRUE;
946    }
947
948    return kTRUE;
949}
950
951//______________________________________________________________________________
952Bool_t EGViewer::ProcessMessageCommandMenu(Long_t mp1) {
953    //
954    // Menu messages
955    //
956
957    switch (mp1) {
958        case kFileSaveAs:
959            {
960                TGFileInfo fi;
961                fi.fFileTypes   = gSaveAsTypes;
962                fi.fFileTypeIdx = 0;
963                fi.fOverwrite   = kFALSE;
964                new TGFileDialog(gClient->GetRoot(), 0, kFDSave, &fi);
965
966                if ( fi.fFilename ) {
967                    TString name = fi.fFilename;
968
969                    if ( name.EndsWith(".ps")) SaveAsPS(name);
970                    if ( name.EndsWith(".pdf")) SaveAsPDF(name);
971                    if ( name.EndsWith(".root")) SaveAsRoot(name);
972                }
973            }
974            break;
975        case kFileSaveAsPS:
976            SaveAsPS();
977            break;
978        case kFileSaveAsPDF:
979            SaveAsPDF();
980            break;
981        case kFileSaveAsRoot:
982            SaveAsRoot();
983            break;
984        case kFileCloseViewer:
985            SendCloseMessage();
986            break;
987        case kFileExit:
988            gApplication->Terminate(0);
989            break;
990
991        case kViewEditor:
992            ToggleEditor();
993            break;
994        case kViewCombo:
995            ToggleTabList();
996            break;
997        case kViewX3D:
998            gPad->GetViewer3D("x3d");
999            break;
1000        case kViewOpenGL:
1001            gPad->GetViewer3D("ogl");
1002            break;
1003
1004            //
1005            //
1006        case kPadExpandOnce:
1007            SetPadSeekMode( kPadSeekOnce );
1008            break;
1009        case kPadExpandLoop:
1010            SetPadSeekMode( kPadSeekLoop );
1011            break;
1012
1013        case kPadUseMultiWin:
1014            ToggleMultiWinExpand();
1015            break;
1016
1017        case kPadOwnCanvas:
1018            ToggleOwnCanvasExpand();
1019            break;
1020
1021        case kOptionStatistics:
1022            if (gStyle->GetOptStat()) {
1023                gStyle->SetOptStat(0);
1024                delete gPad->FindObject("stats");
1025                fOptionMenu->UnCheckEntry(kOptionStatistics);
1026            } else {
1027                gStyle->SetOptStat(1);
1028                fOptionMenu->CheckEntry(kOptionStatistics);
1029            }
1030            gPad->Modified();
1031            gPad->Update();
1032            break;
1033        case kOptionHistTitle:
1034            if (gStyle->GetOptTitle()) {
1035                gStyle->SetOptTitle(0);
1036                delete gPad->FindObject("title");
1037                fOptionMenu->UnCheckEntry(kOptionHistTitle);
1038            } else {
1039                gStyle->SetOptTitle(1);
1040                fOptionMenu->CheckEntry(kOptionHistTitle);
1041            }
1042            gPad->Modified();
1043            gPad->Update();
1044            break;
1045        case kOptionFitParams:
1046            if (gStyle->GetOptFit()) {
1047                gStyle->SetOptFit(0);
1048                fOptionMenu->UnCheckEntry(kOptionFitParams);
1049            } else {
1050                gStyle->SetOptFit(1);
1051                fOptionMenu->CheckEntry(kOptionFitParams);
1052            }
1053            gPad->Modified();
1054            gPad->Update();
1055            break;
1056        case kOptionCanEdit:
1057            if (gROOT->GetEditHistograms()) {
1058                gROOT->SetEditHistograms(kFALSE);
1059                fOptionMenu->UnCheckEntry(kOptionCanEdit);
1060            } else {
1061                gROOT->SetEditHistograms(kTRUE);
1062                fOptionMenu->CheckEntry(kOptionCanEdit);
1063            }
1064            break;
1065        case kSizeA4:
1066            Resize(640,A4Height(640));
1067            break;
1068        case kSize640:
1069            Resize(640,480);
1070            break;
1071        case kSize800:
1072            Resize(800,600);
1073            break;
1074        case kSize960:
1075            Resize(960,720);
1076            break;
1077        case kSize1024:
1078            Resize(1024,768);
1079            break;
1080        case kSize1280:
1081            Resize(1280,1024);
1082            break;
1083
1084    }
1085    return kTRUE;
1086}
1087
1088//______________________________________________________________________________
1089Bool_t EGViewer::ProcessMessageTextview(Long_t submsg, Long_t mp1, Long_t mp2) {
1090    return kTRUE;
1091}
1092
1093//______________________________________________________________________________
1094Bool_t EGViewer::ProcessMessageUser(Long_t submsg, Long_t mp1, Long_t mp2) {
1095    return kTRUE;
1096}
1097
1098//______________________________________________________________________________
1099TRootEmbeddedCanvas *EGViewer::GetEmbeddedCanvas(TGCompositeFrame *cf) const {
1100    //
1101    // Takes a TGCompositeFrame as argument. Searches for the first
1102    // TRootEmbeddedCanvas which is contained by it and returns a pointer
1103    // to the corresponding TCanvas. If it isn't found NULL is returned.
1104    //
1105
1106    TIter next(cf->GetList());
1107
1108    TGFrameElement *f;
1109    while ((f=(TGFrameElement*)next()))
1110        if (f->fFrame->InheritsFrom(TRootEmbeddedCanvas::Class()))
1111            return (TRootEmbeddedCanvas*)f->fFrame;
1112
1113    return NULL;
1114}
1115
1116
1117//______________________________________________________________________________
1118TCanvas* EGViewer::CurrentCanvas() const {
1119    //
1120    // Returns the canvas in the selected tab, otherwise 0
1121    //
1122    return FindCanvasByTab(GetTab()->GetCurrent());
1123
1124}
1125
1126//______________________________________________________________________________
1127TCanvas* EGViewer::FindCanvasByTab(int i) const {
1128    //
1129    // Returns GetCanvas of the i-th Tab.
1130    //
1131
1132    //    if (gROOT->IsBatch())
1133    //        return (TCanvas*)fBatch->At(i-1);
1134
1135    if (i<0 || i>=GetTab()->GetNumberOfTabs())
1136    {
1137        return NULL;
1138    }
1139
1140    return FindCanvasByTab(GetTab()->GetTabContainer(i));
1141}
1142
1143//______________________________________________________________________________
1144TCanvas* EGViewer::FindCanvasByTab(TGCompositeFrame *f) const {
1145    //
1146    // Takes a TGCompositeFrame as argument. Searches for the first
1147    // TRootEmbeddedCanvas which is contained by it and returns a pointer
1148    // to the corresponding TCanvas. If it isn't found NULL is returned.
1149    //
1150
1151    TRootEmbeddedCanvas *ec = GetEmbeddedCanvas(f);
1152    return ec ? ec->GetCanvas() : NULL;
1153}
1154
1155//______________________________________________________________________________
1156TCanvas* EGViewer::FindCanvas(const char* name) const {
1157
1158    //if (gROOT->IsBatch())
1159    //    return (TCanvas*)fBatch->FindObject(name);
1160/*
1161    TGFrameElement *f;
1162    TIter next(GetTab()->GetList());
1163    while ((f=(TGFrameElement*)next()))
1164    {
1165        TObject *frame = f->fFrame;
1166        if (!frame->InheritsFrom(TGTabElement::Class()))
1167            continue;
1168
1169        TGTabElement *tab = (TGTabElement*)frame;
1170        if (tab->GetString()==name)
1171            break;
1172    }
1173
1174    // Search for the next TGCompositeFrame in the list
1175    while ((f=(TGFrameElement*)next()))
1176    {
1177        Printf("%s",f->GetName());
1178        TObject *frame = f->fFrame;
1179        if (frame->InheritsFrom(TGCompositeFrame::Class()))
1180            return FindCanvasByTab((TGCompositeFrame*)frame);
1181    }
1182
1183    return NULL;
1184    */
1185
1186    return (TCanvas*)fCanvases->FindObject(name);
1187}
1188
1189//______________________________________________________________________________
1190void EGViewer::RemoveTab( const char* name ) {
1191    //
1192    // Find and remove the tab with name
1193    //
1194
1195    Int_t count(0);
1196   
1197    TGFrameElement *f;
1198    TIter next(GetTab()->GetList());
1199    while ((f=(TGFrameElement*)next()))
1200    {
1201        TGTabElement *tab = dynamic_cast<TGTabElement*>(f->fFrame);
1202        if ( tab ) {
1203            if ( (*tab->GetText()) == name ) break;
1204            count++;
1205        }
1206       
1207    }
1208
1209    if ( count == GetTab()->GetNumberOfTabs()) return;
1210
1211    RemoveTab(count);
1212   
1213}
1214
1215//______________________________________________________________________________
1216void EGViewer::RemoveTabs() {
1217    //
1218    // Find the tab with name
1219    //
1220
1221    while(GetTab()->GetNumberOfTabs())
1222        RemoveTab(0);
1223}
1224
1225//______________________________________________________________________________
1226void EGViewer::SetStatusText(const char *txt, Int_t partidx) {
1227    //
1228    // Set text in status bar.
1229    //
1230
1231    fStatusBar->SetText(txt, partidx);
1232   
1233    if ( !TThread::Self() )
1234        gClient->ProcessEventsFor(fStatusBar);
1235}
1236
1237//______________________________________________________________________________
1238void EGViewer::SetStatusText(const char *txt, Int_t partidx) const {
1239    //
1240    // Const version of SetStatusText
1241    //
1242
1243    ((EGViewer*)this)->SetStatusText(txt,partidx);
1244}
1245//______________________________________________________________________________
1246void EGViewer::UpdateTab(TGCompositeFrame *f) {
1247    //
1248    // Update a canvas in a tab, takes the corresponding TGCompositeFrame
1249    // as an argument. This is necessary, because not all functions
1250    // changing the contents of a canvas or pad can call SetModified()
1251    // for the corresponding tab. If this is not called correctly the
1252    // tab won't be updated calling TCanvas::Update(). So we simply
1253    // redraw it by our own (instead we could recursively call
1254    // TPad::Modified() for everything contained by the TCanvas and
1255    // call TCanvas::Update() afterwards)
1256    //
1257
1258    if (!f)
1259        return;
1260
1261    TCanvas *c=FindCanvasByTab(f);
1262    if (!c)
1263        return;
1264
1265    //
1266    // If we are in a multithreaded environment (gThreadXAR) we
1267    // have to make sure, that thus function is called from
1268    // the main thread.
1269    //
1270    if (gThreadXAR)
1271    {
1272        // Tell the X-Requester how to call this method
1273        TString str = Form("%lu", (ULong_t)f);
1274
1275        TMethodCall call(IsA(), "UpdateTab", "NULL");
1276        void *arr[4] = { NULL, &call, this, (void*)(const char*)str };
1277
1278        // If this is not the main thread return
1279        if (((*gThreadXAR)("METH", 4, arr, NULL)))
1280            return;
1281    }
1282
1283    //
1284    // Secure calls to update the tabs against itself, at least
1285    // c->Paint() or c->Flush() may crash X (bad drawable).
1286    // This makes sure, that a X call is not interuppted by
1287    // another X-call which was started from an gui interrrupt
1288    // in the same thread
1289    //
1290    if (fMutex->TryLock()) {
1291        return;
1292    }
1293
1294    if (!c->IsBatch())
1295        c->FeedbackMode(kFALSE);  // Goto double buffer mode
1296
1297    //
1298    // Doing this ourself gives us the possibility to repaint
1299    // the canvas in any case (Paint() instead of PaintModified())
1300    //
1301    c->Paint();                   // Repaint all pads
1302    c->Flush();                   // Copy all pad pixmaps to the screen
1303
1304    fMutex->UnLock();
1305}
1306
1307//______________________________________________________________________________
1308Bool_t EGViewer::CloneToCanvas(TVirtualPad* pad) {
1309    // Clones the pad to a new canvas. If fUseMultiPad is true, a new
1310    // canvas with a proper name is created for every pad, otherwise a
1311    // standard canvas is used
1312    //
1313
1314    if (!pad) return kFALSE;
1315
1316    //
1317    // Create and Unique name for the Pad
1318    //
1319    TString cname;
1320    if ( UseMultiWinExpand() ) {
1321        cname = "c_";
1322        cname+=pad->GetName();
1323        cname+="_expanded";
1324    } else 
1325        cname ="c_padexpand";
1326   
1327    TCanvas *nc;
1328    if ( fOwnCanvasExpand ) 
1329        nc = (TCanvas*)fExtCanvases->FindObject(cname);
1330    else 
1331        nc = (TCanvas*)gROOT->GetListOfCanvases()->FindObject(cname);
1332
1333    if (!nc) { 
1334        nc = new TCanvas(cname,"");
1335        if ( fOwnCanvasExpand ) {
1336            gROOT->GetListOfCanvases()->Remove(nc);
1337            fExtCanvases->Add(nc);
1338            nc->Connect("Closed()","EGViewer",this,"RemoveCanvas()");
1339        }
1340    }
1341
1342    TString title = pad->GetTitle();
1343    if ( title.IsNull() ) title = pad->GetName();
1344    nc->SetTitle(title+" (expanded)");
1345
1346    nc->Clear();
1347    DrawClonePad(nc,pad);
1348
1349    nc->cd();
1350    return kTRUE;
1351
1352}
1353
1354//______________________________________________________________________________
1355void EGViewer::RemoveCanvas() {
1356    //
1357    //
1358    //
1359   
1360    TObject *obj = (TObject*)gTQSender;
1361    if ( obj->IsA() != TCanvas::Class()) {
1362        cout << "RemoveCanvas: " << obj->GetName() << endl;
1363        return;
1364    }
1365
1366    fExtCanvases->Remove(obj);
1367}
1368
1369
1370//______________________________________________________________________________
1371void EGViewer::AddPadToClean(TVirtualPad* pad) const {
1372    //
1373    //
1374    //
1375    TListIter next(pad->GetListOfPrimitives());
1376
1377    while( TObject *obj = next()) {
1378        obj->SetBit(kCanDelete|kMustCleanup);
1379
1380        if ( dynamic_cast<TVirtualPad*>(obj) )
1381            AddPadToClean((TVirtualPad*)obj);
1382    }
1383   
1384}
1385//______________________________________________________________________________
1386void EGViewer::DrawClonePad(TVirtualPad *newp, TVirtualPad *oldp) const
1387{
1388    if (!newp || !oldp) 
1389        return;
1390
1391    TVirtualPad* savepad = gPad;
1392    const Bool_t store = TH1::AddDirectoryStatus();
1393    TH1::AddDirectory(kFALSE);
1394
1395//    if ( dynamic_cast<TPad*>(newp) )
1396//        gROOT->GetListOfCleanups()->Add(newp);
1397
1398    newp->cd();
1399    newp->Range(oldp->GetUxmin(),oldp->GetUymin(),oldp->GetUxmax(),oldp->GetUymax());
1400    oldp->TAttFill::Copy(*newp);
1401    oldp->TAttLine::Copy(*newp);
1402    oldp->TAttPad::Copy(*newp);
1403
1404    newp->SetLogx(oldp->GetLogx());
1405    newp->SetLogy(oldp->GetLogy());
1406    newp->SetLogz(oldp->GetLogz());
1407    newp->SetTickx(oldp->GetTickx());
1408    newp->SetTicky(oldp->GetTicky());
1409    newp->SetGridx(oldp->GetGridx());
1410    newp->SetGridy(oldp->GetGridy());
1411    newp->SetBorderSize(oldp->GetBorderSize());
1412    newp->SetBorderMode(oldp->GetBorderMode());
1413
1414    TListIter next(oldp->GetListOfPrimitives());
1415
1416    TObject *newobj;
1417    while( TObject *obj = next()) {
1418        newobj = obj->Clone();
1419        if (!newobj) continue;
1420
1421        // the following lines are the same as in DrawClonePad
1422        // Clone also important bits (FIXME: Is this correct)
1423        newobj->SetBit(obj->TestBits(kCannotPick|kNoContextMenu));
1424
1425        // Clone also important bits (FIXME: Is this correct)
1426        newobj->SetBit(kCanDelete|kMustCleanup);
1427
1428        // FIXME: This is a workaround for the problem with the MAstroCatalog in
1429        // MHFalseSource. It doesn't harm. We'll still try to find the reason
1430        if (newobj->IsA()==TPad::Class()) {
1431            gROOT->GetListOfCleanups()->Add(newobj);
1432            AddPadToClean((TVirtualPad*)newobj);
1433        }
1434
1435        newobj->Draw(next.GetOption());
1436
1437    }
1438
1439    newp->Modified();
1440    newp->Update();
1441
1442    TH1::AddDirectory(store);
1443
1444    savepad->cd();
1445
1446}
1447
1448//______________________________________________________________________________
1449void EGViewer::EventInfo(Int_t event, Int_t px, Int_t py, TObject *selected) {
1450    //
1451    //    This function is called when the option "Event Status"
1452    //    in the canvas menu "Options" is selected.
1453    //
1454
1455    const Int_t kTMAX=256;
1456    static char atext[kTMAX];
1457
1458    TVirtualPad* savepad = gPad;
1459   
1460    TCanvas *c = (TCanvas*)gTQSender;
1461//    if (!c) return;  delete
1462
1463    if ( GetPadSeekMode() ) {
1464        TVirtualPad* pad = c->GetSelectedPad();
1465        if ( c->GetEvent() == kButton1Up ) {
1466            CloneToCanvas(pad);
1467            if ( fPadSeekMode != kPadSeekLoop ) { 
1468                SetPadSeekMode(kPadSeekOff);
1469                c->FeedbackMode(kFALSE);
1470                fOldPad = NULL;
1471                gPad=savepad;
1472                return;
1473            }
1474        }
1475
1476        if ( pad && fOldPad != pad) {
1477            gVirtualX->SetLineWidth(2);
1478            c->FeedbackMode(kTRUE);
1479//            gVirtualX->SetDrawMode(TVirtualX::kCopy);
1480
1481            if ( fOldPad ) {
1482                UInt_t px1old, py1old, px2old, py2old;
1483                px1old = fOldPad->XtoAbsPixel(fOldPad->GetX1());
1484                py1old = fOldPad->YtoAbsPixel(fOldPad->GetY1());
1485                px2old = fOldPad->XtoAbsPixel(fOldPad->GetX2());
1486                py2old = fOldPad->YtoAbsPixel(fOldPad->GetY2());
1487
1488                gVirtualX->DrawBox(px1old-2,py1old-2,px2old+2,py2old+2,TVirtualX::kHollow);
1489            }
1490
1491            UInt_t px1, py1, px2, py2;
1492            px1 = pad->XtoAbsPixel(pad->GetX1());
1493            py1 = pad->YtoAbsPixel(pad->GetY1());
1494            px2 = pad->XtoAbsPixel(pad->GetX2());
1495            py2 = pad->YtoAbsPixel(pad->GetY2());
1496            gVirtualX->DrawBox(px1-2,py1-2,px2+2,py2+2,TVirtualX::kHollow);
1497//            Printf("Box");
1498        }
1499
1500        fOldPad = pad;
1501       
1502        sprintf(atext, "Select the pad to Clone");
1503        SetStatusText(atext,2);
1504        return;
1505    }
1506   
1507    if (!selected) return;
1508
1509    gPad = c->GetSelectedPad();
1510
1511    SetStatusText(selected->GetName(),0);
1512    if (event == kKeyPress)
1513        sprintf(atext, "%c", (char) px);
1514    else
1515        sprintf(atext, "%d,%d", px, py);
1516    SetStatusText(atext,1);
1517    SetStatusText(selected->GetObjectInfo(px,py),2);
1518
1519    gPad = savepad;
1520}
1521
1522//______________________________________________________________________________
1523void EGViewer::SetPadFillColor(TVirtualPad &p, Int_t col) const {
1524    //
1525    // Set the background color in a canvas
1526    //
1527
1528    TObject *obj;
1529
1530    // See also TPad::UseCurrentStyle
1531    TIter next(p.GetListOfPrimitives());
1532    while ((obj=next()))
1533    {
1534        if (obj->InheritsFrom(TPad::Class()))
1535            SetPadFillColor(*(TPad*)obj, col);
1536        if (obj->InheritsFrom(TFrame::Class()))
1537            ((TFrame*)obj)->SetFillColor(col);
1538    }
1539
1540    p.SetFillColor(col);
1541}
1542
1543//______________________________________________________________________________
1544void EGViewer::UpdatePSHeader(const TString &name) const {
1545//
1546// Insert the following two lines into the postscript header:
1547//
1548//   %%DocumentPaperSizes: a4
1549//   %%Orientation: Landscape
1550//
1551
1552    const TString newstr("%%DocumentPaperSizes: a4\n%%Orientation: Landscape\n");
1553
1554    ifstream fin(name);
1555    ofstream fout(name+".$$$");
1556
1557    char c;
1558
1559    TString str;
1560    fin >> str >> c;                // Read "%!PS-Adobe-2.0\n"
1561    fout << str << endl << newstr;
1562
1563    // Doing it in blocks seems not to gain much for small (MB) files
1564    while (fin)
1565    {
1566        fin.read(&c, 1);
1567        fout.write(&c, 1);
1568    }
1569
1570    gSystem->Unlink(name);
1571    gSystem->Rename(name+".$$$", name);
1572}
1573
1574////______________________________________________________________________________
1575//Int_t EGViewer::SaveAsPS( const char* name ) {
1576//    //
1577//    // Save all tabs in a PS File
1578//    //
1579//   
1580//    Int_t npages = fCanvases->GetEntries();
1581//    if ( !npages ) return 0;
1582//
1583//    if ( !name ) name = GetName();
1584//   
1585//    TString psname(name);
1586//    if ( !psname.EndsWith(".ps") ) psname+=".ps";
1587//   
1588//
1589//    TVirtualPad* padsave = gPad;
1590//    TVirtualPS* pssave = gVirtualPS;
1591//
1592//    TPostScript ps(psname, 112);
1593//    ps.SetBit(TPad::kPrintingPS);
1594//    ps.PrintFast(13, "/nan {1} def ");
1595//
1596//    gVirtualPS = &ps;
1597//
1598//    // Create a list to delete the canvas clones
1599//    TList l;
1600//    l.SetOwner();
1601//
1602//    Int_t page = 0 ;
1603//
1604//    TIter next(fCanvases);
1605//
1606//    while( TCanvas* c=(TCanvas*)next()) {
1607//        ps.NewPage();
1608//
1609//        SetStatusText("Printing..",0);
1610//        SetStatusText(Form("Canvas %s on page %d",c->GetTitle(),++page),2);
1611//       
1612//        TCanvas *clone = (TCanvas*)c->Clone();
1613//        SetPadFillColor(*clone, kWhite);
1614//        l.Add(clone);
1615//
1616//        clone->SetBatch(kTRUE);
1617//        // test
1618//        clone->Size(.9*kA4Width, .9*kA4Height);
1619//
1620//        ps.Range(0.925*kA4Width,0.90*kA4Height); // A4
1621//
1622//        clone->Paint();
1623//
1624//        gPad=clone;
1625//
1626//        //
1627//        // Create some GUI elements for a page legend
1628//        //
1629//        TLine line;
1630//        //
1631//        // Print overlaying text (NDC = %)
1632//        //
1633//        ps.SetTextColor(kBlack);
1634//        ps.SetTextSize(0.025);
1635//        ps.SetTextFont(62);
1636//        ps.SetTextAlign(11); // left top
1637//        ps.TextNDC(0, 1.015, TString("  ")+clone->GetTitle());
1638//        ps.SetTextAlign(21); // cent top
1639//        ps.TextNDC(0.5, 1.015, "ESAF");
1640//        ps.SetTextAlign(31); // right top
1641//        ps.TextNDC(1, 1.015, Form("Page No.%i (%i)  ", page, npages));
1642//        line.PaintLineNDC(0, 1.01, 1, 1.01);
1643//
1644//        line.PaintLineNDC(0, -0.01, 1, -0.01);
1645//        ps.SetTextAlign(13); // left top
1646//        if ( !fTitle.IsNull() ) ps.TextNDC(0, -0.015, TString("  ")+fTitle);
1647//        ps.SetTextAlign(33); // right top
1648//        ps.TextNDC(1, -0.015, "Comment");
1649//
1650//        clone->SetBatch(kFALSE);
1651//    }
1652//    gPad=NULL;
1653//    l.Delete();
1654//    ps.Close();
1655//
1656//    UpdatePSHeader(psname);
1657//   
1658//    gVirtualPS = pssave;
1659//    if (padsave)
1660//        padsave->cd();
1661//
1662//        SetStatusText(Form("Done (%d pages)",page),0);
1663//    return page;
1664//
1665//}
1666
1667//______________________________________________________________________________
1668Int_t EGViewer::SaveAsPS( const char* name ) {
1669    //
1670    // Save all tabs in a PDF File.
1671    // FIXME: the behaviour is not well understood, use SaveAsPS instead
1672    //
1673
1674    Int_t npages = fCanvases->GetEntries();
1675    if ( !npages ) return 0;
1676
1677    if ( !name ) name = GetName();
1678
1679    TString psname(name);
1680    if ( !psname.EndsWith(".ps") ) psname+=".ps";
1681
1682
1683    TVirtualPad* padsave = gPad;
1684    TVirtualPS* pssave = gVirtualPS;
1685
1686    // change to the target canvas before the first image
1687    TCanvas* first = ((TCanvas*)fCanvases->First());
1688    first->cd();
1689
1690    TPostScript *ps = new TPostScript;
1691    ps->Range(0.9*kA4Width,0.9*kA4Height);
1692    ps->Open(psname, 112);
1693    ps->SetBit(TPad::kPrintingPS);
1694
1695    gVirtualPS = ps;
1696
1697    // Create a list to delete the canvas clones
1698    Int_t page = 0 ;
1699
1700    TIter next(fCanvases);
1701
1702    while( TCanvas* c=(TCanvas*)next() ) {
1703        // suspend writhing while arranging the canvas
1704        ps->Off();
1705        gPad = 0;
1706        c->cd();
1707       
1708        Float_t xmin = 0.03;
1709        Float_t xmax = 0.97;
1710        Float_t ymin = 0.06;
1711        Float_t ymax = 0.94;
1712
1713        SetStatusText("Printing..",0);
1714        SetStatusText(Form("Canvas %s on page %d",c->GetTitle(),++page),2);
1715
1716        TCanvas *clone = new TCanvas("", c->GetTitle());
1717        TPad* newpad = new TPad("backgroud","backgroud",xmin,ymin,xmax,ymax,kWhite,0);
1718        newpad->Draw();
1719        newpad->cd();
1720        TList* oldl = c->GetListOfPrimitives();
1721        TListIter next(oldl);
1722        while( TObject *obj = next()) {
1723            TObject* newobj = obj->Clone();
1724            newobj->SetBit(kCanDelete);
1725            newobj->Draw();
1726        }
1727        clone->Size(kA4Width, kA4Height);
1728        clone->cd();
1729        clone->Modified();
1730        clone->PaintModified();
1731
1732        SetPadFillColor(*clone, kWhite);
1733        ps->Range(0.925*kA4Width,0.925*kA4Height);
1734        ps->NewPage();
1735
1736        // write to file from now.
1737        ps->On();
1738
1739        clone->Paint();
1740
1741        gPad=clone;
1742
1743        //
1744        // Create some GUI elements for a page legend
1745        //
1746        TLine line;
1747        //
1748        // Print overlaying text (NDC = %)
1749        //
1750        ps->SetTextColor(kBlack);
1751        ps->SetTextSize(0.025);
1752        ps->SetTextFont(62);
1753        ps->SetTextAlign(13); // left top
1754        ps->TextNDC(xmin, ymax+0.05, TString("  ")+clone->GetTitle());
1755        ps->SetTextAlign(23); // cent top
1756        ps->TextNDC(0.5, ymax+0.05, "ESAF");
1757        ps->SetTextAlign(33); // right top
1758        ps->TextNDC(xmax, ymax+0.05, Form("Page No.%i (%i)  ", page, npages));
1759        line.PaintLineNDC(xmin, ymax+0.01, xmax, ymax+0.01);
1760
1761        line.PaintLineNDC(xmin, ymin-0.01, xmax, ymin-0.01);
1762        ps->SetTextAlign(11); // left top
1763        if ( !fTitle.IsNull() ) ps->TextNDC(xmin, ymin-0.04, TString("  ")+fTitle);
1764        ps->SetTextAlign(31); // right top
1765        ps->TextNDC(xmax, ymin-0.04, "Comment");
1766
1767        delete clone;
1768    }
1769       
1770    gPad=NULL;
1771    ps->Close();
1772    delete ps;
1773
1774    UpdatePSHeader(psname);
1775
1776    gVirtualPS = pssave;
1777    if (padsave)
1778        padsave->cd();
1779
1780    SetStatusText(Form("Done (%d pages)",page),0);
1781    return page;
1782
1783}
1784//______________________________________________________________________________
1785Int_t EGViewer::SaveAsPDF( const char* name ) {
1786    //
1787    // Save all tabs in a PDF File.
1788    // FIXME: the behaviour is not well understood, use SaveAsPS instead
1789    //
1790
1791    Int_t npages = fCanvases->GetEntries();
1792    if ( !npages ) return 0;
1793
1794    if ( !name ) name = GetName();
1795
1796    TString pdfname(name);
1797    if ( !pdfname.EndsWith(".pdf") ) pdfname+=".pdf";
1798
1799
1800    TVirtualPad* padsave = gPad;
1801    TVirtualPS* pssave = gVirtualPS;
1802
1803    // change to the target canvas before the first image
1804    TCanvas* first = ((TCanvas*)fCanvases->First());
1805    first->cd();
1806
1807    TPDF *pdf = new TPDF;
1808    pdf->Open(pdfname, 112);
1809    pdf->SetBit(TPad::kPrintingPS);
1810
1811    gVirtualPS = pdf;
1812
1813    // Create a list to delete the canvas clones
1814    Int_t page = 0 ;
1815
1816    TIter next(fCanvases);
1817
1818    while( TCanvas* c=(TCanvas*)next() ) {
1819        // suspend writhing while arranging the canvas
1820        pdf->Off();
1821        gPad = 0;
1822        c->cd();
1823       
1824        Float_t xmin = 0.03;
1825        Float_t xmax = 0.97;
1826        Float_t ymin = 0.06;
1827        Float_t ymax = 0.94;
1828
1829        SetStatusText("Printing..",0);
1830        SetStatusText(Form("Canvas %s on page %d",c->GetTitle(),page+1),2);
1831
1832        //______________________________________________________________________________
1833        TCanvas *clone = new TCanvas("", c->GetTitle());
1834        TPad* newpad = new TPad("backgroud","backgroud",xmin,ymin,xmax,ymax,kWhite,0);
1835        newpad->Draw();
1836        newpad->cd();
1837        TList* oldl = c->GetListOfPrimitives();
1838        TListIter next(oldl);
1839        while( TObject *obj = next()) {
1840            TObject* newobj = obj->Clone();
1841            newobj->SetBit(kCanDelete);
1842            newobj->Draw();
1843        }
1844        clone->cd();
1845
1846        SetPadFillColor(*clone, kWhite);
1847        if ( page++ ) {
1848            // use first as template
1849            pdf->NewPage();
1850        }
1851        // write to file from now.
1852        pdf->On();
1853
1854        clone->Paint();
1855
1856        gPad=clone;
1857
1858        //
1859        // Create some GUI elements for a page legend
1860        //
1861        TLine line;
1862        //
1863        // Print overlaying text (NDC = %)
1864        //
1865        pdf->SetTextColor(kBlack);
1866        pdf->SetTextSize(0.025);
1867        pdf->SetTextFont(62);
1868        pdf->SetTextAlign(13); // left top
1869        pdf->TextNDC(xmin, ymax+0.05, TString("  ")+clone->GetTitle());
1870        pdf->SetTextAlign(23); // cent top
1871        pdf->TextNDC(0.5, ymax+0.05, "ESAF");
1872        pdf->SetTextAlign(33); // right top
1873        pdf->TextNDC(xmax, ymax+0.05, Form("Page No.%i (%i)  ", page, npages));
1874        line.PaintLineNDC(xmin, ymax+0.01, xmax, ymax+0.01);
1875
1876        line.PaintLineNDC(xmin, ymin-0.01, xmax, ymin-0.01);
1877        pdf->SetTextAlign(11); // left top
1878        if ( !fTitle.IsNull() ) pdf->TextNDC(xmin, ymin-0.04, TString("  ")+fTitle);
1879        pdf->SetTextAlign(31); // right top
1880        pdf->TextNDC(xmax, ymin-0.04, "Comment");
1881
1882        delete clone;
1883    }
1884       
1885    gPad=NULL;
1886    pdf->Close();
1887    delete pdf;
1888
1889
1890    gVirtualPS = pssave;
1891    if (padsave)
1892        padsave->cd();
1893
1894    SetStatusText(Form("Done (%d pages)",page),0);
1895    return page;
1896
1897}
1898
1899
1900//______________________________________________________________________________
1901Int_t EGViewer::SaveAsRoot(const char* name) {
1902    //
1903    //
1904    //
1905
1906    Int_t npages = fCanvases->GetEntries();
1907    if ( !npages ) return 0;
1908
1909    if ( !name ) name = GetName();
1910
1911    TString rootname(name);
1912    if ( !rootname.EndsWith(".root") ) rootname+=".root";
1913
1914    TFile f(rootname,"RECREATE");
1915
1916    Write();
1917    f.Close();
1918
1919    SetStatusText(Form("%s saved", rootname.Data()),0);
1920    return fCanvases->GetEntries();
1921}
1922
1923//______________________________________________________________________________
1924Int_t EGViewer::A4Height( Int_t w ) {
1925
1926    Int_t bw = GetWidth()-GetTab()->GetWidth()+4; // border width
1927    Int_t bh = GetHeight()-GetTab()->GetHeight()+GetTab()->GetTabHeight()+4; // canvas height
1928
1929    Int_t cw = w-bw;
1930    Int_t ch = (Int_t)(cw/kA4CanvasWHRatio);
1931
1932    return ch+bh;
1933   
1934}
1935
1936//______________________________________________________________________________
1937void EGViewer::ShowProgressBarPosition(Bool_t set, Bool_t percent, const char* format) {
1938    fProgressBar->ShowPosition( set, percent, format);
1939}
1940
1941
1942//______________________________________________________________________________
1943Int_t EGViewer::Write(const char *name, Int_t option, Int_t bufsize) const {
1944    //
1945    //
1946    //
1947
1948    return fCanvases->Write(name ? name : GetName(), kSingleKey);
1949   
1950}
1951
1952//______________________________________________________________________________
1953Int_t EGViewer::Read(const char *name) {
1954    //
1955    //
1956    //
1957   
1958    TList list;
1959    if ( !gFile )
1960        return 0;
1961
1962    Int_t bytes = list.Read(name);
1963
1964    TIter next(&list);
1965
1966    while( TCanvas* c = dynamic_cast<TCanvas*>(next())) {
1967        if (!c) continue;
1968
1969        TString name = c->GetName();
1970        TString title = c->GetTitle();
1971
1972        TCanvas *nc = AddTab( name, !title.IsNull() ? title : name );
1973        DrawClonePad(nc, c);
1974    }
1975
1976    return bytes;
1977}
1978
1979//______________________________________________________________________________
1980Int_t EGViewer::SaveAllEPS( const char* path, const char* prefix, Bool_t subpads ){
1981    //
1982    //
1983    //
1984
1985    TString epspath = path;
1986    gSystem->ExpandPathName(epspath);
1987    gSystem->mkdir(epspath,kTRUE);
1988
1989    TString pfx(prefix), epsname;
1990    Int_t nCPrinted(0);
1991
1992    TIter nextC(fCanvases);
1993    while( TCanvas* c=(TCanvas*)nextC() ) {
1994        epsname=epspath+"/"+pfx+c->GetName();
1995        c->Print(epsname+".eps","eps");
1996
1997       
1998        if ( subpads ) {
1999            Int_t nPads(0);
2000
2001            TList* primitives = c->GetListOfPrimitives();
2002            TListIter nextP(primitives);
2003            while( TObject *obj = nextP()) {
2004
2005                if ( obj->IsA() == TPad::Class() ) 
2006                    ((TPad*)obj)->Print(epsname+Form("_p%d.eps",++nPads),"eps");
2007            }
2008
2009            nCPrinted++;
2010
2011        }
2012    }
2013
2014    return nCPrinted;
2015} 
2016
2017//______________________________________________________________________________
2018void EGViewer::SetPadSeekMode( UInt_t mode ) {
2019
2020    if ( mode == fPadSeekMode ) 
2021        mode = kPadSeekOff;
2022
2023    fPadSeekMode = mode ;
2024
2025    switch (fPadSeekMode) {
2026        case kPadSeekOnce:
2027            fTabMenu->CheckEntry( kPadExpandOnce);
2028            fTabMenu->UnCheckEntry( kPadExpandLoop );
2029            break;
2030        case kPadSeekLoop:
2031            fTabMenu->UnCheckEntry( kPadExpandOnce );
2032            fTabMenu->CheckEntry( kPadExpandLoop );
2033            break;
2034        case kPadSeekOff:
2035        default:
2036            fTabMenu->UnCheckEntry( kPadExpandOnce );
2037            fTabMenu->UnCheckEntry( kPadExpandLoop );
2038    }
2039}
2040
2041
2042//______________________________________________________________________________
2043void EGViewer::SetMultiWinExpand( Bool_t multi) {
2044    fMultiWinExpand = multi;
2045    if ( fMultiWinExpand ) 
2046        fTabMenu->CheckEntry( kPadUseMultiWin  );
2047    else 
2048        fTabMenu->UnCheckEntry( kPadUseMultiWin  );
2049}
2050
2051//______________________________________________________________________________
2052void EGViewer::SetOwnCanvasExpand( Bool_t own ) {
2053    fOwnCanvasExpand = own;
2054
2055    if ( fOwnCanvasExpand  ) 
2056        fTabMenu->CheckEntry( kPadOwnCanvas );
2057    else 
2058        fTabMenu->UnCheckEntry( kPadOwnCanvas );
2059}
2060
2061ClassImp(EClusterOfPrimitives)
2062
2063//______________________________________________________________________________
2064//
2065//   EClusterOfPrimitives
2066//
2067
2068
2069//______________________________________________________________________________
2070EClusterOfPrimitives::EClusterOfPrimitives() : TList() {
2071    //
2072    // Constructor
2073    //
2074
2075}
2076
2077//______________________________________________________________________________
2078EClusterOfPrimitives::EClusterOfPrimitives( const char* name, const char* title)
2079    : TList(), fName(name), fTitle(title) {
2080    //
2081    // Constructor
2082    //
2083
2084}
2085
2086
2087//______________________________________________________________________________
2088EClusterOfPrimitives::~EClusterOfPrimitives() {
2089    //
2090    // Destructor
2091    //
2092
2093}
2094
2095//______________________________________________________________________________
2096void EClusterOfPrimitives::Draw(Option_t *option) {
2097    //
2098    // Draw all the objects in the list according their sequence
2099    //
2100
2101    TString opt(option);
2102
2103    if ( opt.Contains("paint") ) {
2104        TObject::Draw(opt);
2105    } else {
2106        TObjLink *lnk = FirstLink();
2107        while (lnk) {
2108            lnk->GetObject()->Draw(lnk->GetOption());
2109            lnk = lnk->Next();
2110        }
2111    }
2112}
2113
2114
2115//______________________________________________________________________________
2116void EClusterOfPrimitives::Paint(Option_t *option) {
2117    //
2118    //
2119    //
2120
2121    TObjLink *lnk = FirstLink();
2122    while (lnk) {
2123        lnk->GetObject()->Paint(lnk->GetOption());
2124        lnk = lnk->Next();
2125    }
2126}
2127
2128//______________________________________________________________________________
2129Int_t EClusterOfPrimitives::DistancetoPrimitive(Int_t px, Int_t py) {
2130    //
2131    //
2132    //
2133
2134    Int_t dist = 999999;
2135    TObject* obj = 0;
2136    TObjLink *lnk = LastLink();
2137    while (lnk) {
2138        Int_t newdist = lnk->GetObject()->DistancetoPrimitive(px, py);
2139        if ( newdist < dist ) {
2140            dist = newdist;
2141            obj = lnk->GetObject();
2142        } 
2143        lnk = lnk->Prev();
2144    }
2145
2146//    if ( obj ) gPad->SetSelected(obj);
2147    return dist;
2148}
2149
2150//______________________________________________________________________________
2151void EClusterOfPrimitives::ExecuteEvent(Int_t event, Int_t px, Int_t py) {
2152    //
2153    //
2154    //
2155   
2156    TObject *obj = Locate(px,py);
2157
2158    if ( obj ) {
2159        Printf("Located %s",obj->GetName());
2160        obj->ExecuteEvent(event,px,py);
2161    }
2162   
2163}
2164
2165//______________________________________________________________________________
2166TObject* EClusterOfPrimitives::Locate(Int_t px, Int_t py) const {
2167    //
2168    // Locate the closest object
2169    //
2170    //
2171   
2172    TObject *obj = 0;
2173    Int_t dist = 999999;
2174   
2175    TObjLink *lnk = FirstLink();
2176    while (lnk) {
2177        Int_t objdist = lnk->GetObject()->DistancetoPrimitive(px, py);
2178        if ( objdist < dist ) {
2179            dist = objdist;
2180            obj = lnk->GetObject();
2181        }
2182       
2183        lnk = lnk->Next();
2184    }
2185
2186    return obj; 
2187}
2188
2189//______________________________________________________________________________
2190char* EClusterOfPrimitives::GetObjectInfo(Int_t px, Int_t py) const {
2191    //
2192    //
2193    //
2194
2195    TObject *obj = Locate(px,py);
2196
2197    if ( obj ) {
2198        Printf("GetObjectInfo %s",obj->GetName());
2199        return obj->GetObjectInfo(px,py);
2200    }
2201
2202    return (char*) "";
2203
2204}
2205
Note: See TracBrowser for help on using the repository browser.