source: trunk/MagicSoft/Mars/mbase/MStatusDisplay.cc@ 2772

Last change on this file since 2772 was 2772, checked in by tbretz, 21 years ago
*** empty log message ***
File size: 61.6 KB
Line 
1/* ======================================================================== *\
2!
3! *
4! * This file is part of MARS, the MAGIC Analysis and Reconstruction
5! * Software. It is distributed to you in the hope that it can be a useful
6! * and timesaving tool in analysing Data of imaging Cerenkov telescopes.
7! * It is distributed WITHOUT ANY WARRANTY.
8! *
9! * Permission to use, copy, modify and distribute this software and its
10! * documentation for any purpose is hereby granted without fee,
11! * provided that the above copyright notice appear in all copies and
12! * that both that copyright notice and this permission notice appear
13! * in supporting documentation. It is provided "as is" without express
14! * or implied warranty.
15! *
16!
17!
18! Author(s): Thomas Bretz, 4/2003 <mailto:tbretz@astro-uni-wuerzburg.de>
19!
20! Copyright: MAGIC Software Development, 2003
21!
22!
23\* ======================================================================== */
24
25/////////////////////////////////////////////////////////////////////////////
26//
27// MStatusDisplay
28//
29// This status display can be used (and is used) to display results in
30// a tabbed window. The window can be written to and read from a root file
31// (see Read and Write) or printed as a postscript file (see SaveAsPS).
32//
33// To write gif files of C-Macros use SaveAsGif() or SaveAsC().
34// Direct printing to the default printer (via lpr) can be done by
35// PrintToLpr().
36//
37// It has also to half status lines which can be used to display the status
38// or something going on. Together with the status lines it has a progress
39// bar which can display the progress of a job or loop.
40// Access the progress bar by GetProgressBar()
41//
42// To add a new tab and get a pointer to the newly created TCanvas
43// use AddTab.
44//
45// If you have a MStatusDisplay and you are not sure whether it was
46// destroyed by the user meanwhile use:
47// gROOT->GetListOfSpecials()->FindObject(pointer);
48// Each MStatusDisplay is added to list list by its constructor and
49// removed from the list by the destructor.
50//
51// You can redirect an output to a MLog-logstream by calling SetLogStream().
52// To disable redirction call SetLogStream(NULL)
53//
54// Because updates to the tabs are only done/displayed if a tab is active
55// using the gui doesn't make things slower (<1%) if the first (legend
56// tab) is displayed. This gives you the possibility to look into
57// the current progress of a loop without loosing more time than the
58// single update of the tab.
59//
60/////////////////////////////////////////////////////////////////////////////
61#include "MStatusDisplay.h"
62
63#include <fstream> // fstream
64
65#include <TLine.h> // TLine
66#include <TText.h> // TText
67#include <TFile.h> // gFile
68#include <TFrame.h> // TFrame
69#include <TStyle.h> // gStyle
70#include <TCanvas.h> // TCanvas
71#include <TSystem.h> // gSystem
72#include <TDatime.h> // TDatime
73#include <TRandom.h> // TRandom
74#include <TThread.h> // TThread::Self()
75#include <TBrowser.h> // TBrowser
76#include <TObjArray.h> // TObjArray
77#include <TPostScript.h> // TPostScript
78#include <TMethodCall.h> // TMethodCall
79
80//#include <TRint.h> // gApplication, TRint::Class()
81#include <TInterpreter.h> // gInterpreter
82
83#include <TGTab.h> // TGTab
84#include <TGLabel.h> // TGLabel
85#include <TG3DLine.h> // TGHorizontal3DLine
86#include <TGButton.h> // TGPictureButton
87#include <TGTextView.h> // TGTextView
88#include <TGStatusBar.h> // TGStatusBar
89#include <TGProgressBar.h> // TGHProgressBar
90
91#include <TRootEmbeddedCanvas.h> // TRootEmbeddedCanvas
92
93#include "MLog.h" // MLog
94#include "MLogManip.h" // inf, warn, err
95
96#include "MGList.h" // MGList
97#include "MGMenu.h" // MGMenu, TGMenu
98#include "MSearch.h" // MSearch
99#include "MParContainer.h" // MParContainer::GetDescriptor
100
101#undef DEBUG
102//#define DEBUG
103
104ClassImp(MStatusDisplay);
105
106using namespace std;
107
108// ------------ Workaround for a non working TGTextView::Search -------------
109#if ROOT_VERSION_CODE < ROOT_VERSION(3,02,05)
110class MGTextView : public TGTextView
111{
112public:
113 MGTextView(const TGWindow *parent, UInt_t w, UInt_t h, Int_t id = -1,
114 UInt_t sboptions = 0, ULong_t back = GetWhitePixel()) :
115 TGTextView(parent, w, h, id, sboptions, back) {}
116 MGTextView(const TGWindow *parent, UInt_t w, UInt_t h, TGText *text,
117 Int_t id = -1, UInt_t sboptions = 0, ULong_t back = GetWhitePixel()) :
118 TGTextView(parent, w, h, text, id, sboptions, back) {}
119 MGTextView(const TGWindow *parent, UInt_t w, UInt_t h, const char *string,
120 Int_t id = -1, UInt_t sboptions = 0, ULong_t back = GetWhitePixel()) :
121 TGTextView(parent, w, h, string, id, sboptions, back) {}
122
123 void Mark(Long_t xPos, Long_t yPos) { TGTextView::Mark(xPos, yPos); }
124 void UnMark() { TGTextView::UnMark(); }
125
126 Bool_t Search(const char *string, Bool_t direction, Bool_t caseSensitive)
127 {
128 // Taken from TGTextView::Search and modified.
129
130 TGLongPosition pos, pos2;
131 pos2.fX = pos2.fY = 0;
132 if (fIsMarked) {
133 if (!direction)
134 {
135 pos2.fX = fMarkedStart.fX;
136 pos2.fY = fMarkedStart.fY;
137 }
138 else
139 {
140 pos2.fX = fMarkedEnd.fX + 1;
141 pos2.fY = fMarkedEnd.fY;
142 }
143 }
144 if (!fText->Search(&pos, pos2, string, direction, caseSensitive))
145 return kFALSE;
146 UnMark();
147 fIsMarked = kTRUE;
148 fMarkedStart.fY = fMarkedEnd.fY = pos.fY;
149 fMarkedStart.fX = pos.fX;
150 fMarkedEnd.fX = fMarkedStart.fX + strlen(string);
151 pos.fY = ToObjYCoord(fVisible.fY);
152 if ((fMarkedStart.fY < pos.fY) ||
153 (ToScrYCoord(fMarkedStart.fY) >= (Int_t)fCanvas->GetHeight()))
154 pos.fY = fMarkedStart.fY;
155 pos.fX = ToObjXCoord(fVisible.fX, pos.fY);
156 if ((fMarkedStart.fX < pos.fX) ||
157 (ToScrXCoord(fMarkedStart.fX, pos.fY) >= (Int_t)fCanvas->GetWidth()))
158 pos.fX = fMarkedStart.fX;
159
160 SetVsbPosition((ToScrYCoord(pos.fY) + fVisible.fY)/fScrollVal.fY);
161 SetHsbPosition((ToScrXCoord(pos.fX, pos.fY) + fVisible.fX)/fScrollVal.fX);
162 DrawRegion(0, (Int_t)ToScrYCoord(fMarkedStart.fY), fCanvas->GetWidth(),
163 UInt_t(ToScrYCoord(fMarkedEnd.fY+1) - ToScrYCoord(fMarkedEnd.fY)));
164
165 return kTRUE;
166 }
167};
168#else
169#define MGTextView TGTextView
170#endif
171// --------------------------------------------------------------------------
172
173// --------------------------------------------------------------------------
174//
175// Add menu bar to the GUI
176//
177void MStatusDisplay::AddMenuBar()
178{
179 //
180 // File Menu
181 //
182 MGPopupMenu *filemenu = new MGPopupMenu(gClient->GetRoot());
183 // filemenu->AddEntry("Save &As...", kFileSaveAs);
184 filemenu->AddEntry("New Can&vas", kFileCanvas);
185 filemenu->AddEntry("New &Browser", kFileBrowser);
186 filemenu->AddSeparator();
187 filemenu->AddEntry("Save As status.&ps", kFileSaveAsPS);
188 filemenu->AddEntry("Save As status.&gif", kFileSaveAsGIF);
189 filemenu->AddEntry("Save As status.&C", kFileSaveAsC);
190 filemenu->AddEntry("Save As status.&root", kFileSaveAsRoot);
191 filemenu->AddSeparator();
192 filemenu->AddEntry("Re&set", kFileReset);
193 filemenu->AddSeparator();
194 filemenu->AddEntry("Print with &lpr", kFilePrint);
195 //filemenu->AddEntry("Set printer &name", kFilePrinterName);
196 filemenu->AddSeparator();
197 filemenu->AddEntry("C&lose", kFileClose);
198 filemenu->AddEntry("E&xit", kFileExit);
199 filemenu->Associate(this);
200
201 //
202 // Tab Menu
203 //
204 MGPopupMenu *tabmenu = new MGPopupMenu(gClient->GetRoot());
205 // tabmenu->AddEntry("Save &As...", kFileSaveAs);
206 tabmenu->AddEntry("Next [&+]", kTabNext);
207 tabmenu->AddEntry("Previous [&-]", kTabPrevious);
208 tabmenu->AddSeparator();
209 tabmenu->AddEntry("Save As tab-i.&ps", kTabSaveAsPS);
210 tabmenu->AddEntry("Save As tab-i.&gif", kTabSaveAsGIF);
211 tabmenu->AddEntry("Save As tab-i.&C", kTabSaveAsC);
212 tabmenu->AddEntry("Save As tab-i.&root", kTabSaveAsRoot);
213 tabmenu->AddSeparator();
214 tabmenu->AddEntry("Re&move", kTabRemove);
215 tabmenu->AddSeparator();
216 tabmenu->AddEntry("Print with &lpr", kTabPrint);
217 tabmenu->Associate(this);
218
219 //
220 // Loop Menu
221 //
222 MGPopupMenu *loopmenu = new MGPopupMenu(gClient->GetRoot());
223 loopmenu->AddEntry("&Stop", kLoopStop);
224 loopmenu->Associate(this);
225
226 //
227 // Loop Menu
228 //
229 MGPopupMenu *sizemenu = new MGPopupMenu(gClient->GetRoot());
230 sizemenu->AddEntry("Fit to 640x&480", kSize640);
231 sizemenu->AddEntry("Fit to 800x&600", kSize800);
232 sizemenu->AddEntry("Fit to 960x7&20", kSize960);
233 sizemenu->AddEntry("Fit to 1024x&768", kSize1024);
234 sizemenu->AddEntry("Fit to 1280x&1024", kSize1280);
235 sizemenu->Associate(this);
236
237 //
238 // Log Menu
239 //
240 MGPopupMenu *logmenu = new MGPopupMenu(gClient->GetRoot());
241 logmenu->AddEntry("&Copy Selected", kLogCopy);
242 logmenu->AddEntry("Cl&ear all", kLogClear);
243 logmenu->AddSeparator();
244 logmenu->AddEntry("Select &All", kLogSelect);
245 logmenu->AddSeparator();
246 logmenu->AddEntry("&Find...", kLogFind);
247 logmenu->AddSeparator();
248 logmenu->AddEntry("&Save", kLogSave);
249 logmenu->AddEntry("Save &append", kLogAppend);
250 logmenu->Associate(this);
251
252 //
253 // Menu Bar
254 //
255 TGLayoutHints *layitem = new TGLayoutHints(kLHintsNormal, 0, 4, 0, 0);
256 fList->Add(layitem);
257
258 MGMenuBar *menubar = new MGMenuBar(this, 1, 1, kHorizontalFrame);
259 menubar->AddPopup("&File", filemenu, layitem);
260 menubar->AddPopup("Lo&g", logmenu, layitem);
261 menubar->AddPopup("&Size", sizemenu, layitem);
262 menubar->AddPopup("&Tab", tabmenu, layitem);
263 menubar->AddPopup("&Loop", loopmenu, layitem);
264 menubar->BindKeys(this);
265 AddFrame(menubar);
266
267 //
268 // Line below menu bar
269 //
270 TGLayoutHints *laylinesep = new TGLayoutHints(kLHintsTop|kLHintsExpandX);
271 fList->Add(laylinesep);
272
273 TGHorizontal3DLine *linesep = new TGHorizontal3DLine(this);
274 AddFrame(linesep, laylinesep);
275
276 //
277 // Add everything to autodel list
278 //
279 fList->Add(filemenu);
280 fList->Add(loopmenu);
281 fList->Add(sizemenu);
282 fList->Add(menubar);
283 fList->Add(tabmenu);
284 fList->Add(logmenu);
285 fList->Add(linesep);
286}
287
288// --------------------------------------------------------------------------
289//
290// Adds an empty TGCompositeFrame which might be filled by the user
291//
292void MStatusDisplay::AddUserFrame()
293{
294 TGLayoutHints *lay=new TGLayoutHints(kLHintsExpandX);
295 fList->Add(lay);
296
297 fUserFrame = new TGCompositeFrame(this, 1, 1);
298 AddFrame(fUserFrame, lay);
299 fList->Add(fUserFrame);
300}
301
302// --------------------------------------------------------------------------
303//
304// Add the title tab
305//
306void MStatusDisplay::AddMarsTab()
307{
308 // Create Tab1
309 TGCompositeFrame *f = fTab->AddTab("-=MARS=-");
310
311 // Add MARS version
312 TGLabel *l = new TGLabel(f, Form("Official Release: V%s", MARSVER));
313 fList->Add(l);
314
315 TGLayoutHints *layb = new TGLayoutHints(kLHintsCenterX|kLHintsTop, 10, 10, 5, 5);
316 fList->Add(layb);
317 f->AddFrame(l, layb);
318
319 // Add root version
320 l = new TGLabel(f, Form("Using ROOT v%s", ROOTVER));
321 fList->Add(l);
322
323 TGLayoutHints *lay = new TGLayoutHints(kLHintsCenterX|kLHintsTop);
324 fList->Add(lay);
325 f->AddFrame(l, lay);
326
327 // Add Mars logo picture
328 const TGPicture *pic2 = fList->GetPicture("marslogo.xpm");
329 if (pic2)
330 {
331 TGPictureButton *mars = new TGPictureButton(f, pic2, kPicMars);
332 fList->Add(mars);
333 mars->Associate(this);
334
335 TGLayoutHints *lay2 = new TGLayoutHints(kLHintsCenterX|kLHintsCenterY, 10, 10, 5, 5);
336 fList->Add(lay2);
337 f->AddFrame(mars, lay2);
338 }
339
340 // Add date and time
341 TDatime d;
342 l = new TGLabel(f, d.AsString());
343 fList->Add(l);
344 f->AddFrame(l, lay);
345
346 // Add copyright notice
347 l = new TGLabel(f, "(c) MAGIC Software Development, 2000-2003");
348 fList->Add(l);
349 f->AddFrame(l, layb);
350
351 TGLayoutHints *layc = new TGLayoutHints(kLHintsCenterX|kLHintsTop, 10, 10, 0, 5);
352 fList->Add(layc);
353
354 l = new TGLabel(f, "<< Thomas Bretz >>");
355 fList->Add(l);
356 f->AddFrame(l, layc);
357}
358
359// --------------------------------------------------------------------------
360//
361// Adds the logbook tab to the GUI if it was not added previously.
362//
363// The logbook is updated four times a second only if the tab is visible.
364//
365// You can redirect an output to a MLog-logstream by calling SetLogStream().
366// To disable redirction call SetLogStream(NULL)
367//
368// if enable==kFALSE the stdout is disabled/enabled. Otherwise stdout
369// is ignored.
370//
371void MStatusDisplay::SetLogStream(MLog *log, Bool_t enable)
372{
373 if (gROOT->IsBatch())
374 return;
375
376 if (log && fLogBox==NULL)
377 {
378 fLogIdx = fTab->GetNumberOfTabs();
379
380 // Create Tab1
381 TGCompositeFrame *f = fTab->AddTab("-Logbook-");
382
383 // Create Text View
384 fLogBox = new MGTextView(f, 1, 1); // , -1, 0, TGFrame::GetDefaultFrameBackground());
385 if (fFont)
386 fLogBox->SetFont(fFont);
387 //fLogBox->Associate(this);
388
389 // Add List box to the tab
390 TGLayoutHints *lay = new TGLayoutHints(kLHintsNormal|kLHintsExpandX|kLHintsExpandY,2,2,2,2);
391 f->AddFrame(fLogBox, lay);
392
393 // layout and map tab
394 Layout();
395 MapSubwindows();
396
397 // make it visible
398 // FIXME: This is a workaround, because TApplication::Run is not
399 // thread safe against ProcessEvents. We assume, that if
400 // we are not in the Main-Thread ProcessEvents() is
401 // called by the TApplication Event Loop...
402 if (!TThread::Self()/*gApplication->InheritsFrom(TRint::Class())*/)
403 gClient->ProcessEventsFor(fTab);
404 }
405
406 if (log)
407 {
408 fLog = log;
409
410 log->SetOutputGui(fLogBox, kTRUE);
411 log->EnableOutputDevice(MLog::eGui);
412 if (!enable)
413 log->DisableOutputDevice(MLog::eStdout);
414
415 fLogTimer.Start();
416 }
417 else
418 {
419 fLogTimer.Stop();
420
421 fLog->DisableOutputDevice(MLog::eGui);
422 fLog->SetOutputGui(NULL);
423 if (!enable)
424 fLog->EnableOutputDevice(MLog::eStdout);
425
426 fLog = &gLog;
427 }
428}
429
430// --------------------------------------------------------------------------
431//
432// Add the Tabs and the predifined Tabs to the GUI
433//
434void MStatusDisplay::AddTabs()
435{
436 fTab = new TGTab(this, 300, 300);
437
438 AddMarsTab();
439
440 // Add fTab to Frame
441 TGLayoutHints *laytabs = new TGLayoutHints(kLHintsNormal|kLHintsExpandX|kLHintsExpandY, 5, 5, 5);
442 AddFrame(fTab, laytabs);
443
444 fList->Add(fTab);
445 fList->Add(laytabs);
446}
447
448// --------------------------------------------------------------------------
449//
450// Add the progress bar to the GUI. The Progress Bar range is set to
451// (0,1) as default.
452//
453void MStatusDisplay::AddProgressBar()
454{
455 TGLayoutHints *laybar=new TGLayoutHints(kLHintsExpandX, 5, 5, 5, 5);
456 fList->Add(laybar);
457
458 fBar=new TGHProgressBar(this);
459 fBar->SetRange(0, 1);
460 fBar->ShowPosition();
461 AddFrame(fBar, laybar);
462 fList->Add(fBar);
463}
464
465// --------------------------------------------------------------------------
466//
467// Set the progress bar position between 0 and 1. The Progress bar range
468// is assumed to be (0,1)
469//
470void MStatusDisplay::SetProgressBarPosition(Float_t p)
471{
472 fBar->SetPosition(p);
473}
474
475// --------------------------------------------------------------------------
476//
477// Adds the status bar to the GUI
478//
479void MStatusDisplay::AddStatusBar()
480{
481 fStatusBar = new TGStatusBar(this, 1, 1);
482
483 //
484 // Divide it like the 'Golden Cut' (goldener Schnitt)
485 //
486 // 1-a a
487 // 1: ------|----
488 //
489 // a/(1-a) = (1-a)/1
490 // a^2+a-1 = 0
491 // a = (-1+-sqrt(1+4))/2 = sqrt(5)/2-1/2 = 0.618
492 //
493 Int_t p[2] = {38, 62};
494
495 fStatusBar->SetParts(p, 2);
496
497 TGLayoutHints *layb = new TGLayoutHints(kLHintsNormal|kLHintsExpandX, 5, 4, 0, 3);
498 AddFrame(fStatusBar, layb);
499
500 fList->Add(fStatusBar);
501 fList->Add(layb);
502}
503
504// --------------------------------------------------------------------------
505//
506// Change the text in the status line 1
507//
508void MStatusDisplay::SetStatusLine1(const char *txt)
509{
510 if (gROOT->IsBatch())
511 return;
512 fStatusBar->SetText(txt, 0);
513
514 // FIXME: This is a workaround, because TApplication::Run is not
515 // thread safe against ProcessEvents. We assume, that if
516 // we are not in the Main-Thread ProcessEvents() is
517 // called by the TApplication Event Loop...
518 if (!TThread::Self()/*gApplication->InheritsFrom(TRint::Class())*/)
519 gClient->ProcessEventsFor(fStatusBar);
520}
521
522// --------------------------------------------------------------------------
523//
524// Change the text in the status line 2
525//
526void MStatusDisplay::SetStatusLine2(const char *txt)
527{
528 if (gROOT->IsBatch())
529 return;
530 fStatusBar->SetText(txt, 1);
531
532 // FIXME: This is a workaround, because TApplication::Run is not
533 // thread safe against ProcessEvents. We assume, that if
534 // we are not in the Main-Thread ProcessEvents() is
535 // called by the TApplication Event Loop...
536 if (!TThread::Self()/*gApplication->InheritsFrom(TRint::Class())*/)
537 gClient->ProcessEventsFor(fStatusBar);
538}
539
540// --------------------------------------------------------------------------
541//
542// Display information about the name of a container
543//
544void MStatusDisplay::SetStatusLine2(const MParContainer &cont)
545{
546 SetStatusLine2(Form("%s: %s", cont.GetDescriptor(), cont.GetTitle()));
547}
548
549// --------------------------------------------------------------------------
550//
551// Default constructor. Opens a window with a progress bar. Get a pointer
552// to the bar by calling GetBar. This pointer can be used for the
553// eventloop.
554//
555// Be carefull: killing or closing the window while the progress meter
556// is still in use may cause segmentation faults. Please kill the window
557// always by deleting the corresponding object.
558//
559// Update time default: 10s
560//
561MStatusDisplay::MStatusDisplay(Long_t t)
562: TGMainFrame(NULL, 1, 1), fLog(&gLog), fTab(NULL), fTimer(this, t, kTRUE), fStatus(kLoopNone), fLogIdx(-1), fLogTimer(this, 250, kTRUE), fLogBox(NULL), fIsLocked(0)
563{
564 // p==NULL means: Take gClient->GetRoot() if not in batch mode
565 // see TGWindow::TGWindow()
566
567 //
568 // This is a possibility for the user to check whether this
569 // object has already been deleted. It will be removed
570 // from the list in the destructor.
571 //
572 gROOT->GetListOfSpecials()->Add(this);
573
574 fFont = gVirtualX->LoadQueryFont("7x13bold");
575 fMutex = new TMutex;
576
577 //
578 // In case we are in batch mode use a list of canvases
579 // instead of the Root Embedded Canvases in the TGTab
580 //
581 fBatch = new TList;
582 fBatch->SetOwner();
583
584 //
585 // Create a list handling GUI widgets
586 //
587 fList = new MGList;
588 fList->SetOwner();
589
590 //
591 // Create the layout hint for the root embedded canavses
592 //
593 fLayCanvas = new TGLayoutHints(kLHintsExpandX|kLHintsExpandY);
594 fList->Add(fLayCanvas);
595
596 //
597 // Add Widgets (from top to bottom)
598 //
599 if (gClient) // BATCH MODE
600 {
601 AddMenuBar();
602 AddUserFrame();
603 AddTabs();
604 AddProgressBar();
605 AddStatusBar();
606 }
607
608 //
609 // set the smallest and biggest size of the Main frame
610 // and move it to its appearance position
611 SetWMSizeHints(570, 480, 1280, 980, 1, 1);
612 MoveResize(rand()%100+570, rand()%100+480, 570, 480);
613
614 //
615 // Now do an automatic layout of the widgets and display the window
616 //
617 Layout();
618 MapSubwindows();
619
620 SetWindowName("Status Display");
621 SetIconName("Status Display");
622
623 MapWindow();
624
625 // FIXME: This is a workaround, because TApplication::Run is not
626 // thread safe against ProcessEvents. We assume, that if
627 // we are not in the Main-Thread ProcessEvents() is
628 // called by the TApplication Event Loop...
629 if (!TThread::Self()/*gApplication->InheritsFrom(TRint::Class())*/)
630 gSystem->ProcessEvents();
631}
632
633// --------------------------------------------------------------------------
634//
635// Destruct the window with all its tiles. Also the Progress Bar object
636// is deleted.
637//
638MStatusDisplay::~MStatusDisplay()
639{
640#if ROOT_VERSION_CODE < ROOT_VERSION(3,10,01)
641 fTab = NULL; // See HandleEvent
642#endif
643
644 //
645 // Delete object from global object table so it cannot
646 // be deleted by chance a second time
647 //
648 gInterpreter->DeleteGlobal(this);
649
650 //
651 // This is a possibility for the user to check whether this
652 // object has already been deleted. It has been added
653 // to the list in the constructor.
654 //
655 gROOT->GetListOfSpecials()->Remove(this);
656
657 SetLogStream(NULL);
658
659 //
660 // Delete the list of objects corresponding to this object
661 //
662 delete fList;
663
664 //
665 // Delete the list list of canvases used in batch mode
666 // instead of the Root Embedded Canvases in the TGTab
667 //
668 delete fBatch;
669
670 //
671 // Delete the font used for the logging window
672 //
673 if (fFont)
674 gVirtualX->DeleteFont(fFont);
675
676 //
677 // Delete mutex
678 //
679 delete fMutex;
680}
681
682// --------------------------------------------------------------------------
683//
684// Takes a TGCompositeFrame as argument. Searches for the first
685// TRootEmbeddedCanvas which is contained by it and returns a pointer
686// to the corresponding TCanvas. If it isn't found NULL is returned.
687//
688TRootEmbeddedCanvas *MStatusDisplay::GetEmbeddedCanvas(TGCompositeFrame *cf) const
689{
690 TIter Next(cf->GetList());
691
692 TGFrameElement *f;
693 while ((f=(TGFrameElement*)Next()))
694 if (f->fFrame->InheritsFrom(TRootEmbeddedCanvas::Class()))
695 return (TRootEmbeddedCanvas*)f->fFrame;
696
697 return NULL;
698}
699
700// --------------------------------------------------------------------------
701//
702// Takes a TGCompositeFrame as argument. Searches for the first
703// TRootEmbeddedCanvas which is contained by it and returns a pointer
704// to the corresponding TCanvas. If it isn't found NULL is returned.
705//
706TCanvas *MStatusDisplay::GetCanvas(TGCompositeFrame *cf) const
707{
708 TRootEmbeddedCanvas *ec = GetEmbeddedCanvas(cf);
709 return ec ? ec->GetCanvas() : NULL;
710}
711
712// --------------------------------------------------------------------------
713//
714// Returns GetCanvas of the i-th Tab.
715//
716TCanvas *MStatusDisplay::GetCanvas(int i) const
717{
718 if (gROOT->IsBatch())
719 return (TCanvas*)fBatch->At(i-1);
720
721 if (i<0 || i>=fTab->GetNumberOfTabs())
722 {
723 *fLog << warn << "MStatusDisplay::GetCanvas: Out of range." << endl;
724 return NULL;
725 }
726
727 return GetCanvas(fTab->GetTabContainer(i));
728}
729
730// --------------------------------------------------------------------------
731//
732// Searches for a TRootEmbeddedCanvas in the TGCompositeFramme of the
733// Tab with the name 'name'. Returns the corresponding TCanvas or
734// NULL if something isn't found.
735//
736TCanvas *MStatusDisplay::GetCanvas(const TString &name) const
737{
738 TGFrameElement *f;
739 TIter Next(fTab->GetList());
740 while ((f=(TGFrameElement*)Next()))
741 {
742 TObject *frame = f->fFrame;
743 if (!frame->InheritsFrom(TGTabElement::Class()))
744 continue;
745
746 TGTabElement *tab = (TGTabElement*)frame;
747 if (tab->GetString()==name)
748 break;
749 }
750
751 // Search for the next TGCompositeFrame in the list
752 while ((f=(TGFrameElement*)Next()))
753 {
754 TObject *frame = f->fFrame;
755 if (frame->InheritsFrom(TGCompositeFrame::Class()))
756 return GetCanvas((TGCompositeFrame*)frame);
757 }
758
759 return NULL;
760}
761
762// --------------------------------------------------------------------------
763//
764// Calls TCanvas::cd(), for the canvas returned by GetCanvas.
765//
766Bool_t MStatusDisplay::CdCanvas(const TString &name)
767{
768 TCanvas *c = GetCanvas(name);
769 if (!c)
770 return kFALSE;
771
772 c->cd();
773 return kTRUE;
774}
775
776TGCompositeFrame *MStatusDisplay::AddRawTab(const char *name)
777{
778 // Add new tab
779 TGCompositeFrame *f = fTab->AddTab(name);
780
781 // layout and map new tab
782 Layout();
783 MapSubwindows();
784 Layout();
785
786 // display new tab in the main frame
787 // FIXME: This is a workaround, because TApplication::Run is not
788 // thread safe against ProcessEvents. We assume, that if
789 // we are not in the Main-Thread ProcessEvents() is
790 // called by the TApplication Event Loop...
791 if (!TThread::Self()/*gApplication->InheritsFrom(TRint::Class())*/)
792 gClient->ProcessEventsFor(fTab);
793
794 *fLog << inf << "Adding Raw Tab '" << name << "' (" << f->GetWidth() << "x";
795 *fLog << f->GetHeight() << ")" << endl;
796
797 // return pointer to new canvas
798 return f;
799}
800
801// --------------------------------------------------------------------------
802//
803// Adds a new tab with the name 'name'. Adds a TRootEmbeddedCanvas to the
804// tab and returns a reference to the corresponding TCanvas.
805//
806TCanvas &MStatusDisplay::AddTab(const char *name)
807{
808 if (gROOT->IsBatch())
809 {
810 TCanvas *c = new TCanvas(name, name);
811 fBatch->Add(c);
812 return *c;
813 }
814
815 // Add new tab
816 TGCompositeFrame *f = fTab->AddTab(name);
817
818 // create root embedded canvas and add it to the tab
819 TRootEmbeddedCanvas *ec = new TRootEmbeddedCanvas(name, f, f->GetWidth(), f->GetHeight(), 0);
820 f->AddFrame(ec, fLayCanvas);
821 fList->Add(ec);
822
823 // set background and border mode of the canvas
824 TCanvas &c = *ec->GetCanvas();
825
826 c.SetFillColor(16/*165*//*17*//*203*/);
827 c.SetBorderMode(0);
828
829 // If kNoContextMenu set set kNoContextMenu of the canvas
830 if (TestBit(kNoContextMenu))
831 c.SetBit(kNoContextMenu);
832
833 // layout and map new tab
834 Layout(); // seems to layout the TGCompositeFrame
835 MapSubwindows(); // maps the TGCompositeFrame
836 Layout(); // layout the embedded canvas in the frame
837
838 // display new tab in the main frame
839 // FIXME: This is a workaround, because TApplication::Run is not
840 // thread safe against ProcessEvents. We assume, that if
841 // we are not in the Main-Thread ProcessEvents() is
842 // called by the TApplication Event Loop...
843 if (!TThread::Self()/*gApplication->InheritsFrom(TRint::Class())*/)
844 gClient->ProcessEventsFor(fTab);
845
846 *fLog << inf << "Adding Tab '" << name << "' (" << f->GetWidth() << "x";
847 *fLog << f->GetHeight() << ", TCanvas=" << &c << ")" << endl;
848
849 // return pointer to new canvas
850 return c;
851}
852
853// --------------------------------------------------------------------------
854//
855// Update a canvas in a tab, takes the corresponding TGCompositeFrame
856// as an argument. This is necessary, because not all functions
857// changing the contents of a canvas or pad can call SetModified()
858// for the corresponding tab. If this is not called correctly the
859// tab won't be updated calling TCanvas::Update(). So we simply
860// redraw it by our own (instead we could recursively call
861// TPad::Modified() for everything contained by the TCanvas and
862// call TCanvas::Update() afterwards)
863//
864void MStatusDisplay::UpdateTab(TGCompositeFrame *f)
865{
866 if (!f)
867 return;
868
869 TCanvas *c=GetCanvas(f);
870 if (!c)
871 return;
872
873 //
874 // If we are in a multithreaded environment (gThreadXAR) we
875 // have to make sure, that thus function is called from
876 // the main thread.
877 //
878 if (gThreadXAR)
879 {
880 // Tell the X-Requester how to call this method
881 TString str = Form("%d", (ULong_t)f);
882
883 TMethodCall call(IsA(), "UpdateTab", "NULL");
884 void *arr[4] = { NULL, &call, this, (void*)(const char*)str };
885
886 // If this is not the main thread return
887 if (((*gThreadXAR)("METH", 4, arr, NULL)))
888 return;
889 }
890
891 //
892 // Secure calls to update the tabs against itself, at least
893 // c->Paint() or c->Flush() may crash X (bad drawable).
894 // This makes sure, that a X call is not interuppted by
895 // another X-call which was started from an gui interrrupt
896 // in the same thread
897 //
898 if (fMutex->TryLock())
899 return;
900
901#if ROOT_VERSION_CODE < ROOT_VERSION(3,10,02)
902 TPad *padsav = (TPad*)gPad;
903 if (!gPad)
904 c->cd();
905#endif
906
907 if (!c->IsBatch())
908 c->FeedbackMode(kFALSE); // Goto double buffer mode
909
910 //
911 // Doing this ourself gives us the possibility to repaint
912 // the canvas in any case (Paint() instead of PaintModified())
913 //
914 c->Paint(); // Repaint all pads
915 c->Flush(); // Copy all pad pixmaps to the screen
916
917#if ROOT_VERSION_CODE < ROOT_VERSION(3,10,02)
918 if (padsav)
919 padsav->cd();
920 else
921 gPad=NULL;
922#endif
923
924 //c->SetCursor(kCross);
925
926 // Old version
927 //c->Modified();
928 //c->Update();
929 //c->Paint();
930
931 fMutex->UnLock();
932}
933
934// --------------------------------------------------------------------------
935//
936// Saves the given canvas (pad) or all pads (num<0) as a temporary
937// postscript file and prints it using 'lpr'. If a printer name is set
938// via SetPrinter 'lpr -Pname' is used.
939//
940Int_t MStatusDisplay::PrintToLpr(Int_t num)
941{
942 TString name = "mars";
943
944 for (int i=0; i<6; i++)
945 name += (char)(gRandom->Uniform(25)+65);
946
947 name += ".ps";
948
949 const Int_t pages = SaveAsPS(num, name);
950
951 SetStatusLine1("Printing...");
952 SetStatusLine2("");
953
954 if (!pages)
955 {
956 *fLog << warn << "MStatusDisplay::PrintToLpr: Sorry, couldn't save file as temporary postscript!" << endl;
957 SetStatusLine2("Failed!");
958 return 0;
959 }
960
961 TString cmd="lpr ";
962 if (!fPrinter.IsNull())
963 {
964 cmd += "-P";
965 cmd += fPrinter;
966 cmd += " ";
967 }
968 cmd += name;
969
970 gSystem->Exec(cmd);
971 gSystem->Unlink(name);
972
973 SetStatusLine2(Form("Done (%dpage(s))", pages));
974
975 return pages;
976}
977
978// --------------------------------------------------------------------------
979//
980// Remove tab no i if this tab contains a TRootEmbeddedCanvas
981//
982void MStatusDisplay::RemoveTab(int i)
983{
984 TGCompositeFrame *f = fTab->GetTabContainer(i);
985 if (!f)
986 return;
987
988 TRootEmbeddedCanvas *ec = GetEmbeddedCanvas(f);
989 if (!ec)
990 return;
991
992 TCanvas *c = ec->GetCanvas();
993 if (!c)
994 return;
995
996 const TString name(c->GetName());
997
998 f->RemoveFrame(ec);
999 delete fList->Remove(ec);
1000
1001 fTab->RemoveTab(i);
1002 fTab->SetTab(0);
1003
1004 // Looks strange...
1005 // const Int_t n = fTab->GetNumberOfTabs();
1006 // fTab->SetTab(i<=n-1 ? i : i-1);
1007
1008 // layout and map new tab
1009 Layout(); // seems to layout the TGCompositeFrame
1010 MapSubwindows(); // maps the TGCompositeFrame
1011 Layout(); // layout the embedded canvas in the frame
1012
1013 // display new tab in the main frame
1014 // FIXME: This is a workaround, because TApplication::Run is not
1015 // thread safe against ProcessEvents. We assume, that if
1016 // we are not in the Main-Thread ProcessEvents() is
1017 // called by the TApplication Event Loop...
1018 if (!TThread::Self()/*gApplication->InheritsFrom(TRint::Class())*/)
1019 gClient->ProcessEventsFor(fTab);
1020
1021 *fLog << inf << "Removed Tab #" << i << " '" << name << "'" << endl;
1022}
1023
1024// --------------------------------------------------------------------------
1025//
1026// Use this to check whether the MStatusDisplay still contains the
1027// TCanvas c. It could be removed meanwhile by menu usage.
1028//
1029Bool_t MStatusDisplay::HasCanvas(const TCanvas *c) const
1030{
1031 if (!c)
1032 return kFALSE;
1033
1034 if (gROOT->IsBatch())
1035 return (Bool_t)fBatch->FindObject(c);
1036
1037 for (int i=1; i<fTab->GetNumberOfTabs(); i++)
1038 if (c==GetCanvas(i))
1039 return kTRUE;
1040 return kFALSE;
1041}
1042
1043/*
1044 if (...)
1045 fMenu->AddPopup("&CaOs", fCaOs, NULL);
1046 else
1047 fMenu->RemovePopup("CaOs");
1048 fMenu->Resize(fMenu->GetDefaultSize());
1049 MapSubwindows();
1050 MapWindow();
1051 */
1052
1053void MStatusDisplay::Reset()
1054{
1055 for (int i=fTab->GetNumberOfTabs()-1; i>0; i--)
1056 RemoveTab(i);
1057}
1058
1059// --------------------------------------------------------------------------
1060//
1061// Process the kC_COMMAND, kCM_MENU messages
1062//
1063Bool_t MStatusDisplay::ProcessMessageCommandMenu(Long_t id)
1064{
1065 switch (id)
1066 {
1067 case kLoopStop:
1068 case kFileClose:
1069 case kFileExit:
1070 if (id==kFileExit || id==kFileClose)
1071 CloseWindow();
1072 fStatus = (Status_t)id;
1073 return kTRUE;
1074
1075 case kFileCanvas:
1076 new TCanvas;
1077 return kTRUE;
1078
1079 case kFileBrowser:
1080 new TBrowser;
1081 return kTRUE;
1082
1083 case kFileReset:
1084 Reset();
1085 return kTRUE;
1086 /*
1087 case kFileSave:
1088 cout << "Save..." << endl;
1089 return kTRUE;
1090
1091 case kFileSaveAs:
1092 cout << "SaveAs..." << endl;
1093 return kTRUE;
1094*/
1095 case kFileSaveAsPS:
1096 SaveAsPS();
1097 return kTRUE;
1098
1099 case kFileSaveAsGIF:
1100 SaveAsGIF();
1101 return kTRUE;
1102
1103 case kFileSaveAsC:
1104 SaveAsC();
1105 return kTRUE;
1106
1107 case kFileSaveAsRoot:
1108 SaveAsRoot();
1109 return kTRUE;
1110
1111 case kFilePrint:
1112 PrintToLpr();
1113 return kTRUE;
1114
1115 case kTabSaveAsPS:
1116 SaveAsPS(fTab->GetCurrent());
1117 return kTRUE;
1118
1119 case kTabSaveAsGIF:
1120 SaveAsGIF(fTab->GetCurrent());
1121 return kTRUE;
1122
1123 case kTabSaveAsC:
1124 SaveAsC(fTab->GetCurrent());
1125 return kTRUE;
1126
1127 case kTabSaveAsRoot:
1128 SaveAsRoot(fTab->GetCurrent());
1129 return kTRUE;
1130
1131 case kTabPrint:
1132 PrintToLpr(fTab->GetCurrent());
1133 return kTRUE;
1134
1135 case kTabNext:
1136 fTab->SetTab(fTab->GetCurrent()+1);
1137 return kTRUE;
1138
1139 case kTabPrevious:
1140 fTab->SetTab(fTab->GetCurrent()-1);
1141 return kTRUE;
1142
1143 case kTabRemove:
1144 RemoveTab(fTab->GetCurrent());
1145 return kTRUE;
1146
1147 case kSize640:
1148 Resize(570, 480);
1149 return kTRUE;
1150 case kSize800:
1151 Resize(740, 600);
1152 return kTRUE;
1153 case kSize960:
1154 Resize(880, 700);
1155 return kTRUE;
1156 case kSize1024:
1157 Resize(980, 768);
1158 return kTRUE;
1159 case kSize1280:
1160 Resize(1280, 980);
1161 return kTRUE;
1162
1163 case kLogClear:
1164 fLogBox->Clear();
1165 return kTRUE;
1166 case kLogCopy:
1167 fLogBox->Copy();
1168 return kTRUE;
1169 case kLogSelect:
1170 fLogBox->SelectAll();
1171 return kTRUE;
1172 case kLogFind:
1173 new MSearch(this);
1174 return kTRUE;
1175 case kLogSave:
1176 SetStatusLine1("Saving log...");
1177 SetStatusLine2("");
1178 *fLog << inf << "Saving log... " << flush;
1179 if (fLogBox->GetText()->Save("statusdisplay.log"))
1180 {
1181 *fLog << "done." << endl;
1182 SetStatusLine2("done.");
1183 }
1184 else
1185 {
1186 *fLog << "failed!" << endl;
1187 SetStatusLine2("Failed!");
1188 }
1189 return kTRUE;
1190
1191 case kLogAppend:
1192 SetStatusLine1("Appending logg...");
1193 SetStatusLine2("");
1194 *fLog << inf << "Appending log... " << flush;
1195 if (fLogBox->GetText()->Append("statusdisplay.log"))
1196 {
1197 *fLog << "done." << endl;
1198 SetStatusLine2("done.");
1199 }
1200 else
1201 {
1202 *fLog << "failed!" << endl;
1203 SetStatusLine2("Failed!");
1204 }
1205 return kTRUE;
1206#ifdef DEBUG
1207 default:
1208 cout << "Command-Menu #" << id << endl;
1209#endif
1210 }
1211 return kTRUE;
1212
1213}
1214
1215// --------------------------------------------------------------------------
1216//
1217// Process the kC_COMMAND messages
1218//
1219Bool_t MStatusDisplay::ProcessMessageCommand(Long_t submsg, Long_t mp1, Long_t mp2)
1220{
1221 switch (submsg)
1222 {
1223 case kCM_MENU: // 1
1224 return ProcessMessageCommandMenu(mp1); // mp2=userdata
1225 case kCM_TAB: // 8
1226 /*
1227 for (int i=0; i<fTab->GetNumberOfTabs(); i++)
1228 fTab->GetTabContainer(i)->UnmapWindow();
1229 */
1230 UpdateTab(fTab->GetTabContainer(mp1));
1231 //fTab->GetTabContainer(mp1)->MapWindow();
1232
1233 /*
1234 if (mp1>0)
1235 fMenu->AddPopup("&CaOs", fCaOs, NULL);
1236 else
1237 fMenu->RemovePopup("CaOs");
1238 fMenu->Resize(fMenu->GetDefaultSize());
1239 MapSubwindows();
1240 MapWindow();
1241 */
1242 return kTRUE;
1243#ifdef DEBUG
1244 case kCM_MENUSELECT: // 2
1245 cout << "Command-Menuselect #" << mp1 << " (UserData=" << (void*)mp2 << ")" << endl;
1246 return kTRUE;
1247
1248 case kCM_BUTTON: // 3
1249 cout << "Command-Button." << endl;
1250 return kTRUE;
1251
1252 case kCM_CHECKBUTTON: // 4
1253 cout << "Command-CheckButton." << endl;
1254 return kTRUE;
1255
1256 case kCM_RADIOBUTTON: // 5
1257 cout << "Command-RadioButton." << endl;
1258 return kTRUE;
1259
1260 case kCM_LISTBOX: // 6
1261 cout << "Command-Listbox #" << mp1 << " (LineId #" << mp2 << ")" << endl;
1262 return kTRUE;
1263
1264 case kCM_COMBOBOX: // 7
1265 cout << "Command-ComboBox." << endl;
1266 return kTRUE;
1267 default:
1268 cout << "Command: " << "Submsg:" << submsg << " Mp1=" << mp1 << " Mp2=" << mp2 << endl;
1269#endif
1270 }
1271 return kTRUE;
1272}
1273
1274// --------------------------------------------------------------------------
1275//
1276// Process the kC_TEXTVIEW messages
1277//
1278Bool_t MStatusDisplay::ProcessMessageTextview(Long_t submsg, Long_t mp1, Long_t mp2)
1279{
1280 // kC_TEXTVIEW, kTXT_ISMARKED, widget id, [true|false] //
1281 // kC_TEXTVIEW, kTXT_DATACHANGE, widget id, 0 //
1282 // kC_TEXTVIEW, kTXT_CLICK2, widget id, position (y << 16) | x) //
1283 // kC_TEXTVIEW, kTXT_CLICK3, widget id, position (y << 16) | x) //
1284 // kC_TEXTVIEW, kTXT_F3, widget id, true //
1285 // kC_TEXTVIEW, kTXT_OPEN, widget id, 0 //
1286 // kC_TEXTVIEW, kTXT_CLOSE, widget id, 0 //
1287 // kC_TEXTVIEW, kTXT_SAVE, widget id, 0 //
1288#ifdef DEBUG
1289 switch (submsg)
1290 {
1291 case kTXT_ISMARKED:
1292 cout << "Textview-IsMarked #" << mp1 << " " << (mp2?"yes":"no") << endl;
1293 return kTRUE;
1294
1295 case kTXT_DATACHANGE:
1296 cout << "Textview-DataChange #" << mp1 << endl;
1297 return kTRUE;
1298
1299 case kTXT_CLICK2:
1300 cout << "Textview-Click2 #" << mp1 << " x=" << (mp2&0xffff) << " y= " << (mp2>>16) << endl;
1301 return kTRUE;
1302
1303 case kTXT_CLICK3:
1304 cout << "Textview-Click3 #" << mp1 << " x=" << (mp2&0xffff) << " y= " << (mp2>>16) << endl;
1305 return kTRUE;
1306
1307 case kTXT_F3:
1308 cout << "Textview-F3 #" << mp1 << endl;
1309 return kTRUE;
1310
1311 case kTXT_OPEN:
1312 cout << "Textview-Open #" << mp1 << endl;
1313 return kTRUE;
1314
1315 case kTXT_CLOSE:
1316 cout << "Textview-Close #" << mp1 << endl;
1317 return kTRUE;
1318
1319 case kTXT_SAVE:
1320 cout << "Textview-Save #" << mp1 << endl;
1321 return kTRUE;
1322
1323 default:
1324 cout << "Textview: " << "Submsg:" << submsg << " Mp1=" << mp1 << " Mp2=" << mp2 << endl;
1325 }
1326#endif
1327 return kTRUE;
1328}
1329
1330// --------------------------------------------------------------------------
1331//
1332// Process the kC_USER messages
1333//
1334Bool_t MStatusDisplay::ProcessMessageUser(Long_t submsg, Long_t mp1, Long_t mp2)
1335{
1336 // kS_START, case sensitive | backward<<1, char *txt
1337 switch (submsg)
1338 {
1339 case kS_START:
1340 fLogBox->Search((char*)mp2, !(mp1&2>>1), mp1&1);
1341 return kTRUE;
1342#ifdef DEBUG
1343 default:
1344 cout << "User: " << "Submsg:" << submsg << " Mp1=" << mp1 << " Mp2=" << mp2 << endl;
1345#endif
1346 }
1347 return kTRUE;
1348}
1349
1350// --------------------------------------------------------------------------
1351//
1352// Process the messages from the GUI
1353//
1354Bool_t MStatusDisplay::ProcessMessage(Long_t msg, Long_t mp1, Long_t mp2)
1355{
1356 // Can be found in WidgetMessageTypes.h
1357#ifdef DEBUG
1358 cout << "Msg: " << GET_MSG(msg) << " Submsg:" << GET_SUBMSG(msg);
1359 cout << " Mp1=" << mp1 << " Mp2=" << mp2 << endl;
1360#endif
1361 switch (GET_MSG(msg))
1362 {
1363 case kC_COMMAND: // 1
1364 return ProcessMessageCommand(GET_SUBMSG(msg), mp1, mp2);
1365
1366 case kC_TEXTVIEW: // 9
1367 return ProcessMessageTextview(GET_SUBMSG(msg), mp1, mp2);
1368
1369 case kC_USER: // 1001
1370 return ProcessMessageUser(GET_SUBMSG(msg), mp1, mp2);
1371 }
1372#ifdef DEBUG
1373 cout << "Msg: " << GET_MSG(msg) << " Submsg:" << GET_SUBMSG(msg);
1374 cout << " Mp1=" << mp1 << " Mp2=" << mp2 << endl;
1375#endif
1376 return kTRUE;
1377}
1378
1379void MStatusDisplay::CloseWindow()
1380{
1381 // Got close message for this MainFrame. Calls parent CloseWindow()
1382 // (which destroys the window) and terminate the application.
1383 // The close message is generated by the window manager when its close
1384 // window menu item is selected.
1385
1386 // CloseWindow must be overwritten because otherwise CloseWindow
1387 // and the destructor are calling DestroyWindow which seems to be
1388 // in conflict with the TRootEmbeddedCanvas.
1389
1390 // FIXME: Make sure that the Status Display is deleted from every
1391 // where (eg Eventloop) first!
1392
1393 gLog << dbg << "MStatusDisplay is on heap: " << (int)IsOnHeap() << endl;
1394
1395 if (TestBit(kExitLoopOnExit) || TestBit(kExitLoopOnClose))
1396 {
1397 gLog << dbg << "CloseWindow() calling ExitLoop." << endl;
1398 gSystem->ExitLoop();
1399 }
1400
1401 if (fIsLocked<=0 && IsOnHeap())
1402 {
1403 gLog << dbg << "delete MStatusDisplay;" << endl;
1404 delete this;
1405 }
1406 fStatus = kFileExit;
1407 gLog << dbg << "MStatusDisplay.fStatus=kFileExit;" << endl;
1408}
1409
1410// --------------------------------------------------------------------------
1411//
1412// Calls SetBit(kNoContextMenu) for all TCanvas objects found in the
1413// Tabs.
1414//
1415void MStatusDisplay::SetNoContextMenu(Bool_t flag)
1416{
1417 if (fIsLocked>1 || gROOT->IsBatch())
1418 return;
1419
1420 flag ? SetBit(kNoContextMenu) : ResetBit(kNoContextMenu);
1421
1422 for (int i=1; i<fTab->GetNumberOfTabs(); i++)
1423 {
1424 TCanvas *c = GetCanvas(i);
1425 if (c)
1426 flag ? c->SetBit(kNoContextMenu) : c->ResetBit(kNoContextMenu);
1427 }
1428}
1429
1430// --------------------------------------------------------------------------
1431//
1432// Updates the canvas (if existing) in the currenly displayed Tab.
1433// The update intervall is controlled by StartUpdate and StopUpdate
1434//
1435Bool_t MStatusDisplay::HandleTimer(TTimer *timer)
1436{
1437 if (gROOT->IsBatch())
1438 return kTRUE;
1439
1440 const Int_t c = fTab->GetCurrent();
1441
1442 // Skip Legend Tab
1443 if (c==0)
1444 return kTRUE;
1445
1446 // Update a canvas tab (if visible)
1447 if (timer==&fTimer && c!=fLogIdx)
1448 {
1449 UpdateTab(fTab->GetCurrentContainer());
1450 return kTRUE;
1451 }
1452
1453 // update the logbook tab (if visible)
1454 if (timer==&fLogTimer && c==fLogIdx)
1455 {
1456 fLog->UpdateGui();
1457
1458 /*
1459 if (!fLogBox->TestBit(kHasChanged))
1460 return kTRUE;
1461
1462 fLogBox->ResetBit(kHasChanged);
1463 */
1464 return kTRUE;
1465 }
1466
1467 return kTRUE;
1468}
1469
1470// --------------------------------------------------------------------------
1471//
1472// Draws a clone of a canvas into a new canvas. Taken from TCanvas.
1473//
1474void MStatusDisplay::DrawClonePad(TCanvas &newc, const TCanvas &oldc) const
1475{
1476 //copy pad attributes
1477 newc.Range(oldc.GetX1(),oldc.GetY1(),oldc.GetX2(),oldc.GetY2());
1478 newc.SetTickx(oldc.GetTickx());
1479 newc.SetTicky(oldc.GetTicky());
1480 newc.SetGridx(oldc.GetGridx());
1481 newc.SetGridy(oldc.GetGridy());
1482 newc.SetLogx(oldc.GetLogx());
1483 newc.SetLogy(oldc.GetLogy());
1484 newc.SetLogz(oldc.GetLogz());
1485 newc.SetBorderSize(oldc.GetBorderSize());
1486 newc.SetBorderMode(oldc.GetBorderMode());
1487 ((TAttLine&)oldc).Copy((TAttLine&)newc);
1488 ((TAttFill&)oldc).Copy((TAttFill&)newc);
1489 ((TAttPad&)oldc).Copy((TAttPad&)newc);
1490
1491 //copy primitives
1492 TObject *obj;
1493 TIter next(oldc.GetListOfPrimitives());
1494 while ((obj=next())) {
1495 gROOT->SetSelectedPad(&newc);
1496 newc.GetListOfPrimitives()->Add(obj->Clone(),obj->GetDrawOption());
1497 }
1498 newc.Modified();
1499 newc.Update();
1500}
1501
1502// --------------------------------------------------------------------------
1503//
1504// Reads the contents of a saved MStatusDisplay from a file.
1505//
1506Int_t MStatusDisplay::Read(const char *name)
1507{
1508 if (!gFile)
1509 {
1510 *fLog << warn << "MStatusDisplay::Read: No file found. Please create a TFile first." << endl;
1511 return 0;
1512 }
1513
1514 if (!gFile->IsOpen())
1515 {
1516 *fLog << warn << "MStatusDisplay::Read: File not open. Please open the TFile first." << endl;
1517 return 0;
1518 }
1519
1520 TObjArray list;
1521
1522 const Int_t n = list.Read(name);
1523 if (n==0)
1524 {
1525 *fLog << warn << "MStatusDisplay::Read: No objects read." << endl;
1526 return 0;
1527 }
1528
1529 TIter Next(&list);
1530 TCanvas *c;
1531 while ((c=(TCanvas*)Next()))
1532 DrawClonePad(AddTab(c->GetName()), *c);
1533
1534 *fLog << inf << "MStatusDisplay: Key " << name << " with " << n << " keys read from file." << endl;
1535
1536 return n;
1537}
1538
1539// --------------------------------------------------------------------------
1540//
1541// Writes the contents of a MStatusDisplay to a file.
1542//
1543Int_t MStatusDisplay::Write(Int_t num, const char *name, Int_t option, Int_t bufsize)
1544{
1545 if (!gFile)
1546 {
1547 *fLog << warn << "MStatusDisplay::Write: No file found. Please create a TFile first." << endl;
1548 return 0;
1549 }
1550
1551 if (!gFile->IsOpen())
1552 {
1553 *fLog << warn << "MStatusDisplay::Write: File not open. Please open the TFile first." << endl;
1554 return 0;
1555 }
1556
1557 if (!gFile->IsWritable())
1558 {
1559 *fLog << warn << "MStatusDisplay::Write: File not writable." << endl;
1560 return 0;
1561 }
1562
1563 if (num==0)
1564 {
1565 *fLog << warn << "MStatusDisplay::Write: Tab doesn't contain an embedded Canvas... skipped." << endl;
1566 return 0;
1567 }
1568
1569 if (!gROOT->IsBatch() && num>=fTab->GetNumberOfTabs())
1570 {
1571 *fLog << warn << "MStatusDisplay::Write: Tab doesn't exist... skipped." << endl;
1572 return 0;
1573 }
1574 if (gROOT->IsBatch() && num>fBatch->GetSize())
1575 {
1576 *fLog << warn << "MStatusDisplay::Write: Tab doesn't exist... skipped." << endl;
1577 return 0;
1578 }
1579
1580 TObjArray list;
1581
1582 const Int_t max = gROOT->IsBatch() ? fBatch->GetSize()+1 : fTab->GetNumberOfTabs();
1583 const Int_t from = num<0 ? 1 : num;
1584 const Int_t to = num<0 ? max : num+1;
1585
1586 TCanvas *c;
1587 for (int i=from; i<to; i++)
1588 if ((c = GetCanvas(i)))
1589 list.Add(c);
1590
1591 const Int_t n = list.Write(name, kSingleKey);
1592
1593 *fLog << inf << "MStatusDisplay: " << n << " keys written to file as key " << name << "." << endl;
1594
1595 return n;
1596}
1597
1598// --------------------------------------------------------------------------
1599//
1600// Use this to start the synchronous (GUI eventloop driven) tab update.
1601// Can also be used to change the update intervall. If millisec<0
1602// the intervall given in SetUpdateTime is used. If the intervall in
1603// SetUpdateTime is <0 nothing is done. (Call SetUpdateTime(-1) to
1604// disable the automatic update in a MEventloop.
1605//
1606void MStatusDisplay::StartUpdate(Int_t millisec)
1607{
1608 if (fIsLocked>1)
1609 return;
1610
1611 if (fTimer.GetTime()<TTime(0))
1612 return;
1613 fTimer.Start(millisec);
1614}
1615
1616// --------------------------------------------------------------------------
1617//
1618// Stops the automatic GUI update
1619//
1620void MStatusDisplay::StopUpdate()
1621{
1622 if (fIsLocked>1)
1623 return;
1624
1625 fTimer.Stop();
1626}
1627
1628// --------------------------------------------------------------------------
1629//
1630// Set the update interval for the GUI update, see StartUpdate.
1631//
1632void MStatusDisplay::SetUpdateTime(Long_t t)
1633{
1634 fTimer.SetTime(t);
1635}
1636
1637// --------------------------------------------------------------------------
1638//
1639// Set the background color in a canvas
1640//
1641void MStatusDisplay::CanvasSetFillColor(TPad &p, Int_t col) const
1642{
1643 TObject *obj;
1644
1645 // See also TPad::UseCurrentStyle
1646 TIter Next(p.GetListOfPrimitives());
1647 while ((obj=Next()))
1648 {
1649 if (obj->InheritsFrom(TPad::Class()))
1650 CanvasSetFillColor(*(TPad*)obj, col);
1651 if (obj->InheritsFrom(TFrame::Class()))
1652 ((TFrame*)obj)->SetFillColor(col);
1653 }
1654
1655 p.SetFillColor(col);
1656}
1657
1658void MStatusDisplay::AddExtension(TString &name, const TString &ext, Int_t num) const
1659{
1660 if (name.IsNull())
1661 {
1662 name = "status";
1663 if (num>0)
1664 {
1665 name += "-";
1666 name += num;
1667 }
1668 }
1669
1670 if (name.EndsWith("."+ext))
1671 return;
1672
1673 name += ".";
1674 name += ext;
1675}
1676
1677Bool_t MStatusDisplay::CheckTabForCanvas(int num) const
1678{
1679 if (gROOT->IsBatch())
1680 return num>0 && num<=fBatch->GetSize() || num<0;
1681
1682 if (num>=fTab->GetNumberOfTabs())
1683 {
1684 *fLog << warn << "Tab #" << num << " doesn't exist..." << endl;
1685 return kFALSE;
1686 }
1687 if (num==0)
1688 {
1689 *fLog << warn << "Tab #" << num << " doesn't contain an embedded canvas..." << endl;
1690 return kFALSE;
1691 }
1692 if (fTab->GetNumberOfTabs()<2 || !gPad)
1693 {
1694 *fLog << warn << "Sorry, you must have at least one existing canvas (gPad!=NULL)" << endl;
1695 return kFALSE;
1696 }
1697 return kTRUE;
1698}
1699
1700// --------------------------------------------------------------------------
1701//
1702// Insert the following two lines into the postscript header:
1703//
1704// %%DocumentPaperSizes: a4
1705// %%Orientation: Landscape
1706//
1707void MStatusDisplay::UpdatePSHeader(const TString &name) const
1708{
1709 const TString newstr("%%DocumentPaperSizes: a4\n%%Orientation: Landscape\n");
1710 const Int_t l = newstr.Length();
1711
1712 Long_t t[4]; // { id, size, flags, modtime }
1713 gSystem->GetPathInfo(name, t, t+1, t+2, t+3);
1714
1715 char *c[2] = { new char[l], new char[l] };
1716
1717 fstream f(name, ios::in|ios::out);
1718
1719 TString str;
1720 f >> str >> c[0][0]; // Read "%!PS-Adobe-2.0\n" (Mini Header)
1721 f.read(c[0], l);
1722 f.seekp(-l, ios::cur);
1723 f.write(newstr, l);
1724
1725 int i=0;
1726 while (1)
1727 {
1728 f.read(c[(i+1)%2], l);
1729 f.seekp(-l, ios::cur);
1730
1731 if (f)
1732 {
1733 f.write(c[i%2],l);
1734 i++;
1735 i%=2;
1736 continue;
1737 }
1738
1739 const Int_t ssz = str.Length()+1; // Length of Mini-Header
1740 const Int_t block = t[1]-ssz; // Length of block to be shifted
1741 const Int_t size = block%l; // Reminder
1742 const Int_t pos = (block/l)*l + ssz + 1; // Position to start writing
1743
1744 f.clear();
1745 f.seekp(pos);
1746 f.write(c[i%2], l);
1747 f.write(c[(i+1)%2], size);
1748 break;
1749 }
1750
1751 delete c[1];
1752 delete c[0];
1753}
1754
1755// --------------------------------------------------------------------------
1756//
1757// In case of num<0 all tabs are written into the PS file. If num>0
1758// the canvas in the corresponding tab is written to the file.
1759// Name is the name of the file (with or without extension).
1760//
1761// Returns the number of pages written.
1762//
1763// To write all tabs you can also use SaveAsPS(name)
1764//
1765// If the third argument is given a bottom line is drawn with the text
1766// under it.
1767//
1768Int_t MStatusDisplay::SaveAsPS(Int_t num, TString name, const TString addon)
1769{
1770 SetStatusLine1("Writing Postscript file...");
1771 SetStatusLine2("");
1772
1773 if (!CheckTabForCanvas(num))
1774 {
1775 SetStatusLine2("Failed!");
1776 return 0;
1777 }
1778
1779 AddExtension(name, "ps", num);
1780
1781 if (num<0)
1782 *fLog << inf << "Open ps-File: " << name << endl;
1783
1784 TPad *padsav = (TPad*)gPad;
1785 TVirtualPS *psave = gVirtualPS;
1786
1787 TDatime d;
1788
1789 TPostScript ps(name, 112);
1790 ps.SetBit(TPad::kPrintingPS);
1791 ps.PrintFast(13, "/nan {1} def ");
1792
1793 gVirtualPS = &ps;
1794
1795 //
1796 // Create a list to delete the canvas clones
1797 //
1798 TList l;
1799 l.SetOwner();
1800
1801 //
1802 // Create some GUI elements for a page legend
1803 //
1804 TLine line;
1805
1806 int page = 1;
1807
1808 //
1809 // Maintain tab numbers
1810 //
1811 const Int_t max = gROOT->IsBatch() ? fBatch->GetSize()+1 : fTab->GetNumberOfTabs();
1812 const Int_t from = num<0 ? 1 : num;
1813 const Int_t to = num<0 ? max : num+1;
1814
1815 for (int i=from; i<to; i++)
1816 {
1817 TCanvas *c;
1818 if (!(c = GetCanvas(i)))
1819 {
1820 if (num<0)
1821 *fLog << inf << " - ";
1822 *fLog << "Tab #" << i << " doesn't contain an embedded Canvas... skipped." << endl;
1823 continue;
1824 }
1825
1826 SetStatusLine2(Form("Tab #%d", i));
1827
1828 //
1829 // Init page and page size, make sure, that the canvas in the file
1830 // has the same Aspect Ratio than on the screen.
1831 //
1832 ps.NewPage();
1833
1834 //
1835 // 28 is used here to scale the canvas into a height of 28,
1836 // such that the page title can be set above the canvas...
1837 //
1838 Float_t psw = 28.0; // A4 - width (29.7)
1839 Float_t psh = 21.0; // A4 - height (21.0)
1840
1841 const Float_t cw = c->GetWw();
1842 const Float_t ch = c->GetWh();
1843
1844 if (psw/psh>cw/ch)
1845 psw = cw/ch*psh;
1846 else
1847 psh = ch/cw*psw;
1848
1849 ps.Range(psw, psh); // A4
1850
1851 //
1852 // Clone canvas and change background color and schedule for
1853 // deletion
1854 //
1855 TCanvas *n = (TCanvas*)c->Clone();
1856 CanvasSetFillColor(*n, kWhite);
1857 l.Add(n);
1858
1859 //
1860 // Paint canvas into root file
1861 //
1862 if (num<0)
1863 *fLog << inf << " - ";
1864 *fLog << inf << "Writing Tab #" << i << ": " << c->GetName() << " (" << c << ") ";
1865 if (num>0)
1866 *fLog << "to " << name;
1867 *fLog << "..." << flush;
1868
1869 n->SetBatch(kTRUE);
1870 n->Paint();
1871
1872 //
1873 // Use the canvas as coordinate system for the overlaying text
1874 //
1875 gPad = n;
1876
1877 //
1878 // Print overlaying text (NDC = %)
1879 //
1880 ps.SetTextColor(kBlack);
1881 ps.SetTextSize(0.015);
1882 ps.SetTextFont(22);
1883 ps.SetTextAlign(11); // left top
1884 ps.TextNDC(0, 1.015, TString(" ")+n->GetName());
1885 ps.SetTextAlign(21); // cent top
1886 ps.TextNDC(0.5, 1.015, TString("MARS - Magic Analysis and Reconstruction Software - ")+d.AsString());
1887 ps.SetTextAlign(31); // right top
1888 ps.TextNDC(1, 1.015, Form("Page No.%i (%i) ", page++, i));
1889 line.PaintLineNDC(0, 1.01, 1, 1.01);
1890
1891 if (!addon.IsNull())
1892 {
1893 line.PaintLineNDC(0, -0.00, 1, -0.00);
1894 ps.SetTextAlign(23); // cent bottom
1895 ps.TextNDC(0.5, -0.005, addon);
1896 }
1897
1898 //
1899 // Finish drawing page
1900 //
1901 n->SetBatch(kFALSE);
1902 if (num<0)
1903 *fLog << "done." << endl;
1904 }
1905
1906 gPad = NULL; // Important!
1907 l.Delete();
1908
1909 ps.Close();
1910 UpdatePSHeader(name);
1911
1912 gVirtualPS = psave;
1913 if (padsav)
1914 padsav->cd();
1915
1916 *fLog << inf << "done." << endl;
1917
1918 SetStatusLine2(Form("Done (%dpages)", page-1));
1919
1920 return page-1;
1921}
1922
1923Bool_t MStatusDisplay::SaveAsGIF(Int_t num, TString name)
1924{
1925 if (gROOT->IsBatch())
1926 {
1927 *fLog << warn << "Sorry, writing gif-files is not available in batch mode." << endl;
1928 return 0;
1929 }
1930 SetStatusLine1("Writing GIF file...");
1931 SetStatusLine2("");
1932
1933 if (!CheckTabForCanvas(num))
1934 {
1935 SetStatusLine2("Failed!");
1936 return 0;
1937 }
1938
1939 AddExtension(name, "gif", num);
1940
1941 if (num<0)
1942 *fLog << inf << "Writing gif-Files..." << endl;
1943
1944 TPad *padsav = (TPad*)gPad;
1945
1946 int page = 1;
1947
1948 //
1949 // Maintain tab numbers
1950 //
1951 const Int_t from = num<0 ? 1 : num;
1952 const Int_t to = num<0 ? fTab->GetNumberOfTabs() : num+1;
1953
1954 for (int i=from; i<to; i++)
1955 {
1956 TCanvas *c;
1957 if (!(c = GetCanvas(i)))
1958 {
1959 if (num<0)
1960 *fLog << inf << " - ";
1961 *fLog << "Tab #" << i << " doesn't contain an embedded Canvas... skipped." << endl;
1962 continue;
1963 }
1964
1965 SetStatusLine2(Form("Tab #%d", i));
1966
1967 //
1968 // Clone canvas and change background color and schedule for
1969 // deletion
1970 //
1971 //TCanvas *n = (TCanvas*)c->Clone();
1972 //CanvasSetFillColor(*n, kWhite);
1973
1974 //
1975 // Paint canvas into root file
1976 //
1977 TString writename = name;
1978 if (num<0)
1979 {
1980 TString numname = "-";
1981 numname += i;
1982 writename.Insert(name.Last('.'), numname);
1983 }
1984 if (num<0)
1985 *fLog << inf << " - ";
1986 *fLog << inf << "Writing Tab #" << i << " to " << writename << ": " << c->GetName() << " (" << c << ") ";
1987 if (num>0)
1988 *fLog << "to " << name;
1989 *fLog << "..." << flush;
1990
1991 c->Draw();
1992 c->SaveAs(writename);
1993 /*
1994 n->Draw();
1995 n->SaveAs(writename);
1996 delete n;
1997 */
1998
1999 if (num<0)
2000 *fLog << "done." << endl;
2001 }
2002
2003 padsav->cd();
2004
2005 *fLog << inf << "done." << endl;
2006
2007 SetStatusLine2("Done.");
2008
2009 return page-1;
2010}
2011
2012Bool_t MStatusDisplay::SaveAsC(Int_t num, TString name)
2013{
2014 SetStatusLine1("Writing C++ file...");
2015 SetStatusLine2("");
2016
2017 if (!CheckTabForCanvas(num))
2018 {
2019 SetStatusLine2("Failed!");
2020 return 0;
2021 }
2022
2023 AddExtension(name, "C", num);
2024
2025 if (num<0)
2026 *fLog << inf << "Writing C-Files..." << endl;
2027
2028 TPad *padsav = (TPad*)gPad;
2029
2030 int page = 1;
2031
2032 //
2033 // Maintain tab numbers
2034 //
2035 const Int_t from = num<0 ? 1 : num;
2036 const Int_t to = num<0 ? fTab->GetNumberOfTabs() : num+1;
2037
2038 for (int i=from; i<to; i++)
2039 {
2040 TCanvas *c;
2041 if (!(c = GetCanvas(i)))
2042 {
2043 if (num<0)
2044 *fLog << inf << " - ";
2045 *fLog << "Tab #" << i << " doesn't contain an embedded Canvas... skipped." << endl;
2046 continue;
2047 }
2048
2049 SetStatusLine2(Form("Tab #%d", i));
2050
2051 //
2052 // Clone canvas and change background color and schedule for
2053 // deletion
2054 //
2055 TCanvas *n = (TCanvas*)c->Clone();
2056 CanvasSetFillColor(*n, kWhite);
2057
2058 //
2059 // Paint canvas into root file
2060 //
2061 TString writename = name;
2062 if (num<0)
2063 {
2064 TString numname = "-";
2065 numname += i;
2066 writename.Insert(name.Last('.'), numname);
2067 }
2068 if (num<0)
2069 *fLog << inf << " - ";
2070 *fLog << inf << "Writing Tab #" << i << " to " << writename << ": " << c->GetName() << " (" << n << ") ";
2071 if (num>0)
2072 *fLog << "to " << name;
2073 *fLog << "..." << flush;
2074
2075 n->SaveSource(writename, "");
2076 delete n;
2077
2078 if (num<0)
2079 *fLog << "done." << endl;
2080 }
2081
2082 padsav->cd();
2083
2084 *fLog << inf << "done." << endl;
2085
2086 SetStatusLine2("Done.");
2087
2088 return page-1;
2089}
2090
2091// --------------------------------------------------------------------------
2092//
2093// In case of num<0 all tabs are written into the PS file. If num>0
2094// the canvas in the corresponding tab is written to the file.
2095// Name is the name of the file (with or without extension).
2096//
2097// Returns the number of keys written.
2098//
2099// To write all tabs you can also use SaveAsPS(name)
2100//
2101Int_t MStatusDisplay::SaveAsRoot(Int_t num, TString name)
2102{
2103 SetStatusLine1("Writing root file...");
2104 SetStatusLine2("");
2105
2106 if (!CheckTabForCanvas(num))
2107 {
2108 SetStatusLine2("Failed!");
2109 return 0;
2110 }
2111
2112 AddExtension(name, "root", num);
2113
2114 TFile *fsave = gFile;
2115 TFile file(name, "RECREATE", "MARS - Status Window Contents", 9);
2116 const Int_t keys = Write(num);
2117 gFile = fsave;
2118
2119 SetStatusLine2("Done.");
2120
2121 return keys;
2122}
2123
2124Bool_t MStatusDisplay::HandleConfigureNotify(Event_t *evt)
2125{
2126 //
2127 // The initialization of the GUI is not yet enough finished...
2128 //
2129 if (!fTab)
2130 return kTRUE;
2131
2132 UInt_t w = evt->fWidth;
2133 UInt_t h = evt->fHeight;
2134
2135 /*
2136 cout << "Old: " << GetWidth() << " " << GetHeight() << " " << GetBorderWidth() << endl;
2137 cout << "New: " << w << " " << h << " ";
2138 cout << "New: " << GetDefaultWidth() << " " << GetDefaultHeight() << " " << endl;
2139 */
2140
2141 Bool_t wchanged = w!=GetWidth();
2142 Bool_t hchanged = h!=GetHeight();
2143
2144 if (!wchanged && !hchanged)
2145 {
2146 Layout();
2147 // FIXME: Make sure that this doesn't result in endless loops.
2148 return kTRUE;
2149 }
2150
2151
2152 if (GetWidth()==1 && GetHeight()==1)
2153 return kTRUE;
2154
2155 // calculate the constant part of the window
2156 const UInt_t cw = GetWidth() -fTab->GetWidth();
2157 const UInt_t ch = GetHeight()-fTab->GetHeight();
2158
2159 // calculate new size of frame (canvas @ 1:sqrt(2))
2160 if (hchanged)
2161 w = (UInt_t)((h-ch)*sqrt(2.)+.5)+cw;
2162 else
2163 h = (UInt_t)((w-cw)/sqrt(2.)+.5)+ch;
2164
2165 // resize frame
2166 Resize(w, h);
2167
2168 return kTRUE;
2169}
2170
2171Bool_t MStatusDisplay::HandleEvent(Event_t *event)
2172{
2173 Bool_t rc = TGMainFrame::HandleEvent(event);
2174
2175 //
2176 // This fixes a bug in older root versions which makes
2177 // TCanvas crash if gPad==NULL. So we make sure, that
2178 // gPad!=NULL -- be carfull, this may have other side
2179 // effects.
2180 //
2181#if ROOT_VERSION_CODE < ROOT_VERSION(3,10,01)
2182 if (!gPad && fTab)
2183 for (int i=0; i<fTab->GetNumberOfTabs(); i++)
2184 {
2185 TCanvas *c = GetCanvas(i);
2186 if (c)
2187 {
2188 c->cd();
2189 gLog << dbg << "MStatusDisplay::HandleEvent - Workaround: gPad=" << gPad << "." << endl;
2190 break;
2191 }
2192 }
2193#endif
2194
2195 return rc;
2196}
2197
2198/*
2199 // --------------------------------------------------------------------------
2200//
2201// Opens a save as dialog, and tries to store the canvas
2202// in the given output format
2203//
2204void MGEvtDisplay::SaveAsDialog() const
2205{
2206 static const char *gSaveAsTypes[] =
2207 {
2208 "PostScript", "*.ps",
2209 "Encapsulated PostScript", "*.eps",
2210 "Gif files", "*.gif",
2211 "Macro files", "*.C",
2212 "ROOT files", "*.root",
2213 "All files", "*",
2214 NULL, NULL
2215 };
2216
2217 static TString dir(".");
2218
2219 TGFileInfo fi; // fFileName and fIniDir deleted in ~TGFileInfo
2220
2221 fi.fFileTypes = (const char**)gSaveAsTypes;
2222 fi.fIniDir = StrDup(dir);
2223
2224 new TGFileDialog(fClient->GetRoot(), this, kFDSave, &fi);
2225
2226 if (!fi.fFilename)
2227 return;
2228
2229 dir = fi.fIniDir;
2230
2231 if (strstr(fi.fFilename, ".root") ||
2232 strstr(fi.fFilename, ".ps") ||
2233 strstr(fi.fFilename, ".eps") ||
2234 strstr(fi.fFilename, ".gif"))
2235 {
2236 fCanvas->SaveAs(fi.fFilename);
2237 return;
2238 }
2239 if (strstr(fi.fFilename, ".C"))
2240 {
2241 fCanvas->SaveSource(fi.fFilename);
2242 return;
2243 }
2244 Warning("SaveAsDialog", "Unknown Extension: %s", fi.fFilename);
2245}
2246*/
Note: See TracBrowser for help on using the repository browser.