Logo ROOT   6.10/09
Reference Guide
TPad.cxx
Go to the documentation of this file.
1 // @(#)root/gpad:$Id$
2 // Author: Rene Brun 12/12/94
3 
4 /*************************************************************************
5  * Copyright (C) 1995-2000, Rene Brun and Fons Rademakers. *
6  * All rights reserved. *
7  * *
8  * For the licensing terms see $ROOTSYS/LICENSE. *
9  * For the list of contributors see $ROOTSYS/README/CREDITS. *
10  *************************************************************************/
11 
12 #include <string.h>
13 #include <stdlib.h>
14 
15 #include "Riostream.h"
16 #include "TROOT.h"
17 #include "TError.h"
18 #include "TMath.h"
19 #include "TSystem.h"
20 #include "TStyle.h"
21 #include "TH1.h"
22 #include "TH2.h"
23 #include "TH3.h"
24 #include "TClass.h"
25 #include "TBaseClass.h"
26 #include "TClassTable.h"
27 #include "TVirtualPS.h"
28 #include "TVirtualX.h"
29 #include "TVirtualViewer3D.h"
30 #include "TView.h"
31 #include "TPoint.h"
32 #include "TGraph.h"
33 #include "TMultiGraph.h"
34 #include "THStack.h"
35 #include "TPaveText.h"
36 #include "TPaveStats.h"
37 #include "TGroupButton.h"
38 #include "TBrowser.h"
39 #include "TVirtualGL.h"
40 #include "TString.h"
41 #include "TDataMember.h"
42 #include "TMethod.h"
43 #include "TDataType.h"
44 #include "TRealData.h"
45 #include "TFrame.h"
46 #include "TExec.h"
47 #include "TDatime.h"
48 #include "TColor.h"
49 #include "TCanvas.h"
50 #include "TPluginManager.h"
51 #include "TEnv.h"
52 #include "TImage.h"
53 #include "TViewer3DPad.h"
54 #include "TBuffer3D.h"
55 #include "TBuffer3DTypes.h"
56 #include "TCreatePrimitives.h"
57 #include "TLegend.h"
58 #include "TAtt3D.h"
59 #include "TObjString.h"
60 #include "TApplication.h"
61 #include "TVirtualPadPainter.h"
62 
63 #include "TVirtualMutex.h"
64 
65 static Int_t gReadLevel = 0;
66 
68 
70 
71 /** \class TPad
72 \ingroup gpad
73 
74 The most important graphics class in the ROOT system.
75 
76 A Pad is contained in a Canvas.
77 
78 A Pad may contain other pads (unlimited pad hierarchy).
79 
80 A pad is a linked list of primitives of any type (graphics objects,
81 histograms, detectors, tracks, etc.).
82 
83 Adding a new element into a pad is in general performed by the Draw
84 member function of the object classes.
85 
86 It is important to realize that the pad is a linked list of references
87 to the original object.
88 For example, in case of a histogram, the histogram.Draw() operation
89 only stores a reference to the histogram object and not a graphical
90 representation of this histogram.
91 When the mouse is used to change (say the bin content), the bin content
92 of the original histogram is changed.
93 
94 The convention used in ROOT is that a Draw operation only adds
95 a reference to the object. The effective drawing is performed
96 when the canvas receives a signal to be painted.
97 
98 \image html gpad_pad1.png
99 
100 This signal is generally sent when typing carriage return in the
101 command input or when a graphical operation has been performed on one
102 of the pads of this canvas.
103 When a Canvas/Pad is repainted, the member function Paint for all
104 objects in the Pad linked list is invoked.
105 
106 \image html gpad_pad2.png
107 
108 When the mouse is moved on the Pad, The member function DistancetoPrimitive
109 is called for all the elements in the pad. DistancetoPrimitive returns
110 the distance in pixels to this object.
111 
112 When the object is within the distance window, the member function
113 ExecuteEvent is called for this object.
114 
115 In ExecuteEvent, move, changes can be performed on the object.
116 
117 For examples of DistancetoPrimitive and ExecuteEvent functions,
118 see classes
119 ~~~ {.cpp}
120  TLine::DistancetoPrimitive, TLine::ExecuteEvent
121  TBox::DistancetoPrimitive, TBox::ExecuteEvent
122  TH1::DistancetoPrimitive, TH1::ExecuteEvent
123 ~~~
124 A Pad supports linear and log scales coordinate systems.
125 The transformation coefficients are explained in TPad::ResizePad.
126 */
127 
128 ////////////////////////////////////////////////////////////////////////////////
129 /// Pad default constructor.
130 
132 {
133  fModified = kTRUE;
134  fTip = 0;
135  fPadPointer = 0;
136  fPrimitives = 0;
137  fExecs = 0;
138  fCanvas = 0;
139  fPadPaint = 0;
140  fPixmapID = -1;
141  fGLDevice = -1;
142  fCopyGLDevice = kFALSE;
143  fEmbeddedGL = kFALSE;
144  fTheta = 30;
145  fPhi = 30;
146  fNumber = 0;
147  fAbsCoord = kFALSE;
148  fEditable = kTRUE;
149  fCrosshair = 0;
150  fCrosshairPos = 0;
151  fPadView3D = 0;
152  fMother = (TPad*)gPad;
153 
154  fAbsHNDC = 0.;
155  fAbsPixeltoXk = 0.;
156  fAbsPixeltoYk = 0.;
157  fAbsWNDC = 0.;
158  fAbsXlowNDC = 0.;
159  fAbsYlowNDC = 0.;
160  fBorderMode = 0;
161  fBorderSize = 0;
162  fPixeltoX = 0;
163  fPixeltoXk = 0.;
164  fPixeltoY = 0.;
165  fPixeltoYk = 0.;
166  fUtoAbsPixelk = 0.;
167  fUtoPixel = 0.;
168  fUtoPixelk = 0.;
169  fVtoAbsPixelk = 0.;
170  fVtoPixel = 0.;
171  fVtoPixelk = 0.;
172  fXtoAbsPixelk = 0.;
173  fXtoPixel = 0.;
174  fXtoPixelk = 0.;
175  fYtoAbsPixelk = 0.;
176  fYtoPixel = 0.;
177  fYtoPixelk = 0.;
178  fXUpNDC = 0.;
179  fYUpNDC = 0.;
180 
181  fFixedAspectRatio = kFALSE;
182  fAspectRatio = 0.;
183 
184  fNumPaletteColor = 0;
185  fNextPaletteColor = 0;
186  fCollideGrid = 0;
187  fCGnx = 0;
188  fCGny = 0;
189 
190  fLogx = 0;
191  fLogy = 0;
192  fLogz = 0;
193  fGridx = 0;
194  fGridy = 0;
195  fTickx = 0;
196  fTicky = 0;
197  fFrame = 0;
198  fView = 0;
199 
200  fUxmin = fUymin = fUxmax = fUymax = 0;
201 
202  // Set default world coordinates to NDC [0,1]
203  fX1 = 0;
204  fX2 = 1;
205  fY1 = 0;
206  fY2 = 1;
207 
208  // Set default pad range
209  fXlowNDC = 0;
210  fYlowNDC = 0;
211  fWNDC = 1;
212  fHNDC = 1;
213 
214  fViewer3D = 0;
215  SetBit(kMustCleanup);
216 
217  // the following line is temporarily disabled. It has side effects
218  // when the pad is a TDrawPanelHist or a TFitPanel.
219  // the line was supposed to fix a problem with DrawClonePad
220  // gROOT->SetSelectedPad(this);
221 }
222 
223 ////////////////////////////////////////////////////////////////////////////////
224 /// Pad constructor.
225 ///
226 /// A pad is a linked list of primitives.
227 /// A pad is contained in a canvas. It may contain other pads.
228 /// A pad has attributes. When a pad is created, the attributes
229 /// defined in the current style are copied to the pad attributes.
230 ///
231 /// \param[in] name pad name
232 /// \param[in] title pad title
233 /// \param[in] xlow [0,1] is the position of the bottom left point of the pad
234 /// expressed in the mother pad reference system
235 /// \param[in] ylow [0,1] is the Y position of this point.
236 /// \param[in] xup [0,1] is the x position of the top right point of the pad
237 /// expressed in the mother pad reference system
238 /// \param[in] yup [0,1] is the Y position of this point.
239 /// \param[in] color pad color
240 /// \param[in] bordersize border size in pixels
241 /// \param[in] bordermode border mode
242 /// - bordermode = -1 box looks as it is behind the screen
243 /// - bordermode = 0 no special effects
244 /// - bordermode = 1 box looks as it is in front of the screen
245 
246 TPad::TPad(const char *name, const char *title, Double_t xlow,
247  Double_t ylow, Double_t xup, Double_t yup,
248  Color_t color, Short_t bordersize, Short_t bordermode)
249  : TVirtualPad(name,title,xlow,ylow,xup,yup,color,bordersize,bordermode)
250 {
251  fModified = kTRUE;
252  fTip = 0;
253  fBorderSize = bordersize;
254  fBorderMode = bordermode;
255  if (gPad) fCanvas = gPad->GetCanvas();
256  else fCanvas = (TCanvas*)this;
257  fMother = (TPad*)gPad;
258  fPrimitives = new TList;
259  fExecs = new TList;
260  fPadPointer = 0;
261  fTheta = 30;
262  fPhi = 30;
267  fFrame = 0;
268  fView = 0;
269  fPadPaint = 0;
270  fPadView3D = 0;
271  fPixmapID = -1; // -1 means pixmap will be created by ResizePad()
274  fNumber = 0;
275  fAbsCoord = kFALSE;
276  fEditable = kTRUE;
277  fCrosshair = 0;
278  fCrosshairPos = 0;
279 
280  fVtoAbsPixelk = 0.;
281  fVtoPixelk = 0.;
282  fVtoPixel = 0.;
283  fAbsPixeltoXk = 0.;
284  fPixeltoXk = 0.;
285  fPixeltoX = 0;
286  fAbsPixeltoYk = 0.;
287  fPixeltoYk = 0.;
288  fPixeltoY = 0.;
289  fXlowNDC = 0;
290  fYlowNDC = 0;
291  fWNDC = 1;
292  fHNDC = 1;
293  fXUpNDC = 0.;
294  fYUpNDC = 0.;
295  fAbsXlowNDC = 0.;
296  fAbsYlowNDC = 0.;
297  fAbsWNDC = 0.;
298  fAbsHNDC = 0.;
299  fUxmin = fUymin = fUxmax = fUymax = 0;
300  fLogx = gStyle->GetOptLogx();
301  fLogy = gStyle->GetOptLogy();
302  fLogz = gStyle->GetOptLogz();
303 
305  fAspectRatio = 0.;
306 
307  fNumPaletteColor = 0;
308  fNextPaletteColor = 0;
309  fCollideGrid = 0;
310  fCGnx = 0;
311  fCGny = 0;
312 
313  fViewer3D = 0;
314 
316  // Set default world coordinates to NDC [0,1]
317  fX1 = 0;
318  fX2 = 1;
319  fY1 = 0;
320  fY2 = 1;
321 
322  if (!gPad) {
323  Error("TPad", "You must create a TCanvas before creating a TPad");
324  MakeZombie();
325  return;
326  }
327 
328  TPad *padsav = (TPad*)gPad;
329 
330  if ((xlow < 0) || (xlow > 1) || (ylow < 0) || (ylow > 1)) {
331  Error("TPad", "illegal bottom left position: x=%f, y=%f", xlow, ylow);
332  goto zombie;
333  }
334  if ((xup < 0) || (xup > 1) || (yup < 0) || (yup > 1)) {
335  Error("TPad", "illegal top right position: x=%f, y=%f", xup, yup);
336  goto zombie;
337  }
338 
339  fLogx = gStyle->GetOptLogx();
340  fLogy = gStyle->GetOptLogy();
341  fLogz = gStyle->GetOptLogz();
342 
343  fUxmin = fUymin = fUxmax = fUymax = 0;
344 
345  // Set pad parameters and Compute conversion coefficients
346  SetPad(name, title, xlow, ylow, xup, yup, color, bordersize, bordermode);
347  Range(0, 0, 1, 1);
350 
351  padsav->cd();
352  return;
353 
354 zombie:
355  // error in creating pad occurred, make this pad a zombie
356  MakeZombie();
357  padsav->cd();
358 }
359 
360 
361 ////////////////////////////////////////////////////////////////////////////////
362 /// Pad destructor.
363 
365 {
366  if (!TestBit(kNotDeleted)) return;
367  Close();
372  delete fViewer3D;
373  if (fCollideGrid) delete [] fCollideGrid;
374 }
375 
376 ////////////////////////////////////////////////////////////////////////////////
377 /// Add a new TExec object to the list of Execs.
378 ///
379 /// When an event occurs in the pad (mouse click, etc) the list of C++ commands
380 /// in the list of Execs are executed via TPad::AutoExec.
381 ///
382 /// When a pad event occurs (mouse move, click, etc) all the commands
383 /// contained in the fExecs list are executed in the order found in the list.
384 ///
385 /// This facility is activated by default. It can be deactivated by using
386 /// the canvas "Option" menu.
387 ///
388 /// The following examples of TExec commands are provided in the tutorials:
389 /// macros exec1.C and exec2.C.
390 ///
391 /// ### Example1 of use of exec1.C
392 /// ~~~ {.cpp}
393 /// Root > TFile f("hsimple.root")
394 /// Root > hpx.Draw()
395 /// Root > c1.AddExec("ex1",".x exec1.C")
396 /// ~~~
397 ///
398 /// At this point you can use the mouse to click on the contour of
399 /// the histogram hpx. When the mouse is clicked, the bin number and its
400 /// contents are printed.
401 ///
402 /// ### Example2 of use of exec1.C
403 /// ~~~ {.cpp}
404 /// Root > TFile f("hsimple.root")
405 /// Root > hpxpy.Draw()
406 /// Root > c1.AddExec("ex2",".x exec2.C")
407 /// ~~~
408 ///
409 /// When moving the mouse in the canvas, a second canvas shows the
410 /// projection along X of the bin corresponding to the Y position
411 /// of the mouse. The resulting histogram is fitted with a gaussian.
412 /// A "dynamic" line shows the current bin position in Y.
413 /// This more elaborated example can be used as a starting point
414 /// to develop more powerful interactive applications exploiting the C++
415 /// interpreter as a development engine.
416 
417 void TPad::AddExec(const char *name, const char*command)
418 {
419  if (!fExecs) fExecs = new TList;
420  TExec *ex = new TExec(name,command);
421  fExecs->Add(ex);
422 }
423 
424 ////////////////////////////////////////////////////////////////////////////////
425 /// Execute the list of Execs when a pad event occurs.
426 
428 {
429  if (GetCrosshair()) DrawCrosshair();
430 
431  if (!fExecs) fExecs = new TList;
432  TIter next(fExecs);
433  TExec *exec;
434  while ((exec = (TExec*)next())) {
435  exec->Exec();
436  }
437 }
438 
439 ////////////////////////////////////////////////////////////////////////////////
440 /// Browse pad.
441 
443 {
444  cd();
445  if (fPrimitives) fPrimitives->Browse(b);
446 }
447 
448 ////////////////////////////////////////////////////////////////////////////////
449 /// Build a legend from the graphical objects in the pad.
450 ///
451 /// A simple method to build automatically a TLegend from the primitives in a TPad.
452 ///
453 /// Only those deriving from TAttLine, TAttMarker and TAttFill are added, excluding
454 /// TPave and TFrame derived classes.
455 ///
456 /// \param[in] x1, y1, x2, y2 The TLegend coordinates
457 /// \param[in] title The legend title. By default it is " "
458 /// \param[in] option The TLegend option
459 ///
460 /// The caller program owns the returned TLegend.
461 ///
462 /// If the pad contains some TMultiGraph or THStack the individual
463 /// graphs or histograms in them are added to the TLegend.
464 
466  const char* title, Option_t *option)
467 {
468  TList *lop=GetListOfPrimitives();
469  if (!lop) return 0;
470  TLegend *leg=0;
471  TIter next(lop);
472  TString mes;
473  TObject *o=0;
474  TString opt("");
475  while( (o=next()) ) {
477  o->InheritsFrom(TAttFill::Class())) &&
478  ( !(o->InheritsFrom(TFrame::Class())) && !(o->InheritsFrom(TPave::Class())) )) {
479  if (!leg) leg = new TLegend(x1, y1, x2, y2, title);
480  if (o->InheritsFrom(TNamed::Class()) && strlen(((TNamed *)o)->GetTitle()))
481  mes = ((TNamed *)o)->GetTitle();
482  else if (strlen(o->GetName()))
483  mes = o->GetName();
484  else
485  mes = o->ClassName();
486  if (strlen(option)) {
487  opt = option;
488  } else {
489  if (o->InheritsFrom(TAttLine::Class())) opt += "l";
490  if (o->InheritsFrom(TAttMarker::Class())) opt += "p";
491  if (o->InheritsFrom(TAttFill::Class())) opt += "f";
492  }
493  leg->AddEntry(o,mes.Data(),opt.Data());
494  } else if ( o->InheritsFrom(TMultiGraph::Class() ) ) {
495  if (!leg) leg = new TLegend(x1, y1, x2, y2, title);
496  TList * grlist = ((TMultiGraph *)o)->GetListOfGraphs();
497  TIter nextgraph(grlist);
498  TGraph * gr;
499  TObject * obj;
500  while ((obj = nextgraph())) {
501  gr = (TGraph*) obj;
502  if (strlen(gr->GetTitle())) mes = gr->GetTitle();
503  else if (strlen(gr->GetName())) mes = gr->GetName();
504  else mes = gr->ClassName();
505  if (strlen(option)) opt = option;
506  else opt = "lpf";
507  leg->AddEntry( obj, mes.Data(), opt );
508  }
509  } else if ( o->InheritsFrom(THStack::Class() ) ) {
510  if (!leg) leg = new TLegend(x1, y1, x2, y2, title);
511  TList * hlist = ((THStack *)o)->GetHists();
512  TIter nexthist(hlist);
513  TH1 * hist;
514  TObject * obj;
515  while ((obj = nexthist())) {
516  hist = (TH1*) obj;
517  if (strlen(hist->GetTitle())) mes = hist->GetTitle();
518  else if (strlen(hist->GetName())) mes = hist->GetName();
519  else mes = hist->ClassName();
520  if (strlen(option)) opt = option;
521  else opt = "lpf";
522  leg->AddEntry( obj, mes.Data(), opt );
523  }
524  }
525  }
526  if (leg) {
527  TVirtualPad *gpadsave;
528  gpadsave = gPad;
529  this->cd();
530  leg->Draw();
531  gpadsave->cd();
532  } else {
533  Info("BuildLegend(void)","No object to build a TLegend.");
534  }
535  return leg;
536 }
537 
538 ////////////////////////////////////////////////////////////////////////////////
539 /// Set Current pad.
540 ///
541 /// When a canvas/pad is divided via TPad::Divide, one can directly
542 /// set the current path to one of the subdivisions.
543 /// See TPad::Divide for the convention to number sub-pads.
544 ///
545 /// Returns the new current pad, or 0 in case of failure.
546 ///
547 /// For example:
548 /// ~~~ {.cpp}
549 /// c1.Divide(2,3); // create 6 pads (2 divisions along x, 3 along y).
550 /// ~~~
551 /// To set the current pad to the bottom right pad, do
552 /// ~~~ {.cpp}
553 /// c1.cd(6);
554 /// ~~~
555 /// Note1: c1.cd() is equivalent to c1.cd(0) and sets the current pad
556 /// to c1 itself.
557 ///
558 /// Note2: after a statement like c1.cd(6), the global variable gPad
559 /// points to the current pad. One can use gPad to set attributes
560 /// of the current pad.
561 ///
562 /// Note3: One can get a pointer to one of the sub-pads of pad with:
563 /// TPad *subpad = (TPad*)pad->GetPad(subpadnumber);
564 
565 TVirtualPad *TPad::cd(Int_t subpadnumber)
566 {
567  if (!subpadnumber) {
568  gPad = this;
569  if (!gPad->IsBatch() && GetPainter()) GetPainter()->SelectDrawable(fPixmapID);
570  return gPad;
571  }
572 
573  TObject *obj;
574  if (!fPrimitives) fPrimitives = new TList;
575  TIter next(fPrimitives);
576  while ((obj = next())) {
577  if (obj->InheritsFrom(TPad::Class())) {
578  Int_t n = ((TPad*)obj)->GetNumber();
579  if (n == subpadnumber) {
580  return ((TPad*)obj)->cd();
581  }
582  }
583  }
584  return 0;
585 }
586 
587 ////////////////////////////////////////////////////////////////////////////////
588 /// Delete all pad primitives.
589 ///
590 /// If the bit kClearAfterCR has been set for this pad, the Clear function
591 /// will execute only after having pressed a CarriageReturn
592 /// Set the bit with `mypad->SetBit(TPad::kClearAfterCR)`
593 
594 void TPad::Clear(Option_t *option)
595 {
596  if (!IsEditable()) return;
597 
599 
600  if (!fPadPaint) {
601  SafeDelete(fView);
602  if (fPrimitives) fPrimitives->Clear(option);
603  if (fFrame) {
604  if (fFrame->TestBit(kNotDeleted)) delete fFrame;
605  fFrame = 0;
606  }
607  }
608  if (fCanvas) fCanvas->Cleared(this);
609 
610  cd();
611 
612  if (TestBit(kClearAfterCR)) {
613  // Intentional do not use the return value of getchar,
614  // we just want to get it and forget it
615  getchar();
616  }
617 
618  if (!gPad->IsBatch()) GetPainter()->ClearDrawable();
619  if (gVirtualPS && gPad == gPad->GetCanvas()) gVirtualPS->NewPage();
620 
622  fCrosshairPos = 0;
623  fNumPaletteColor = 0;
624  if (fCollideGrid) {
625  delete [] fCollideGrid;
626  fCollideGrid = 0;
627  fCGnx = 0;
628  fCGny = 0;
629  }
631 }
632 
633 ////////////////////////////////////////////////////////////////////////////////
634 /// Clipping routine: Cohen Sutherland algorithm.
635 ///
636 /// - If Clip ==2 the segment is outside the boundary.
637 /// - If Clip ==1 the segment has one point outside the boundary.
638 /// - If Clip ==0 the segment is inside the boundary.
639 ///
640 /// \param[in] x[],y[] Segment coordinates (2 points)
641 /// \param[in] xclipl,yclipb,xclipr,yclipt Clipping boundary
642 /// \param[out] x[],y[] New segment coordinates( 2 points)
643 
644 Int_t TPad::Clip(Float_t *x, Float_t *y, Float_t xclipl, Float_t yclipb, Float_t xclipr, Float_t yclipt)
645 {
646  const Float_t kP=10000;
647  Int_t clip = 0;
648 
649  for (Int_t i=0;i<2;i++) {
650  if (TMath::Abs(xclipl-x[i]) <= TMath::Abs(xclipr-xclipl)/kP) x[i] = xclipl;
651  if (TMath::Abs(xclipr-x[i]) <= TMath::Abs(xclipr-xclipl)/kP) x[i] = xclipr;
652  if (TMath::Abs(yclipb-y[i]) <= TMath::Abs(yclipt-yclipb)/kP) y[i] = yclipb;
653  if (TMath::Abs(yclipt-y[i]) <= TMath::Abs(yclipt-yclipb)/kP) y[i] = yclipt;
654  }
655 
656  // Compute the first endpoint codes.
657  Int_t code1 = ClippingCode(x[0],y[0],xclipl,yclipb,xclipr,yclipt);
658  Int_t code2 = ClippingCode(x[1],y[1],xclipl,yclipb,xclipr,yclipt);
659 
660  Double_t xt=0, yt=0;
661  Int_t clipped = 0; //this variable could be used in a future version
662  while(code1 + code2) {
663  clipped = 1;
664 
665  // The line lies entirely outside the clipping boundary
666  if (code1&code2) {
667  clip = 2;
668  return clip;
669  }
670 
671  // The line is subdivided into several parts
672  Int_t ic = code1;
673  if (ic == 0) ic = code2;
674  if (ic & 0x1) {
675  yt = y[0] + (y[1]-y[0])*(xclipl-x[0])/(x[1]-x[0]);
676  xt = xclipl;
677  }
678  if (ic & 0x2) {
679  yt = y[0] + (y[1]-y[0])*(xclipr-x[0])/(x[1]-x[0]);
680  xt = xclipr;
681  }
682  if (ic & 0x4) {
683  xt = x[0] + (x[1]-x[0])*(yclipb-y[0])/(y[1]-y[0]);
684  yt = yclipb;
685  }
686  if (ic & 0x8) {
687  xt = x[0] + (x[1]-x[0])*(yclipt-y[0])/(y[1]-y[0]);
688  yt = yclipt;
689  }
690  if (ic == code1) {
691  x[0] = xt;
692  y[0] = yt;
693  code1 = ClippingCode(xt,yt,xclipl,yclipb,xclipr,yclipt);
694  } else {
695  x[1] = xt;
696  y[1] = yt;
697  code2 = ClippingCode(xt,yt,xclipl,yclipb,xclipr,yclipt);
698  }
699  }
700  clip = clipped;
701  return clip;
702 }
703 
704 ////////////////////////////////////////////////////////////////////////////////
705 /// Clipping routine: Cohen Sutherland algorithm.
706 ///
707 /// - If Clip ==2 the segment is outside the boundary.
708 /// - If Clip ==1 the segment has one point outside the boundary.
709 /// - If Clip ==0 the segment is inside the boundary.
710 ///
711 /// \param[in] x[],y[] Segment coordinates (2 points)
712 /// \param[in] xclipl,yclipb,xclipr,yclipt Clipping boundary
713 /// \param[out] x[],y[] New segment coordinates(2 points)
714 
715 Int_t TPad::Clip(Double_t *x, Double_t *y, Double_t xclipl, Double_t yclipb, Double_t xclipr, Double_t yclipt)
716 {
717  const Double_t kP=10000;
718  Int_t clip = 0;
719 
720  for (Int_t i=0;i<2;i++) {
721  if (TMath::Abs(xclipl-x[i]) <= TMath::Abs(xclipr-xclipl)/kP) x[i] = xclipl;
722  if (TMath::Abs(xclipr-x[i]) <= TMath::Abs(xclipr-xclipl)/kP) x[i] = xclipr;
723  if (TMath::Abs(yclipb-y[i]) <= TMath::Abs(yclipt-yclipb)/kP) y[i] = yclipb;
724  if (TMath::Abs(yclipt-y[i]) <= TMath::Abs(yclipt-yclipb)/kP) y[i] = yclipt;
725  }
726 
727  // Compute the first endpoint codes.
728  Int_t code1 = 0;
729  if (x[0] < xclipl) code1 = code1 | 0x1;
730  if (x[0] > xclipr) code1 = code1 | 0x2;
731  if (y[0] < yclipb) code1 = code1 | 0x4;
732  if (y[0] > yclipt) code1 = code1 | 0x8;
733  Int_t code2 = 0;
734  if (x[1] < xclipl) code2 = code2 | 0x1;
735  if (x[1] > xclipr) code2 = code2 | 0x2;
736  if (y[1] < yclipb) code2 = code2 | 0x4;
737  if (y[1] > yclipt) code2 = code2 | 0x8;
738 
739  Double_t xt=0, yt=0;
740  Int_t clipped = 0; //this variable could be used in a future version
741  while(code1 + code2) {
742  clipped = 1;
743 
744  // The line lies entirely outside the clipping boundary
745  if (code1&code2) {
746  clip = 2;
747  return clip;
748  }
749 
750  // The line is subdivided into several parts
751  Int_t ic = code1;
752  if (ic == 0) ic = code2;
753  if (ic & 0x1) {
754  yt = y[0] + (y[1]-y[0])*(xclipl-x[0])/(x[1]-x[0]);
755  xt = xclipl;
756  }
757  if (ic & 0x2) {
758  yt = y[0] + (y[1]-y[0])*(xclipr-x[0])/(x[1]-x[0]);
759  xt = xclipr;
760  }
761  if (ic & 0x4) {
762  xt = x[0] + (x[1]-x[0])*(yclipb-y[0])/(y[1]-y[0]);
763  yt = yclipb;
764  }
765  if (ic & 0x8) {
766  xt = x[0] + (x[1]-x[0])*(yclipt-y[0])/(y[1]-y[0]);
767  yt = yclipt;
768  }
769  if (ic == code1) {
770  x[0] = xt;
771  y[0] = yt;
772  code1 = ClippingCode(xt,yt,xclipl,yclipb,xclipr,yclipt);
773  } else {
774  x[1] = xt;
775  y[1] = yt;
776  code2 = ClippingCode(xt,yt,xclipl,yclipb,xclipr,yclipt);
777  }
778  }
779  clip = clipped;
780  return clip;
781 }
782 
783 ////////////////////////////////////////////////////////////////////////////////
784 /// Compute the endpoint codes for TPad::Clip.
785 
787 {
788  Int_t code = 0;
789  if (x < xcl1) code = code | 0x1;
790  if (x > xcl2) code = code | 0x2;
791  if (y < ycl1) code = code | 0x4;
792  if (y > ycl2) code = code | 0x8;
793  return code;
794 }
795 
796 ////////////////////////////////////////////////////////////////////////////////
797 /// Clip polygon using the Sutherland-Hodgman algorithm.
798 ///
799 /// \param[in] n Number of points in the polygon to
800 /// be clipped
801 /// \param[in] x[n],y[n] Polygon do be clipped vertices
802 /// \param[in] xclipl,yclipb,xclipr,yclipt Clipping boundary
803 /// \param[out] nn Number of points in xc and yc
804 /// \param[out] xc,yc Clipped polygon vertices. The Int_t
805 /// returned by this function is
806 /// the number of points in the clipped
807 /// polygon. These vectors must
808 /// be allocated by the calling function.
809 /// A size of 2*n for each is
810 /// enough.
811 ///
812 /// Sutherland and Hodgman's polygon-clipping algorithm uses a divide-and-conquer
813 /// strategy: It solves a series of simple and identical problems that, when
814 /// combined, solve the overall problem. The simple problem is to clip a polygon
815 /// against a single infinite clip edge. Four clip edges, each defining one boundary
816 /// of the clip rectangle, successively clip a polygon against a clip rectangle.
817 ///
818 /// Steps of Sutherland-Hodgman's polygon-clipping algorithm:
819 ///
820 /// * Polygons can be clipped against each edge of the window one at a time.
821 /// Windows/edge intersections, if any, are easy to find since the X or Y coordinates
822 /// are already known.
823 /// * Vertices which are kept after clipping against one window edge are saved for
824 /// clipping against the remaining edges.
825 /// * Note that the number of vertices usually changes and will often increases.
826 ///
827 /// The clip boundary determines a visible and invisible region. The edges from
828 /// vertex i to vertex i+1 can be one of four types:
829 ///
830 /// * Case 1 : Wholly inside visible region - save endpoint
831 /// * Case 2 : Exit visible region - save the intersection
832 /// * Case 3 : Wholly outside visible region - save nothing
833 /// * Case 4 : Enter visible region - save intersection and endpoint
834 
836 {
837  Int_t nc, nc2;
838  Double_t x1, y1, x2, y2, slope; // Segment to be clipped
839 
840  Double_t *xc2 = new Double_t[nn];
841  Double_t *yc2 = new Double_t[nn];
842 
843  // Clip against the left boundary
844  x1 = x[n-1]; y1 = y[n-1];
845  nc2 = 0;
846  Int_t i;
847  for (i=0; i<n; i++) {
848  x2 = x[i]; y2 = y[i];
849  if (x1 == x2) {
850  slope = 0;
851  } else {
852  slope = (y2-y1)/(x2-x1);
853  }
854  if (x1 >= xclipl) {
855  if (x2 < xclipl) {
856  xc2[nc2] = xclipl; yc2[nc2++] = slope*(xclipl-x1)+y1;
857  } else {
858  xc2[nc2] = x2; yc2[nc2++] = y2;
859  }
860  } else {
861  if (x2 >= xclipl) {
862  xc2[nc2] = xclipl; yc2[nc2++] = slope*(xclipl-x1)+y1;
863  xc2[nc2] = x2; yc2[nc2++] = y2;
864  }
865  }
866  x1 = x2; y1 = y2;
867  }
868 
869  // Clip against the top boundary
870  x1 = xc2[nc2-1]; y1 = yc2[nc2-1];
871  nc = 0;
872  for (i=0; i<nc2; i++) {
873  x2 = xc2[i]; y2 = yc2[i];
874  if (y1 == y2) {
875  slope = 0;
876  } else {
877  slope = (x2-x1)/(y2-y1);
878  }
879  if (y1 <= yclipt) {
880  if (y2 > yclipt) {
881  xc[nc] = x1+(yclipt-y1)*slope; yc[nc++] = yclipt;
882  } else {
883  xc[nc] = x2; yc[nc++] = y2;
884  }
885  } else {
886  if (y2 <= yclipt) {
887  xc[nc] = x1+(yclipt-y1)*slope; yc[nc++] = yclipt;
888  xc[nc] = x2; yc[nc++] = y2;
889  }
890  }
891  x1 = x2; y1 = y2;
892  }
893 
894  // Clip against the right boundary
895  x1 = xc[nc-1]; y1 = yc[nc-1];
896  nc2 = 0;
897  for (i=0; i<nc; i++) {
898  x2 = xc[i]; y2 = yc[i];
899  if (x1 == x2) {
900  slope = 0;
901  } else {
902  slope = (y2-y1)/(x2-x1);
903  }
904  if (x1 <= xclipr) {
905  if (x2 > xclipr) {
906  xc2[nc2] = xclipr; yc2[nc2++] = slope*(xclipr-x1)+y1;
907  } else {
908  xc2[nc2] = x2; yc2[nc2++] = y2;
909  }
910  } else {
911  if (x2 <= xclipr) {
912  xc2[nc2] = xclipr; yc2[nc2++] = slope*(xclipr-x1)+y1;
913  xc2[nc2] = x2; yc2[nc2++] = y2;
914  }
915  }
916  x1 = x2; y1 = y2;
917  }
918 
919  // Clip against the bottom boundary
920  x1 = xc2[nc2-1]; y1 = yc2[nc2-1];
921  nc = 0;
922  for (i=0; i<nc2; i++) {
923  x2 = xc2[i]; y2 = yc2[i];
924  if (y1 == y2) {
925  slope = 0;
926  } else {
927  slope = (x2-x1)/(y2-y1);
928  }
929  if (y1 >= yclipb) {
930  if (y2 < yclipb) {
931  xc[nc] = x1+(yclipb-y1)*slope; yc[nc++] = yclipb;
932  } else {
933  xc[nc] = x2; yc[nc++] = y2;
934  }
935  } else {
936  if (y2 >= yclipb) {
937  xc[nc] = x1+(yclipb-y1)*slope; yc[nc++] = yclipb;
938  xc[nc] = x2; yc[nc++] = y2;
939  }
940  }
941  x1 = x2; y1 = y2;
942  }
943 
944  delete [] xc2;
945  delete [] yc2;
946 
947  if (nc < 3) nc =0;
948  return nc;
949 }
950 
951 ////////////////////////////////////////////////////////////////////////////////
952 /// Delete all primitives in pad and pad itself.
953 /// Pad cannot be used anymore after this call.
954 /// Emits signal "Closed()".
955 
957 {
958  if (!TestBit(kNotDeleted)) return;
959  if (!fMother) return;
960 
961  if (fPrimitives)
962  fPrimitives->Clear();
963  if (fView) {
964  if (fView->TestBit(kNotDeleted)) delete fView;
965  fView = 0;
966  }
967  if (fFrame) {
968  if (fFrame->TestBit(kNotDeleted)) delete fFrame;
969  fFrame = 0;
970  }
971 
972  // emit signal
973  if (IsA() != TCanvas::Class())
974  Closed();
975 
976  if (fPixmapID != -1) {
977  if (gPad) {
978  if (!gPad->IsBatch()) {
981  }
982  }
983  fPixmapID = -1;
984 
985  if (!gROOT->GetListOfCanvases()) return;
986  if (fMother == this) {
987  gROOT->GetListOfCanvases()->Remove(this);
988  return; // in case of TCanvas
989  }
990 
991  // remove from the mother's list of primitives
992  if (fMother) {
995 
996  if (gPad == this) fMother->cd();
997  }
998 
999  if (fCanvas->GetPadSave() == this)
1000  fCanvas->ClearPadSave();
1001  if (fCanvas->GetSelectedPad() == this)
1002  fCanvas->SetSelectedPad(0);
1003  if (fCanvas->GetClickSelectedPad() == this)
1005  }
1006 
1007  fMother = 0;
1008  if (gROOT->GetSelectedPad() == this) gROOT->SetSelectedPad(0);
1009 }
1010 
1011 ////////////////////////////////////////////////////////////////////////////////
1012 /// Copy the pixmap of the pad to the canvas.
1013 
1015 {
1016  int px, py;
1017  XYtoAbsPixel(fX1, fY2, px, py);
1018 
1019  if (fPixmapID != -1)
1020  GetPainter()->CopyDrawable(fPixmapID, px, py);
1021 
1022  if (this == gPad) HighLight(gPad->GetHighLightColor());
1023 }
1024 
1025 ////////////////////////////////////////////////////////////////////////////////
1026 /// Copy the sub-pixmaps of the pad to the canvas.
1027 
1029 {
1030  TObject *obj;
1031  if (!fPrimitives) fPrimitives = new TList;
1032  TIter next(GetListOfPrimitives());
1033  while ((obj = next())) {
1034  if (obj->InheritsFrom(TPad::Class())) {
1035  ((TPad*)obj)->CopyPixmap();
1036  ((TPad*)obj)->CopyPixmaps();
1037  }
1038  }
1039 }
1040 
1041 ////////////////////////////////////////////////////////////////////////////////
1042 /// Remove TExec name from the list of Execs.
1043 
1044 void TPad::DeleteExec(const char *name)
1045 {
1046  if (!fExecs) fExecs = new TList;
1047  TExec *ex = (TExec*)fExecs->FindObject(name);
1048  if (!ex) return;
1049  fExecs->Remove(ex);
1050  delete ex;
1051 }
1052 
1053 ////////////////////////////////////////////////////////////////////////////////
1054 /// Compute distance from point px,py to a box.
1055 ///
1056 /// Compute the closest distance of approach from point px,py to the
1057 /// edges of this pad.
1058 /// The distance is computed in pixels units.
1059 
1061 {
1062  Int_t pxl, pyl, pxt, pyt;
1063  Int_t px1 = gPad->XtoAbsPixel(fX1);
1064  Int_t py1 = gPad->YtoAbsPixel(fY1);
1065  Int_t px2 = gPad->XtoAbsPixel(fX2);
1066  Int_t py2 = gPad->YtoAbsPixel(fY2);
1067  if (px1 < px2) {pxl = px1; pxt = px2;}
1068  else {pxl = px2; pxt = px1;}
1069  if (py1 < py2) {pyl = py1; pyt = py2;}
1070  else {pyl = py2; pyt = py1;}
1071 
1072  // Are we inside the box?
1073  // ======================
1074  if ( (px > pxl && px < pxt) && (py > pyl && py < pyt) ) {
1075  if (GetFillStyle()) return 0; //*-* if pad is filled
1076  }
1077 
1078  // Are we on the edges?
1079  // ====================
1080  Int_t dxl = TMath::Abs(px - pxl);
1081  if (py < pyl) dxl += pyl - py;
1082  if (py > pyt) dxl += py - pyt;
1083  Int_t dxt = TMath::Abs(px - pxt);
1084  if (py < pyl) dxt += pyl - py;
1085  if (py > pyt) dxt += py - pyt;
1086  Int_t dyl = TMath::Abs(py - pyl);
1087  if (px < pxl) dyl += pxl - px;
1088  if (px > pxt) dyl += px - pxt;
1089  Int_t dyt = TMath::Abs(py - pyt);
1090  if (px < pxl) dyt += pxl - px;
1091  if (px > pxt) dyt += px - pxt;
1092 
1093  Int_t distance = dxl;
1094  if (dxt < distance) distance = dxt;
1095  if (dyl < distance) distance = dyl;
1096  if (dyt < distance) distance = dyt;
1097 
1098  return distance - Int_t(0.5*fLineWidth);
1099 }
1100 
1101 ////////////////////////////////////////////////////////////////////////////////
1102 /// Automatic pad generation by division.
1103 ///
1104 /// - The current canvas is divided in nx by ny equal divisions (pads).
1105 /// - xmargin is the space along x between pads in percent of canvas.
1106 /// - ymargin is the space along y between pads in percent of canvas.
1107 /// - color is the color of the new pads. If 0, color is the canvas color.
1108 ///
1109 /// Pads are automatically named `canvasname_n` where `n` is the division number
1110 /// starting from top left pad.
1111 ///
1112 /// Example if canvasname=c1 , nx=2, ny=3:
1113 ///
1114 /// \image html gpad_pad3.png
1115 ///
1116 /// Once a pad is divided into sub-pads, one can set the current pad
1117 /// to a subpad with a given division number as illustrated above
1118 /// with TPad::cd(subpad_number).
1119 ///
1120 /// For example, to set the current pad to c1_4, one can do:
1121 /// ~~~ {.cpp}
1122 /// c1->cd(4)
1123 /// ~~~
1124 /// __Note1:__ c1.cd() is equivalent to c1.cd(0) and sets the current pad
1125 /// to c1 itself.
1126 ///
1127 /// __Note2:__ after a statement like c1.cd(6), the global variable gPad
1128 /// points to the current pad. One can use gPad to set attributes
1129 /// of the current pad.
1130 ///
1131 /// __Note3:__ in case xmargin <=0 and ymargin <= 0, there is no space
1132 /// between pads. The current pad margins are recomputed to
1133 /// optimize the layout.
1134 
1135 void TPad::Divide(Int_t nx, Int_t ny, Float_t xmargin, Float_t ymargin, Int_t color)
1136 {
1137  if (!IsEditable()) return;
1138 
1139 
1140  if (gThreadXAR) {
1141  void *arr[7];
1142  arr[1] = this; arr[2] = (void*)&nx;arr[3] = (void*)& ny;
1143  arr[4] = (void*)&xmargin; arr[5] = (void *)& ymargin; arr[6] = (void *)&color;
1144  if ((*gThreadXAR)("PDCD", 7, arr, 0)) return;
1145  }
1146 
1147  TPad *padsav = (TPad*)gPad;
1148  cd();
1149  if (nx <= 0) nx = 1;
1150  if (ny <= 0) ny = 1;
1151  Int_t ix,iy;
1152  Double_t x1,y1,x2,y2;
1153  Double_t dx,dy;
1154  TPad *pad;
1155  Int_t nchname = strlen(GetName())+6;
1156  Int_t nchtitle = strlen(GetTitle())+6;
1157  char *name = new char [nchname];
1158  char *title = new char [nchtitle];
1159  Int_t n = 0;
1160  if (color == 0) color = GetFillColor();
1161  if (xmargin > 0 && ymargin > 0) {
1162  //general case
1163  dy = 1/Double_t(ny);
1164  dx = 1/Double_t(nx);
1165  for (iy=0;iy<ny;iy++) {
1166  y2 = 1 - iy*dy - ymargin;
1167  y1 = y2 - dy + 2*ymargin;
1168  if (y1 < 0) y1 = 0;
1169  if (y1 > y2) continue;
1170  for (ix=0;ix<nx;ix++) {
1171  x1 = ix*dx + xmargin;
1172  x2 = x1 +dx -2*xmargin;
1173  if (x1 > x2) continue;
1174  n++;
1175  snprintf(name,nchname,"%s_%d",GetName(),n);
1176  pad = new TPad(name,name,x1,y1,x2,y2,color);
1177  pad->SetNumber(n);
1178  pad->Draw();
1179  }
1180  }
1181  } else {
1182  // special case when xmargin <= 0 && ymargin <= 0
1183  Double_t xl = GetLeftMargin();
1184  Double_t xr = GetRightMargin();
1185  Double_t yb = GetBottomMargin();
1186  Double_t yt = GetTopMargin();
1187  xl /= (1-xl+xr)*nx;
1188  xr /= (1-xl+xr)*nx;
1189  yb /= (1-yb+yt)*ny;
1190  yt /= (1-yb+yt)*ny;
1191  SetLeftMargin(xl);
1192  SetRightMargin(xr);
1193  SetBottomMargin(yb);
1194  SetTopMargin(yt);
1195  dx = (1-xl-xr)/nx;
1196  dy = (1-yb-yt)/ny;
1197  Int_t number = 0;
1198  for (Int_t i=0;i<nx;i++) {
1199  x1 = i*dx+xl;
1200  x2 = x1 + dx;
1201  if (i == 0) x1 = 0;
1202  if (i == nx-1) x2 = 1-xr;
1203  for (Int_t j=0;j<ny;j++) {
1204  number = j*nx + i +1;
1205  y2 = 1 -j*dy -yt;
1206  y1 = y2 - dy;
1207  if (j == 0) y2 = 1-yt;
1208  if (j == ny-1) y1 = 0;
1209  snprintf(name,nchname,"%s_%d",GetName(),number);
1210  snprintf(title,nchtitle,"%s_%d",GetTitle(),number);
1211  pad = new TPad(name,title,x1,y1,x2,y2);
1212  pad->SetNumber(number);
1213  pad->SetBorderMode(0);
1214  if (i == 0) pad->SetLeftMargin(xl*nx);
1215  else pad->SetLeftMargin(0);
1216  pad->SetRightMargin(0);
1217  pad->SetTopMargin(0);
1218  if (j == ny-1) pad->SetBottomMargin(yb*ny);
1219  else pad->SetBottomMargin(0);
1220  pad->Draw();
1221  }
1222  }
1223  }
1224  delete [] name;
1225  delete [] title;
1226  Modified();
1227  if (padsav) padsav->cd();
1228 }
1229 
1230 ////////////////////////////////////////////////////////////////////////////////
1231 /// "n" is the total number of sub-pads. The number of sub-pads along the X
1232 /// and Y axis are computed according to the square root of n.
1233 
1234 void TPad::DivideSquare(Int_t n, Float_t xmargin, Float_t ymargin, Int_t color)
1235 {
1236  Int_t w = 1, h = 1;
1237 
1239  w = TMath::Ceil(TMath::Sqrt(n));
1240  h = TMath::Floor(TMath::Sqrt(n));
1241  if (w*h < n) w++;
1242  } else {
1243  h = TMath::Ceil(TMath::Sqrt(n));
1244  w = TMath::Floor(TMath::Sqrt(n));
1245  if (w*h < n) h++;
1246  }
1247 
1248  Divide( w, h, xmargin, ymargin, color);
1249 }
1250 
1251 ////////////////////////////////////////////////////////////////////////////////
1252 /// Draw Pad in Current pad (re-parent pad if necessary).
1253 
1254 void TPad::Draw(Option_t *option)
1255 {
1256  // if no canvas opened yet create a default canvas
1257  if (!gPad) {
1258  gROOT->MakeDefCanvas();
1259  }
1260 
1261  // pad cannot be in itself and it can only be in one other pad at a time
1262  if (!fPrimitives) fPrimitives = new TList;
1263  if (gPad != this) {
1264  if (fMother) fMother->GetListOfPrimitives()->Remove(this);
1265  TPad *oldMother = fMother;
1266  fCanvas = gPad->GetCanvas();
1267  //
1268  fMother = (TPad*)gPad;
1269  if (oldMother != fMother || fPixmapID == -1) ResizePad();
1270  }
1271 
1272  Paint();
1273 
1274  if (gPad->IsRetained() && gPad != this && fMother)
1275  fMother->GetListOfPrimitives()->Add(this, option);
1276 }
1277 
1278 ////////////////////////////////////////////////////////////////////////////////
1279 /// Draw class inheritance tree of the class to which obj belongs.
1280 ///
1281 /// If a class B inherits from a class A, description of B is drawn
1282 /// on the right side of description of A.
1283 ///
1284 /// Member functions overridden by B are shown in class A with a blue line
1285 /// crossing-out the corresponding member function.
1286 
1287 void TPad::DrawClassObject(const TObject *classobj, Option_t *option)
1288 {
1289  char dname[256];
1290  const Int_t kMAXLEVELS = 10;
1291  TClass *clevel[kMAXLEVELS], *cl, *cll;
1292  TBaseClass *base, *cinherit;
1293  TText *ptext = 0;
1294  TString opt=option;
1295  Double_t x,y,dy,y1,v1,v2,dv;
1296  Int_t nd,nf,nc,nkd,nkf,i,j;
1297  TPaveText *pt;
1298  Int_t maxlev = 4;
1299  if (opt.Contains("2")) maxlev = 2;
1300  if (opt.Contains("3")) maxlev = 3;
1301  if (opt.Contains("5")) maxlev = 5;
1302  if (opt.Contains("6")) maxlev = 6;
1303  if (opt.Contains("7")) maxlev = 7;
1304 
1305  // Clear and Set Pad range
1306  Double_t xpad = 20.5;
1307  Double_t ypad = 27.5;
1308  Clear();
1309  Range(0,0,xpad,ypad);
1310 
1311  // Find number of levels
1312  Int_t nlevel = 0;
1313  TClass *obj = (TClass*)classobj;
1314  clevel[nlevel] = obj;
1315  TList *lbase = obj->GetListOfBases();
1316  while(lbase) {
1317  base = (TBaseClass*)lbase->First();
1318  if (!base) break;
1319  if ( base->GetClassPointer() == 0) break;
1320  nlevel++;
1321  clevel[nlevel] = base->GetClassPointer();
1322  lbase = clevel[nlevel]->GetListOfBases();
1323  if (nlevel >= maxlev-1) break;
1324  }
1325  Int_t maxelem = 0;
1326  Int_t ncdraw = 0;
1327  Int_t ilevel, nelem;
1328  for (ilevel=nlevel;ilevel>=0;ilevel--) {
1329  cl = clevel[ilevel];
1330  nelem = cl->GetNdata() + cl->GetNmethods();
1331  if (nelem > maxelem) maxelem = nelem;
1332  nc = (nelem/50) + 1;
1333  ncdraw += nc;
1334  }
1335 
1336  Double_t tsizcm = 0.40;
1337  Double_t x1 = 0.25;
1338  Double_t x2 = 0;
1339  Double_t dx = 3.5;
1340  if (ncdraw > 4) {
1341  dx = dx - 0.42*Double_t(ncdraw-5);
1342  if (dx < 1.3) dx = 1.3;
1343  tsizcm = tsizcm - 0.03*Double_t(ncdraw-5);
1344  if (tsizcm < 0.27) tsizcm = 0.27;
1345  }
1346  Double_t tsiz = 1.2*tsizcm/ypad;
1347 
1348  // Now loop on levels
1349  for (ilevel=nlevel;ilevel>=0;ilevel--) {
1350  cl = clevel[ilevel];
1351  nelem = cl->GetNdata() + cl->GetNmethods();
1352  if (nelem > maxelem) maxelem = nelem;
1353  nc = (nelem/50) + 1;
1354  dy = 0.45;
1355  if (ilevel < nlevel) x1 = x2 + 0.5;
1356  x2 = x1 + nc*dx;
1357  v2 = ypad - 0.5;
1358  lbase = cl->GetListOfBases();
1359  cinherit = 0;
1360  if (lbase) cinherit = (TBaseClass*)lbase->First();
1361 
1362  do {
1363  nd = cl->GetNdata();
1364  nf = cl->GetNmethods() - 2; //do not show default constructor and destructor
1365  if (cl->GetListOfMethods()->FindObject("Dictionary")) {
1366  nf -= 6; // do not count the Dictionary/ClassDef functions
1367  }
1368  nkf= nf/nc +1;
1369  nkd= nd/nc +1;
1370  if (nd == 0) nkd=0;
1371  if (nf == 0) nkf=0;
1372  y1 = v2 - 0.7;
1373  v1 = y1 - Double_t(nkf+nkd+nc-1)*dy;
1374  dv = v2 - v1;
1375 
1376  // Create a new PaveText
1377  pt = new TPaveText(x1,v1,x2,v2);
1378  pt->SetBit(kCanDelete);
1379  pt->SetFillColor(19);
1380  pt->Draw();
1381  pt->SetTextColor(4);
1382  pt->SetTextFont(61);
1383  pt->SetTextAlign(12);
1384  pt->SetTextSize(tsiz);
1385  TBox *box = pt->AddBox(0,(y1+0.01-v1)/dv,0,(v2-0.01-v1)/dv);
1386  if (box) box->SetFillColor(17);
1387  pt->AddLine(0,(y1-v1)/dv,0,(y1-v1)/dv);
1388  TText *title = pt->AddText(0.5,(0.5*(y1+v2)-v1)/dv,(char*)cl->GetName());
1389  title->SetTextAlign(22);
1390  title->SetTextSize(0.6*(v2-y1)/ypad);
1391 
1392  // Draw data Members
1393  i = 0;
1394  x = 0.03;
1395  y = y1 + 0.5*dy;
1396  TDataMember *d;
1397  TIter nextd(cl->GetListOfDataMembers());
1398  while ((d = (TDataMember *) nextd())) {
1399  if (i >= nkd) { i = 1; y = y1 - 0.5*dy; x += 1/Double_t(nc); }
1400  else { i++; y -= dy; }
1401 
1402  // Take in account the room the array index will occupy
1403 
1404  Int_t dim = d->GetArrayDim();
1405  Int_t indx = 0;
1406  snprintf(dname,256,"%s",obj->EscapeChars(d->GetName()));
1407  Int_t ldname = 0;
1408  while (indx < dim ){
1409  ldname = strlen(dname);
1410  snprintf(&dname[ldname],256-ldname,"[%d]",d->GetMaxIndex(indx));
1411  indx++;
1412  }
1413  pt->AddText(x,(y-v1)/dv,dname);
1414  }
1415 
1416  // Draw a separator line
1417  Double_t ysep;
1418  if (nd) {
1419  ysep = y1 - Double_t(nkd)*dy;
1420  pt->AddLine(0,(ysep-v1)/dv,0,(ysep-v1)/dv);
1421  ysep -= 0.5*dy;
1422  } else ysep = y1;
1423 
1424  // Draw Member Functions
1425  Int_t fcount = 0;
1426  i = 0;
1427  x = 0.03;
1428  y = ysep + 0.5*dy;
1429  TMethod *m;
1430  TIter nextm(cl->GetListOfMethods());
1431  while ((m = (TMethod *) nextm())) {
1432  if (
1433  !strcmp( m->GetName(), "Dictionary" ) ||
1434  !strcmp( m->GetName(), "Class_Version" ) ||
1435  !strcmp( m->GetName(), "DeclFileName" ) ||
1436  !strcmp( m->GetName(), "DeclFileLine" ) ||
1437  !strcmp( m->GetName(), "ImplFileName" ) ||
1438  !strcmp( m->GetName(), "ImplFileLine" )
1439  ) continue;
1440  fcount++;
1441  if (fcount > nf) break;
1442  if (i >= nkf) { i = 1; y = ysep - 0.5*dy; x += 1/Double_t(nc); }
1443  else { i++; y -= dy; }
1444  ptext = pt->AddText(x,(y-v1)/dv,obj->EscapeChars(m->GetName()));
1445 
1446  // Check if method is overloaded in a derived class
1447  // If yes, Change the color of the text to blue
1448  for (j=ilevel-1;j>=0;j--) {
1449  if (cl == clevel[ilevel]) {
1450  if (clevel[j]->GetMethodAny((char*)m->GetName())) {
1451  ptext->SetTextColor(15);
1452  break;
1453  }
1454  }
1455  }
1456  }
1457 
1458  // Draw second inheritance classes for this class
1459  cll = 0;
1460  if (cinherit) {
1461  cinherit = (TBaseClass*)lbase->After(cinherit);
1462  if (cinherit) {
1463  cl = cinherit->GetClassPointer();
1464  cll = cl;
1465  v2 = v1 -0.4;
1466  dy = 0.35;
1467  }
1468  }
1469  } while (cll);
1470  }
1471  Update();
1472 }
1473 
1474 ////////////////////////////////////////////////////////////////////////////////
1475 /// Function called to draw a crosshair in the canvas
1476 ///
1477 /// Example:
1478 /// ~~~ {.cpp}
1479 /// Root > TFile f("hsimple.root");
1480 /// Root > hpxpy.Draw();
1481 /// Root > c1.SetCrosshair();
1482 /// ~~~
1483 /// When moving the mouse in the canvas, a crosshair is drawn
1484 ///
1485 /// - if the canvas fCrosshair = 1 , the crosshair spans the full canvas
1486 /// - if the canvas fCrosshair > 1 , the crosshair spans only the pad
1487 
1489 {
1490  if (gPad->GetEvent() == kMouseEnter) return;
1491 
1492  TPad *cpad = (TPad*)gPad;
1493  TCanvas *canvas = cpad->GetCanvas();
1494  canvas->FeedbackMode(kTRUE);
1495 
1496  //erase old position and draw a line at current position
1497  Int_t pxmin,pxmax,pymin,pymax,pxold,pyold,px,py;
1498  pxold = fCrosshairPos%10000;
1499  pyold = fCrosshairPos/10000;
1500  px = cpad->GetEventX();
1501  py = cpad->GetEventY()+1;
1502  if (canvas->GetCrosshair() > 1) { //crosshair only in the current pad
1503  pxmin = cpad->XtoAbsPixel(fX1);
1504  pxmax = cpad->XtoAbsPixel(fX2);
1505  pymin = cpad->YtoAbsPixel(fY1);
1506  pymax = cpad->YtoAbsPixel(fY2);
1507  } else { //default; crosshair spans the full canvas
1508  pxmin = 0;
1509  pxmax = canvas->GetWw();
1510  pymin = 0;
1511  pymax = cpad->GetWh();
1512  }
1513  if(pxold) gVirtualX->DrawLine(pxold,pymin,pxold,pymax);
1514  if(pyold) gVirtualX->DrawLine(pxmin,pyold,pxmax,pyold);
1515  if (cpad->GetEvent() == kButton1Down ||
1516  cpad->GetEvent() == kButton1Up ||
1517  cpad->GetEvent() == kMouseLeave) {
1518  fCrosshairPos = 0;
1519  return;
1520  }
1521  gVirtualX->DrawLine(px,pymin,px,pymax);
1522  gVirtualX->DrawLine(pxmin,py,pxmax,py);
1523  fCrosshairPos = px + 10000*py;
1524 }
1525 
1526 ////////////////////////////////////////////////////////////////////////////////
1527 /// Draw an empty pad frame with X and Y axis.
1528 ///
1529 /// \param[in] xmin X axis lower limit
1530 /// \param[in] xmax X axis upper limit
1531 /// \param[in] ymin Y axis lower limit
1532 /// \param[in] ymax Y axis upper limit
1533 /// \param[in] title Pad title.If title is of the form "stringt;stringx;stringy"
1534 /// the pad title is set to stringt, the x axis title to
1535 /// stringx, the y axis title to stringy.
1536 
1538 {
1539  if (!IsEditable()) return 0;
1540  TPad *padsav = (TPad*)gPad;
1541  if (this != padsav) {
1542  Warning("DrawFrame","Must be called for the current pad only");
1543  return padsav->DrawFrame(xmin,ymin,xmax,ymax,title);
1544  }
1545 
1546  cd();
1547 
1548  TH1F *hframe = (TH1F*)FindObject("hframe");
1549  if (hframe) delete hframe;
1550  Int_t nbins = 1000;
1551  //if log scale in X, use variable bin size linear with log(x)
1552  //this gives a better precision when zooming on the axis
1553  if (fLogx && xmin > 0 && xmax > xmin) {
1554  Double_t xminl = TMath::Log(xmin);
1555  Double_t xmaxl = TMath::Log(xmax);
1556  Double_t dx = (xmaxl-xminl)/nbins;
1557  Double_t *xbins = new Double_t[nbins+1];
1558  xbins[0] = xmin;
1559  for (Int_t i=1;i<=nbins;i++) {
1560  xbins[i] = TMath::Exp(xminl+i*dx);
1561  }
1562  hframe = new TH1F("hframe",title,nbins,xbins);
1563  delete [] xbins;
1564  } else {
1565  hframe = new TH1F("hframe",title,nbins,xmin,xmax);
1566  }
1567  hframe->SetBit(TH1::kNoStats);
1568  hframe->SetBit(kCanDelete);
1569  hframe->SetMinimum(ymin);
1570  hframe->SetMaximum(ymax);
1571  hframe->GetYaxis()->SetLimits(ymin,ymax);
1572  hframe->SetDirectory(0);
1573  hframe->Draw(" ");
1574  Update();
1575  if (padsav) padsav->cd();
1576  return hframe;
1577 }
1578 
1579 ////////////////////////////////////////////////////////////////////////////////
1580 /// Static function to Display Color Table in a pad.
1581 
1583 {
1584  Int_t i, j;
1585  Int_t color;
1586  Double_t xlow, ylow, xup, yup, hs, ws;
1587  Double_t x1, y1, x2, y2;
1588  x1 = y1 = 0;
1589  x2 = y2 = 20;
1590 
1591  gPad->SetFillColor(0);
1592  gPad->Clear();
1593  gPad->Range(x1,y1,x2,y2);
1594 
1595  TText *text = new TText(0,0,"");
1596  text->SetTextFont(61);
1597  text->SetTextSize(0.07);
1598  text->SetTextAlign(22);
1599 
1600  TBox *box = new TBox();
1601 
1602  // Draw color table boxes.
1603  hs = (y2-y1)/Double_t(5);
1604  ws = (x2-x1)/Double_t(10);
1605  for (i=0;i<10;i++) {
1606  xlow = x1 + ws*(Double_t(i)+0.1);
1607  xup = x1 + ws*(Double_t(i)+0.9);
1608  for (j=0;j<5;j++) {
1609  ylow = y1 + hs*(Double_t(j)+0.1);
1610  yup = y1 + hs*(Double_t(j)+0.9);
1611  color = 10*j + i;
1612  box->SetFillStyle(1001);
1613  box->SetFillColor(color);
1614  box->DrawBox(xlow, ylow, xup, yup);
1615  box->SetFillStyle(0);
1616  box->SetLineColor(1);
1617  box->DrawBox(xlow, ylow, xup, yup);
1618  if (color == 1) text->SetTextColor(0);
1619  else text->SetTextColor(1);
1620  text->DrawText(0.5*(xlow+xup), 0.5*(ylow+yup), Form("%d",color));
1621  }
1622  }
1623 }
1624 
1625 ////////////////////////////////////////////////////////////////////////////////
1626 /// Execute action corresponding to one event.
1627 ///
1628 /// This member function is called when a TPad object is clicked.
1629 ///
1630 /// If the mouse is clicked in one of the 4 corners of the pad (pA,pB,pC,pD)
1631 /// the pad is resized with the rubber rectangle.
1632 ///
1633 /// If the mouse is clicked inside the pad, the pad is moved.
1634 ///
1635 /// If the mouse is clicked on the 4 edges (pL,pR,pTop,pBot), the pad is scaled
1636 /// parallel to this edge.
1637 ///
1638 /// \image html gpad_pad4.png
1639 ///
1640 /// Note that this function duplicates on purpose the functionality
1641 /// already implemented in TBox::ExecuteEvent.
1642 /// If somebody modifies this function, may be similar changes should also
1643 /// be applied to TBox::ExecuteEvent.
1644 
1646 {
1647  const Int_t kMaxDiff = 5;
1648  const Int_t kMinSize = 20;
1649  static Int_t pxorg, pyorg;
1650  static Int_t px1, px2, py1, py2, pxl, pyl, pxt, pyt, pxold, pyold;
1651  static Int_t px1p, px2p, py1p, py2p, pxlp, pylp, pxtp, pytp;
1652  static Bool_t pA, pB, pC, pD, pTop, pL, pR, pBot, pINSIDE;
1653  Int_t wx, wy;
1654  Bool_t opaque = OpaqueMoving();
1655  Bool_t ropaque = OpaqueResizing();
1656  Bool_t fixedr = HasFixedAspectRatio();
1657 
1658  if (!IsEditable() && event != kMouseEnter) return;
1659  TVirtualPad *parent = GetMother();
1660  if (!parent->IsEditable()) return;
1661 
1662  HideToolTip(event);
1663 
1664  if (fXlowNDC < 0 && event != kButton1Down) return;
1665  if (fYlowNDC < 0 && event != kButton1Down) return;
1666 
1667  // keep old mouse position
1668  if (event == kButton1Down) {
1669  pxorg = px;
1670  pyorg = py;
1671  }
1672 
1673  Int_t newcode = gROOT->GetEditorMode();
1674  if (newcode)
1675  pA = pB = pC = pD = pTop = pL = pR = pBot = pINSIDE = kFALSE;
1676  switch (newcode) {
1677  case kPad:
1678  TCreatePrimitives::Pad(event,px,py,0);
1679  break;
1680  case kMarker:
1681  case kText:
1682  TCreatePrimitives::Text(event,px,py,newcode);
1683  break;
1684  case kLine:
1685  TCreatePrimitives::Line(event,px,py,kLine);
1686  break;
1687  case kArrow:
1688  TCreatePrimitives::Line(event,px,py,kArrow);
1689  break;
1690  case kCurlyLine:
1691  TCreatePrimitives::Line(event,px,py,kCurlyLine);
1692  break;
1693  case kCurlyArc:
1694  TCreatePrimitives::Line(event,px,py,kCurlyArc);
1695  break;
1696  case kPolyLine:
1698  break;
1699  case kCutG:
1700  TCreatePrimitives::PolyLine(event,px,py,kCutG);
1701  break;
1702  case kArc:
1703  TCreatePrimitives::Ellipse(event,px,py,kArc);
1704  break;
1705  case kEllipse:
1706  TCreatePrimitives::Ellipse(event,px,py,kEllipse);
1707  break;
1708  case kButton:
1709  case kPave:
1710  case kPaveLabel:
1711  case kPaveText:
1712  case kPavesText:
1713  case kDiamond:
1714  TCreatePrimitives::Pave(event,px,py,newcode);
1715  return;
1716  default:
1717  break;
1718  }
1719  if (newcode) return;
1720 
1721  switch (event) {
1722 
1723  case kMouseEnter:
1724  if (fTip)
1725  ResetToolTip(fTip);
1726  break;
1727 
1728  case kArrowKeyPress:
1729  case kButton1Down:
1730 
1731  fXUpNDC = fXlowNDC + fWNDC;
1732  fYUpNDC = fYlowNDC + fHNDC;
1733 
1734  GetPainter()->SetLineColor(-1);
1735  TAttLine::Modify(); //Change line attributes only if necessary
1736  if (GetFillColor())
1738  else
1739  GetPainter()->SetLineColor(1);
1740  GetPainter()->SetLineWidth(2);
1741 
1742  // No break !!!
1743 
1744  case kMouseMotion:
1745 
1746  px1 = XtoAbsPixel(fX1);
1747  py1 = YtoAbsPixel(fY1);
1748  px2 = XtoAbsPixel(fX2);
1749  py2 = YtoAbsPixel(fY2);
1750 
1751  if (px1 < px2) {
1752  pxl = px1;
1753  pxt = px2;
1754  } else {
1755  pxl = px2;
1756  pxt = px1;
1757  }
1758  if (py1 < py2) {
1759  pyl = py1;
1760  pyt = py2;
1761  } else {
1762  pyl = py2;
1763  pyt = py1;
1764  }
1765 
1766  px1p = parent->XtoAbsPixel(parent->GetX1()) + parent->GetBorderSize();
1767  py1p = parent->YtoAbsPixel(parent->GetY1()) - parent->GetBorderSize();
1768  px2p = parent->XtoAbsPixel(parent->GetX2()) - parent->GetBorderSize();
1769  py2p = parent->YtoAbsPixel(parent->GetY2()) + parent->GetBorderSize();
1770 
1771  if (px1p < px2p) {
1772  pxlp = px1p;
1773  pxtp = px2p;
1774  } else {
1775  pxlp = px2p;
1776  pxtp = px1p;
1777  }
1778  if (py1p < py2p) {
1779  pylp = py1p;
1780  pytp = py2p;
1781  } else {
1782  pylp = py2p;
1783  pytp = py1p;
1784  }
1785 
1786  pA = pB = pC = pD = pTop = pL = pR = pBot = pINSIDE = kFALSE;
1787 
1788  // case pA
1789  if (TMath::Abs(px - pxl) <= kMaxDiff && TMath::Abs(py - pyl) <= kMaxDiff) {
1790  pxold = pxl; pyold = pyl; pA = kTRUE;
1792  }
1793  // case pB
1794  if (TMath::Abs(px - pxt) <= kMaxDiff && TMath::Abs(py - pyl) <= kMaxDiff) {
1795  pxold = pxt; pyold = pyl; pB = kTRUE;
1797  }
1798  // case pC
1799  if (TMath::Abs(px - pxt) <= kMaxDiff && TMath::Abs(py - pyt) <= kMaxDiff) {
1800  pxold = pxt; pyold = pyt; pC = kTRUE;
1802  }
1803  // case pD
1804  if (TMath::Abs(px - pxl) <= kMaxDiff && TMath::Abs(py - pyt) <= kMaxDiff) {
1805  pxold = pxl; pyold = pyt; pD = kTRUE;
1807  }
1808 
1809  if ((px > pxl+kMaxDiff && px < pxt-kMaxDiff) &&
1810  TMath::Abs(py - pyl) < kMaxDiff) { // top edge
1811  pxold = pxl; pyold = pyl; pTop = kTRUE;
1813  }
1814 
1815  if ((px > pxl+kMaxDiff && px < pxt-kMaxDiff) &&
1816  TMath::Abs(py - pyt) < kMaxDiff) { // bottom edge
1817  pxold = pxt; pyold = pyt; pBot = kTRUE;
1819  }
1820 
1821  if ((py > pyl+kMaxDiff && py < pyt-kMaxDiff) &&
1822  TMath::Abs(px - pxl) < kMaxDiff) { // left edge
1823  pxold = pxl; pyold = pyl; pL = kTRUE;
1825  }
1826 
1827  if ((py > pyl+kMaxDiff && py < pyt-kMaxDiff) &&
1828  TMath::Abs(px - pxt) < kMaxDiff) { // right edge
1829  pxold = pxt; pyold = pyt; pR = kTRUE;
1831  }
1832 
1833  if ((px > pxl+kMaxDiff && px < pxt-kMaxDiff) &&
1834  (py > pyl+kMaxDiff && py < pyt-kMaxDiff)) { // inside box
1835  pxold = px; pyold = py; pINSIDE = kTRUE;
1836  if (event == kButton1Down)
1837  SetCursor(kMove);
1838  else
1839  SetCursor(kCross);
1840  }
1841 
1842  fResizing = kFALSE;
1843  if (pA || pB || pC || pD || pTop || pL || pR || pBot)
1844  fResizing = kTRUE;
1845 
1846  if (!pA && !pB && !pC && !pD && !pTop && !pL && !pR && !pBot && !pINSIDE)
1847  SetCursor(kCross);
1848 
1849  break;
1850 
1851  case kArrowKeyRelease:
1852  case kButton1Motion:
1853 
1854  if (TestBit(kCannotMove)) break;
1855  wx = wy = 0;
1856 
1857  if (pA) {
1858  if (!ropaque) gVirtualX->DrawBox(pxold, pyt, pxt, pyold, TVirtualX::kHollow);
1859  if (px > pxt-kMinSize) { px = pxt-kMinSize; wx = px; }
1860  if (py > pyt-kMinSize) { py = pyt-kMinSize; wy = py; }
1861  if (px < pxlp) { px = pxlp; wx = px; }
1862  if (py < pylp) { py = pylp; wy = py; }
1863  if (fixedr) {
1864  Double_t dy = Double_t(TMath::Abs(pxt-px))/parent->UtoPixel(1.) /
1865  fAspectRatio;
1866  Int_t npy2 = pyt - TMath::Abs(parent->VtoAbsPixel(dy) -
1867  parent->VtoAbsPixel(0));
1868  if (npy2 < pylp) {
1869  px = pxold;
1870  py = pyold;
1871  } else
1872  py = npy2;
1873 
1874  wx = wy = 0;
1875  }
1876  if (!ropaque) gVirtualX->DrawBox(px, pyt, pxt, py, TVirtualX::kHollow);
1877  }
1878  if (pB) {
1879  if (!ropaque) gVirtualX->DrawBox(pxl , pyt, pxold, pyold, TVirtualX::kHollow);
1880  if (px < pxl+kMinSize) { px = pxl+kMinSize; wx = px; }
1881  if (py > pyt-kMinSize) { py = pyt-kMinSize; wy = py; }
1882  if (px > pxtp) { px = pxtp; wx = px; }
1883  if (py < pylp) { py = pylp; wy = py; }
1884  if (fixedr) {
1885  Double_t dy = Double_t(TMath::Abs(pxl-px))/parent->UtoPixel(1.) /
1886  fAspectRatio;
1887  Int_t npy2 = pyt - TMath::Abs(parent->VtoAbsPixel(dy) -
1888  parent->VtoAbsPixel(0));
1889  if (npy2 < pylp) {
1890  px = pxold;
1891  py = pyold;
1892  } else
1893  py = npy2;
1894 
1895  wx = wy = 0;
1896  }
1897  if (!ropaque) gVirtualX->DrawBox(pxl , pyt, px , py, TVirtualX::kHollow);
1898  }
1899  if (pC) {
1900  if (!ropaque) gVirtualX->DrawBox(pxl , pyl, pxold, pyold, TVirtualX::kHollow);
1901  if (px < pxl+kMinSize) { px = pxl+kMinSize; wx = px; }
1902  if (py < pyl+kMinSize) { py = pyl+kMinSize; wy = py; }
1903  if (px > pxtp) { px = pxtp; wx = px; }
1904  if (py > pytp) { py = pytp; wy = py; }
1905  if (fixedr) {
1906  Double_t dy = Double_t(TMath::Abs(pxl-px))/parent->UtoPixel(1.) /
1907  fAspectRatio;
1908  Int_t npy2 = pyl + TMath::Abs(parent->VtoAbsPixel(dy) -
1909  parent->VtoAbsPixel(0));
1910  if (npy2 > pytp) {
1911  px = pxold;
1912  py = pyold;
1913  } else
1914  py = npy2;
1915 
1916  wx = wy = 0;
1917  }
1918  if (!ropaque) gVirtualX->DrawBox(pxl, pyl, px, py, TVirtualX::kHollow);
1919  }
1920  if (pD) {
1921  if (!ropaque) gVirtualX->DrawBox(pxold, pyold, pxt, pyl, TVirtualX::kHollow);
1922  if (px > pxt-kMinSize) { px = pxt-kMinSize; wx = px; }
1923  if (py < pyl+kMinSize) { py = pyl+kMinSize; wy = py; }
1924  if (px < pxlp) { px = pxlp; wx = px; }
1925  if (py > pytp) { py = pytp; wy = py; }
1926  if (fixedr) {
1927  Double_t dy = Double_t(TMath::Abs(pxt-px))/parent->UtoPixel(1.) /
1928  fAspectRatio;
1929  Int_t npy2 = pyl + TMath::Abs(parent->VtoAbsPixel(dy) -
1930  parent->VtoAbsPixel(0));
1931  if (npy2 > pytp) {
1932  px = pxold;
1933  py = pyold;
1934  } else
1935  py = npy2;
1936 
1937  wx = wy = 0;
1938  }
1939  if (!ropaque) gVirtualX->DrawBox(px, py, pxt, pyl, TVirtualX::kHollow);
1940  }
1941  if (pTop) {
1942  if (!ropaque) gVirtualX->DrawBox(px1, py1, px2, py2, TVirtualX::kHollow);
1943  py2 += py - pyold;
1944  if (py2 > py1-kMinSize) { py2 = py1-kMinSize; wy = py2; }
1945  if (py2 < py2p) { py2 = py2p; wy = py2; }
1946  if (fixedr) {
1947  Double_t dx = Double_t(TMath::Abs(py2-py1))/parent->VtoPixel(0) *
1948  fAspectRatio;
1949  Int_t npx2 = px1 + parent->UtoPixel(dx);
1950  if (npx2 > px2p)
1951  py2 -= py - pyold;
1952  else
1953  px2 = npx2;
1954  }
1955  if (!ropaque) gVirtualX->DrawBox(px1, py1, px2, py2, TVirtualX::kHollow);
1956  }
1957  if (pBot) {
1958  if (!ropaque) gVirtualX->DrawBox(px1, py1, px2, py2, TVirtualX::kHollow);
1959  py1 += py - pyold;
1960  if (py1 < py2+kMinSize) { py1 = py2+kMinSize; wy = py1; }
1961  if (py1 > py1p) { py1 = py1p; wy = py1; }
1962  if (fixedr) {
1963  Double_t dx = Double_t(TMath::Abs(py2-py1))/parent->VtoPixel(0) *
1964  fAspectRatio;
1965  Int_t npx2 = px1 + parent->UtoPixel(dx);
1966  if (npx2 > px2p)
1967  py1 -= py - pyold;
1968  else
1969  px2 = npx2;
1970  }
1971  if (!ropaque) gVirtualX->DrawBox(px1, py1, px2, py2, TVirtualX::kHollow);
1972  }
1973  if (pL) {
1974  if (!ropaque) gVirtualX->DrawBox(px1, py1, px2, py2, TVirtualX::kHollow);
1975  px1 += px - pxold;
1976  if (px1 > px2-kMinSize) { px1 = px2-kMinSize; wx = px1; }
1977  if (px1 < px1p) { px1 = px1p; wx = px1; }
1978  if (fixedr) {
1979  Double_t dy = Double_t(TMath::Abs(px2-px1))/parent->UtoPixel(1.) /
1980  fAspectRatio;
1981  Int_t npy2 = py1 - TMath::Abs(parent->VtoAbsPixel(dy) -
1982  parent->VtoAbsPixel(0));
1983  if (npy2 < py2p)
1984  px1 -= px - pxold;
1985  else
1986  py2 = npy2;
1987  }
1988  if (!ropaque) gVirtualX->DrawBox(px1, py1, px2, py2, TVirtualX::kHollow);
1989  }
1990  if (pR) {
1991  if (!ropaque) gVirtualX->DrawBox(px1, py1, px2, py2, TVirtualX::kHollow);
1992  px2 += px - pxold;
1993  if (px2 < px1+kMinSize) { px2 = px1+kMinSize; wx = px2; }
1994  if (px2 > px2p) { px2 = px2p; wx = px2; }
1995  if (fixedr) {
1996  Double_t dy = Double_t(TMath::Abs(px2-px1))/parent->UtoPixel(1.) /
1997  fAspectRatio;
1998  Int_t npy2 = py1 - TMath::Abs(parent->VtoAbsPixel(dy) -
1999  parent->VtoAbsPixel(0));
2000  if (npy2 < py2p)
2001  px2 -= px - pxold;
2002  else
2003  py2 = npy2;
2004  }
2005  if (!ropaque) gVirtualX->DrawBox(px1, py1, px2, py2, TVirtualX::kHollow);
2006  }
2007  if (pINSIDE) {
2008  if (!opaque) gVirtualX->DrawBox(px1, py1, px2, py2, TVirtualX::kHollow); // draw the old box
2009  Int_t dx = px - pxold;
2010  Int_t dy = py - pyold;
2011  px1 += dx; py1 += dy; px2 += dx; py2 += dy;
2012  if (px1 < px1p) { dx = px1p - px1; px1 += dx; px2 += dx; wx = px+dx; }
2013  if (px2 > px2p) { dx = px2 - px2p; px1 -= dx; px2 -= dx; wx = px-dx; }
2014  if (py1 > py1p) { dy = py1 - py1p; py1 -= dy; py2 -= dy; wy = py-dy; }
2015  if (py2 < py2p) { dy = py2p - py2; py1 += dy; py2 += dy; wy = py+dy; }
2016  if (!opaque) gVirtualX->DrawBox(px1, py1, px2, py2, TVirtualX::kHollow); // draw the new box
2017  }
2018 
2019  if (wx || wy) {
2020  if (wx) px = wx;
2021  if (wy) py = wy;
2022  gVirtualX->Warp(px, py);
2023  }
2024 
2025  pxold = px;
2026  pyold = py;
2027 
2028  Double_t x1, y1, x2, y2;
2029  x1 = x2 = y1 = y2 = 0;
2030 
2031  if ((!fResizing && opaque) || (fResizing && ropaque)) {
2032  if (pA) {
2033  x1 = AbsPixeltoX(pxold);
2034  y1 = AbsPixeltoY(pyt);
2035  x2 = AbsPixeltoX(pxt);
2036  y2 = AbsPixeltoY(pyold);
2037  }
2038  if (pB) {
2039  x1 = AbsPixeltoX(pxl);
2040  y1 = AbsPixeltoY(pyt);
2041  x2 = AbsPixeltoX(pxold);
2042  y2 = AbsPixeltoY(pyold);
2043  }
2044  if (pC) {
2045  x1 = AbsPixeltoX(pxl);
2046  y1 = AbsPixeltoY(pyold);
2047  x2 = AbsPixeltoX(pxold);
2048  y2 = AbsPixeltoY(pyl);
2049  }
2050  if (pD) {
2051  x1 = AbsPixeltoX(pxold);
2052  y1 = AbsPixeltoY(pyold);
2053  x2 = AbsPixeltoX(pxt);
2054  y2 = AbsPixeltoY(pyl);
2055  }
2056  if (pTop || pBot || pL || pR || pINSIDE) {
2057  x1 = AbsPixeltoX(px1);
2058  y1 = AbsPixeltoY(py1);
2059  x2 = AbsPixeltoX(px2);
2060  y2 = AbsPixeltoY(py2);
2061  }
2062 
2063  if (px != pxorg || py != pyorg) {
2064 
2065  // Get parent corners pixels coordinates
2066  Int_t parentpx1 = fMother->XtoAbsPixel(parent->GetX1());
2067  Int_t parentpx2 = fMother->XtoAbsPixel(parent->GetX2());
2068  Int_t parentpy1 = fMother->YtoAbsPixel(parent->GetY1());
2069  Int_t parentpy2 = fMother->YtoAbsPixel(parent->GetY2());
2070 
2071  // Get pad new corners pixels coordinates
2072  Int_t apx1 = XtoAbsPixel(x1); if (apx1 < parentpx1) {apx1 = parentpx1; }
2073  Int_t apx2 = XtoAbsPixel(x2); if (apx2 > parentpx2) {apx2 = parentpx2; }
2074  Int_t apy1 = YtoAbsPixel(y1); if (apy1 > parentpy1) {apy1 = parentpy1; }
2075  Int_t apy2 = YtoAbsPixel(y2); if (apy2 < parentpy2) {apy2 = parentpy2; }
2076 
2077  // Compute new pad positions in the NDC space of parent
2078  fXlowNDC = Double_t(apx1 - parentpx1)/Double_t(parentpx2 - parentpx1);
2079  fYlowNDC = Double_t(apy1 - parentpy1)/Double_t(parentpy2 - parentpy1);
2080  fWNDC = Double_t(apx2 - apx1)/Double_t(parentpx2 - parentpx1);
2081  fHNDC = Double_t(apy2 - apy1)/Double_t(parentpy2 - parentpy1);
2082  }
2083 
2084  // Reset pad parameters and recompute conversion coefficients
2085  ResizePad();
2086 
2087  if (pINSIDE) gPad->ShowGuidelines(this, event);
2088  if (pTop) gPad->ShowGuidelines(this, event, 't', true);
2089  if (pBot) gPad->ShowGuidelines(this, event, 'b', true);
2090  if (pL) gPad->ShowGuidelines(this, event, 'l', true);
2091  if (pR) gPad->ShowGuidelines(this, event, 'r', true);
2092  if (pA) gPad->ShowGuidelines(this, event, '1', true);
2093  if (pB) gPad->ShowGuidelines(this, event, '2', true);
2094  if (pC) gPad->ShowGuidelines(this, event, '3', true);
2095  if (pD) gPad->ShowGuidelines(this, event, '4', true);
2096 
2097  Modified(kTRUE);
2098  }
2099 
2100  break;
2101 
2102  case kButton1Up:
2103 
2104  if (gROOT->IsEscaped()) {
2105  gROOT->SetEscape(kFALSE);
2106  break;
2107  }
2108 
2109  if (opaque||ropaque) {
2110  ShowGuidelines(this, event);
2111  } else {
2112  x1 = x2 = y1 = y2 = 0;
2113 
2114  if (pA) {
2115  x1 = AbsPixeltoX(pxold);
2116  y1 = AbsPixeltoY(pyt);
2117  x2 = AbsPixeltoX(pxt);
2118  y2 = AbsPixeltoY(pyold);
2119  }
2120  if (pB) {
2121  x1 = AbsPixeltoX(pxl);
2122  y1 = AbsPixeltoY(pyt);
2123  x2 = AbsPixeltoX(pxold);
2124  y2 = AbsPixeltoY(pyold);
2125  }
2126  if (pC) {
2127  x1 = AbsPixeltoX(pxl);
2128  y1 = AbsPixeltoY(pyold);
2129  x2 = AbsPixeltoX(pxold);
2130  y2 = AbsPixeltoY(pyl);
2131  }
2132  if (pD) {
2133  x1 = AbsPixeltoX(pxold);
2134  y1 = AbsPixeltoY(pyold);
2135  x2 = AbsPixeltoX(pxt);
2136  y2 = AbsPixeltoY(pyl);
2137  }
2138  if (pTop || pBot || pL || pR || pINSIDE) {
2139  x1 = AbsPixeltoX(px1);
2140  y1 = AbsPixeltoY(py1);
2141  x2 = AbsPixeltoX(px2);
2142  y2 = AbsPixeltoY(py2);
2143  }
2144 
2145  if (pA || pB || pC || pD || pTop || pL || pR || pBot)
2146  Modified(kTRUE);
2147 
2148  gVirtualX->SetLineColor(-1);
2149  gVirtualX->SetLineWidth(-1);
2150 
2151  if (px != pxorg || py != pyorg) {
2152 
2153  // Get parent corners pixels coordinates
2154  Int_t parentpx1 = fMother->XtoAbsPixel(parent->GetX1());
2155  Int_t parentpx2 = fMother->XtoAbsPixel(parent->GetX2());
2156  Int_t parentpy1 = fMother->YtoAbsPixel(parent->GetY1());
2157  Int_t parentpy2 = fMother->YtoAbsPixel(parent->GetY2());
2158 
2159  // Get pad new corners pixels coordinates
2160  Int_t apx1 = XtoAbsPixel(x1); if (apx1 < parentpx1) {apx1 = parentpx1; }
2161  Int_t apx2 = XtoAbsPixel(x2); if (apx2 > parentpx2) {apx2 = parentpx2; }
2162  Int_t apy1 = YtoAbsPixel(y1); if (apy1 > parentpy1) {apy1 = parentpy1; }
2163  Int_t apy2 = YtoAbsPixel(y2); if (apy2 < parentpy2) {apy2 = parentpy2; }
2164 
2165  // Compute new pad positions in the NDC space of parent
2166  fXlowNDC = Double_t(apx1 - parentpx1)/Double_t(parentpx2 - parentpx1);
2167  fYlowNDC = Double_t(apy1 - parentpy1)/Double_t(parentpy2 - parentpy1);
2168  fWNDC = Double_t(apx2 - apx1)/Double_t(parentpx2 - parentpx1);
2169  fHNDC = Double_t(apy2 - apy1)/Double_t(parentpy2 - parentpy1);
2170  }
2171 
2172  // Reset pad parameters and recompute conversion coefficients
2173  ResizePad();
2174 
2175 
2176  // emit signal
2177  RangeChanged();
2178  }
2179 
2180  break;
2181 
2182  case kButton1Locate:
2183 
2184  ExecuteEvent(kButton1Down, px, py);
2185 
2186  while (1) {
2187  px = py = 0;
2188  event = gVirtualX->RequestLocator(1, 1, px, py);
2189 
2190  ExecuteEvent(kButton1Motion, px, py);
2191 
2192  if (event != -1) { // button is released
2193  ExecuteEvent(kButton1Up, px, py);
2194  return;
2195  }
2196  }
2197 
2198  case kButton2Down:
2199 
2200  Pop();
2201  break;
2202 
2203  }
2204 }
2205 
2206 ////////////////////////////////////////////////////////////////////////////////
2207 /// Execute action corresponding to one event for a TAxis object
2208 /// (called by TAxis::ExecuteEvent.)
2209 /// This member function is called when an axis is clicked with the locator
2210 ///
2211 /// The axis range is set between the position where the mouse is pressed
2212 /// and the position where it is released.
2213 ///
2214 /// If the mouse position is outside the current axis range when it is released
2215 /// the axis is unzoomed with the corresponding proportions.
2216 ///
2217 /// Note that the mouse does not need to be in the pad or even canvas
2218 /// when it is released.
2219 
2220 void TPad::ExecuteEventAxis(Int_t event, Int_t px, Int_t py, TAxis *axis)
2221 {
2222  if (!IsEditable()) return;
2223 
2224  SetCursor(kHand);
2225 
2226  TView *view = GetView();
2227  static Int_t axisNumber;
2228  static Double_t ratio1, ratio2;
2229  static Int_t px1old, py1old, px2old, py2old;
2230  Int_t bin1, bin2, first, last;
2231  Double_t temp, xmin,xmax;
2232  Bool_t opaque = gPad->OpaqueMoving();
2233  static TBox *zoombox;
2234  Double_t zbx1=0,zbx2=0,zby1=0,zby2=0;
2235 
2236  // The CONT4 option, used to paint TH2, is a special case; it uses a 3D
2237  // drawing technique to paint a 2D plot.
2238  TString opt = axis->GetParent()->GetDrawOption();
2239  opt.ToLower();
2240  Bool_t kCont4 = kFALSE;
2241  if (strstr(opt,"cont4")) {
2242  view = 0;
2243  kCont4 = kTRUE;
2244  }
2245 
2246  switch (event) {
2247 
2248  case kButton1Down:
2249  axisNumber = 1;
2250  if (!strcmp(axis->GetName(),"xaxis")) {
2251  axisNumber = 1;
2252  if (!IsVertical()) axisNumber = 2;
2253  }
2254  if (!strcmp(axis->GetName(),"yaxis")) {
2255  axisNumber = 2;
2256  if (!IsVertical()) axisNumber = 1;
2257  }
2258  if (!strcmp(axis->GetName(),"zaxis")) {
2259  axisNumber = 3;
2260  }
2261  if (view) {
2262  view->GetDistancetoAxis(axisNumber, px, py, ratio1);
2263  } else {
2264  if (axisNumber == 1) {
2265  ratio1 = (AbsPixeltoX(px) - GetUxmin())/(GetUxmax() - GetUxmin());
2266  px1old = XtoAbsPixel(GetUxmin()+ratio1*(GetUxmax() - GetUxmin()));
2267  py1old = YtoAbsPixel(GetUymin());
2268  px2old = px1old;
2269  py2old = YtoAbsPixel(GetUymax());
2270  } else if (axisNumber == 2) {
2271  ratio1 = (AbsPixeltoY(py) - GetUymin())/(GetUymax() - GetUymin());
2272  py1old = YtoAbsPixel(GetUymin()+ratio1*(GetUymax() - GetUymin()));
2273  px1old = XtoAbsPixel(GetUxmin());
2274  px2old = XtoAbsPixel(GetUxmax());
2275  py2old = py1old;
2276  } else {
2277  ratio1 = (AbsPixeltoY(py) - GetUymin())/(GetUymax() - GetUymin());
2278  py1old = YtoAbsPixel(GetUymin()+ratio1*(GetUymax() - GetUymin()));
2279  px1old = XtoAbsPixel(GetUxmax());
2280  px2old = XtoAbsPixel(GetX2());
2281  py2old = py1old;
2282  }
2283  if (!opaque) {
2284  gVirtualX->DrawBox(px1old, py1old, px2old, py2old, TVirtualX::kHollow);
2285  } else {
2286  if (axisNumber == 1) {
2287  zbx1 = AbsPixeltoX(px1old);
2288  zbx2 = AbsPixeltoX(px2old);
2289  zby1 = GetUymin();
2290  zby2 = GetUymax();
2291  } else if (axisNumber == 2) {
2292  zbx1 = GetUxmin();
2293  zbx2 = GetUxmax();
2294  zby1 = AbsPixeltoY(py1old);
2295  zby2 = AbsPixeltoY(py2old);
2296  }
2297  if (GetLogx()) {
2298  zbx1 = TMath::Power(10,zbx1);
2299  zbx2 = TMath::Power(10,zbx2);
2300  }
2301  if (GetLogy()) {
2302  zby1 = TMath::Power(10,zby1);
2303  zby2 = TMath::Power(10,zby2);
2304  }
2305  zoombox = new TBox(zbx1, zby1, zbx2, zby2);
2306  Int_t ci = TColor::GetColor("#7d7dff");
2307  TColor *zoomcolor = gROOT->GetColor(ci);
2308  if (!TCanvas::SupportAlpha() || !zoomcolor) zoombox->SetFillStyle(3002);
2309  else zoomcolor->SetAlpha(0.5);
2310  zoombox->SetFillColor(ci);
2311  zoombox->Draw();
2312  gPad->Modified();
2313  gPad->Update();
2314  }
2315  }
2316  if (!opaque) gVirtualX->SetLineColor(-1);
2317  // No break !!!
2318 
2319  case kButton1Motion:
2320  if (view) {
2321  view->GetDistancetoAxis(axisNumber, px, py, ratio2);
2322  } else {
2323  if (!opaque) gVirtualX->DrawBox(px1old, py1old, px2old, py2old, TVirtualX::kHollow);
2324  if (axisNumber == 1) {
2325  ratio2 = (AbsPixeltoX(px) - GetUxmin())/(GetUxmax() - GetUxmin());
2326  px2old = XtoAbsPixel(GetUxmin()+ratio2*(GetUxmax() - GetUxmin()));
2327  } else {
2328  ratio2 = (AbsPixeltoY(py) - GetUymin())/(GetUymax() - GetUymin());
2329  py2old = YtoAbsPixel(GetUymin()+ratio2*(GetUymax() - GetUymin()));
2330  }
2331  if (!opaque) {
2332  gVirtualX->DrawBox(px1old, py1old, px2old, py2old, TVirtualX::kHollow);
2333  } else {
2334  if (axisNumber == 1) {
2335  zbx1 = AbsPixeltoX(px1old);
2336  zbx2 = AbsPixeltoX(px2old);
2337  zby1 = GetUymin();
2338  zby2 = GetUymax();
2339  } else if (axisNumber == 2) {
2340  zbx1 = GetUxmin();
2341  zbx2 = GetUxmax();
2342  zby1 = AbsPixeltoY(py1old);
2343  zby2 = AbsPixeltoY(py2old);
2344  }
2345  if (GetLogx()) {
2346  zbx1 = TMath::Power(10,zbx1);
2347  zbx2 = TMath::Power(10,zbx2);
2348  }
2349  if (GetLogy()) {
2350  zby1 = TMath::Power(10,zby1);
2351  zby2 = TMath::Power(10,zby2);
2352  }
2353  if (zoombox) {
2354  zoombox->SetX1(zbx1);
2355  zoombox->SetY1(zby1);
2356  zoombox->SetX2(zbx2);
2357  zoombox->SetY2(zby2);
2358  }
2359  gPad->Modified();
2360  gPad->Update();
2361  }
2362  }
2363  break;
2364 
2365  case kWheelUp:
2366  bin1 = axis->GetFirst()+1;
2367  bin2 = axis->GetLast()-1;
2368  bin1 = TMath::Max(bin1, 1);
2369  bin2 = TMath::Min(bin2, axis->GetNbins());
2370  if (bin2>bin1) {
2371  axis->SetRange(bin1,bin2);
2372  gPad->Modified();
2373  gPad->Update();
2374  }
2375  break;
2376 
2377  case kWheelDown:
2378  bin1 = axis->GetFirst()-1;
2379  bin2 = axis->GetLast()+1;
2380  bin1 = TMath::Max(bin1, 1);
2381  bin2 = TMath::Min(bin2, axis->GetNbins());
2382  if (bin2>bin1) {
2383  axis->SetRange(bin1,bin2);
2384  gPad->Modified();
2385  gPad->Update();
2386  }
2387  break;
2388 
2389  case kButton1Up:
2390  if (gROOT->IsEscaped()) {
2391  gROOT->SetEscape(kFALSE);
2392  if (opaque && zoombox) {
2393  zoombox->Delete();
2394  zoombox = 0;
2395  }
2396  break;
2397  }
2398 
2399  if (view) {
2400  view->GetDistancetoAxis(axisNumber, px, py, ratio2);
2401  if (ratio1 > ratio2) {
2402  temp = ratio1;
2403  ratio1 = ratio2;
2404  ratio2 = temp;
2405  }
2406  if (ratio2 - ratio1 > 0.05) {
2407  TH1 *hobj = (TH1*)axis->GetParent();
2408  if (axisNumber == 3 && hobj && hobj->GetDimension() != 3) {
2409  Float_t zmin = hobj->GetMinimum();
2410  Float_t zmax = hobj->GetMaximum();
2411  if(GetLogz()){
2412  if (zmin <= 0 && zmax > 0) zmin = TMath::Min((Double_t)1,
2413  (Double_t)0.001*zmax);
2414  zmin = TMath::Log10(zmin);
2415  zmax = TMath::Log10(zmax);
2416  }
2417  Float_t newmin = zmin + (zmax-zmin)*ratio1;
2418  Float_t newmax = zmin + (zmax-zmin)*ratio2;
2419  if(newmin < zmin)newmin = hobj->GetBinContent(hobj->GetMinimumBin());
2420  if(newmax > zmax)newmax = hobj->GetBinContent(hobj->GetMaximumBin());
2421  if(GetLogz()){
2422  newmin = TMath::Exp(2.302585092994*newmin);
2423  newmax = TMath::Exp(2.302585092994*newmax);
2424  }
2425  hobj->SetMinimum(newmin);
2426  hobj->SetMaximum(newmax);
2427  hobj->SetBit(TH1::kIsZoomed);
2428  } else {
2429  first = axis->GetFirst();
2430  last = axis->GetLast();
2431  bin1 = first + Int_t((last-first+1)*ratio1);
2432  bin2 = first + Int_t((last-first+1)*ratio2);
2433  bin1 = TMath::Max(bin1, 1);
2434  bin2 = TMath::Min(bin2, axis->GetNbins());
2435  axis->SetRange(bin1, bin2);
2436  }
2437  delete view;
2438  SetView(0);
2439  Modified(kTRUE);
2440  }
2441  } else {
2442  if (axisNumber == 1) {
2443  ratio2 = (AbsPixeltoX(px) - GetUxmin())/(GetUxmax() - GetUxmin());
2444  xmin = GetUxmin() +ratio1*(GetUxmax() - GetUxmin());
2445  xmax = GetUxmin() +ratio2*(GetUxmax() - GetUxmin());
2446  if (GetLogx() && !kCont4) {
2447  xmin = PadtoX(xmin);
2448  xmax = PadtoX(xmax);
2449  }
2450  } else if (axisNumber == 2) {
2451  ratio2 = (AbsPixeltoY(py) - GetUymin())/(GetUymax() - GetUymin());
2452  xmin = GetUymin() +ratio1*(GetUymax() - GetUymin());
2453  xmax = GetUymin() +ratio2*(GetUymax() - GetUymin());
2454  if (GetLogy() && !kCont4) {
2455  xmin = PadtoY(xmin);
2456  xmax = PadtoY(xmax);
2457  }
2458  } else {
2459  ratio2 = (AbsPixeltoY(py) - GetUymin())/(GetUymax() - GetUymin());
2460  xmin = ratio1;
2461  xmax = ratio2;
2462  }
2463  if (xmin > xmax) {
2464  temp = xmin;
2465  xmin = xmax;
2466  xmax = temp;
2467  temp = ratio1;
2468  ratio1 = ratio2;
2469  ratio2 = temp;
2470  }
2471 
2472  // xmin and xmax need to be adjusted in case of CONT4.
2473  if (kCont4) {
2474  Double_t low = axis->GetBinLowEdge(axis->GetFirst());
2475  Double_t up = axis->GetBinUpEdge(axis->GetLast());
2476  Double_t xmi = GetUxmin();
2477  Double_t xma = GetUxmax();
2478  xmin = ((xmin-xmi)/(xma-xmi))*(up-low)+low;
2479  xmax = ((xmax-xmi)/(xma-xmi))*(up-low)+low;
2480  }
2481 
2482  if (!strcmp(axis->GetName(),"xaxis")) axisNumber = 1;
2483  if (!strcmp(axis->GetName(),"yaxis")) axisNumber = 2;
2484  if (ratio2 - ratio1 > 0.05) {
2485  //update object owning this axis
2486  TH1 *hobj1 = (TH1*)axis->GetParent();
2487  bin1 = axis->FindFixBin(xmin);
2488  bin2 = axis->FindFixBin(xmax);
2489  bin1 = TMath::Max(bin1, 1);
2490  bin2 = TMath::Min(bin2, axis->GetNbins());
2491  if (axisNumber == 1) axis->SetRange(bin1,bin2);
2492  if (axisNumber == 2 && hobj1) {
2493  if (hobj1->GetDimension() == 1) {
2494  if (hobj1->GetNormFactor() != 0) {
2495  Double_t norm = hobj1->GetSumOfWeights()/hobj1->GetNormFactor();
2496  xmin *= norm;
2497  xmax *= norm;
2498  }
2499  hobj1->SetMinimum(xmin);
2500  hobj1->SetMaximum(xmax);
2501  hobj1->SetBit(TH1::kIsZoomed);
2502  } else {
2503  axis->SetRange(bin1,bin2);
2504  }
2505  }
2506  //update all histograms in the pad
2507  TIter next(GetListOfPrimitives());
2508  TObject *obj;
2509  while ((obj= next())) {
2510  if (!obj->InheritsFrom(TH1::Class())) continue;
2511  TH1 *hobj = (TH1*)obj;
2512  if (hobj == hobj1) continue;
2513  bin1 = hobj->GetXaxis()->FindFixBin(xmin);
2514  bin2 = hobj->GetXaxis()->FindFixBin(xmax);
2515  if (axisNumber == 1) {
2516  hobj->GetXaxis()->SetRange(bin1,bin2);
2517  } else if (axisNumber == 2) {
2518  if (hobj->GetDimension() == 1) {
2519  Double_t xxmin = xmin;
2520  Double_t xxmax = xmax;
2521  if (hobj->GetNormFactor() != 0) {
2522  Double_t norm = hobj->GetSumOfWeights()/hobj->GetNormFactor();
2523  xxmin *= norm;
2524  xxmax *= norm;
2525  }
2526  hobj->SetMinimum(xxmin);
2527  hobj->SetMaximum(xxmax);
2528  hobj->SetBit(TH1::kIsZoomed);
2529  } else {
2530  bin1 = hobj->GetYaxis()->FindFixBin(xmin);
2531  bin2 = hobj->GetYaxis()->FindFixBin(xmax);
2532  hobj->GetYaxis()->SetRange(bin1,bin2);
2533  }
2534  }
2535  }
2536  Modified(kTRUE);
2537  }
2538  }
2539  if (!opaque) {
2540  gVirtualX->SetLineColor(-1);
2541  } else {
2542  if (zoombox) {
2543  zoombox->Delete();
2544  zoombox = 0;
2545  }
2546  }
2547  break;
2548  }
2549 }
2550 
2551 ////////////////////////////////////////////////////////////////////////////////
2552 /// Search if object named name is inside this pad or in pads inside this pad.
2553 ///
2554 /// In case name is in several sub-pads the first one is returned.
2555 
2556 TObject *TPad::FindObject(const char *name) const
2557 {
2558  if (!fPrimitives) return 0;
2559  TObject *found = fPrimitives->FindObject(name);
2560  if (found) return found;
2561  TObject *cur;
2562  TIter next(GetListOfPrimitives());
2563  while ((cur = next())) {
2564  if (cur->InheritsFrom(TPad::Class())) {
2565  found = ((TPad*)cur)->FindObject(name);
2566  if (found) return found;
2567  }
2568  }
2569  return 0;
2570 }
2571 
2572 ////////////////////////////////////////////////////////////////////////////////
2573 /// Search if obj is in pad or in pads inside this pad.
2574 ///
2575 /// In case obj is in several sub-pads the first one is returned.
2576 
2578 {
2579  if (!fPrimitives) return 0;
2580  TObject *found = fPrimitives->FindObject(obj);
2581  if (found) return found;
2582  TObject *cur;
2583  TIter next(GetListOfPrimitives());
2584  while ((cur = next())) {
2585  if (cur->InheritsFrom(TPad::Class())) {
2586  found = ((TPad*)cur)->FindObject(obj);
2587  if (found) return found;
2588  }
2589  }
2590  return 0;
2591 }
2592 
2593 ////////////////////////////////////////////////////////////////////////////////
2594 /// Get canvas identifier.
2595 
2597 {
2598  return fCanvas ? fCanvas->GetCanvasID() : -1;
2599 }
2600 
2601 ////////////////////////////////////////////////////////////////////////////////
2602 /// Get canvas implementation pointer if any
2603 
2605 {
2606  return fCanvas ? fCanvas->GetCanvasImp() : 0;
2607 }
2608 
2609 ////////////////////////////////////////////////////////////////////////////////
2610 /// Get Event.
2611 
2613 {
2614  return fCanvas ? fCanvas->GetEvent() : 0;
2615 }
2616 
2617 ////////////////////////////////////////////////////////////////////////////////
2618 /// Get X event.
2619 
2621 {
2622  return fCanvas ? fCanvas->GetEventX() : 0;
2623 }
2624 
2625 ////////////////////////////////////////////////////////////////////////////////
2626 /// Get Y event.
2627 
2629 {
2630  return fCanvas ? fCanvas->GetEventY() : 0;
2631 }
2632 
2633 ////////////////////////////////////////////////////////////////////////////////
2634 /// Get virtual canvas.
2635 
2637 {
2638  return fCanvas ? (TVirtualPad*) fCanvas : 0;
2639 }
2640 
2641 ////////////////////////////////////////////////////////////////////////////////
2642 /// Get highlight color.
2643 
2645 {
2646  return fCanvas ? fCanvas->GetHighLightColor() : 0;
2647 }
2648 
2649 ////////////////////////////////////////////////////////////////////////////////
2650 /// Static function (see also TPad::SetMaxPickDistance)
2651 
2653 {
2654  return fgMaxPickDistance;
2655 }
2656 
2657 ////////////////////////////////////////////////////////////////////////////////
2658 /// Get selected.
2659 
2661 {
2662  if (fCanvas == this) return 0;
2663  return fCanvas ? fCanvas->GetSelected() : 0;
2664 }
2665 
2666 ////////////////////////////////////////////////////////////////////////////////
2667 /// Get selected pad.
2668 
2670 {
2671  if (fCanvas == this) return 0;
2672  return fCanvas ? fCanvas->GetSelectedPad() : 0;
2673 }
2674 
2675 ////////////////////////////////////////////////////////////////////////////////
2676 /// Get save pad.
2677 
2679 {
2680  if (fCanvas == this) return 0;
2681  return fCanvas ? fCanvas->GetPadSave() : 0;
2682 }
2683 
2684 ////////////////////////////////////////////////////////////////////////////////
2685 /// Get Wh.
2686 
2688 {
2689  return fCanvas ? fCanvas->GetWh() : 0;
2690 }
2691 
2692 ////////////////////////////////////////////////////////////////////////////////
2693 /// Get Ww.
2694 
2696 {
2697  return fCanvas ? fCanvas->GetWw() : 0;
2698 }
2699 
2700 ////////////////////////////////////////////////////////////////////////////////
2701 /// Hide tool tip depending on the event type. Typically tool tips
2702 /// are hidden when event is not a kMouseEnter and not a kMouseMotion
2703 /// event.
2704 
2706 {
2707  if (event != kMouseEnter && event != kMouseMotion && fTip)
2708  gPad->CloseToolTip(fTip);
2709 }
2710 
2711 ////////////////////////////////////////////////////////////////////////////////
2712 /// Is pad in batch mode ?
2713 
2715 {
2716  return fCanvas ? fCanvas->IsBatch() : 0;
2717 }
2718 
2719 ////////////////////////////////////////////////////////////////////////////////
2720 /// Is pad retained ?
2721 
2723 {
2724  return fCanvas ? fCanvas->IsRetained() : 0;
2725 }
2726 
2727 ////////////////////////////////////////////////////////////////////////////////
2728 /// Is pad moving in opaque mode ?
2729 
2731 {
2732  return fCanvas ? fCanvas->OpaqueMoving() : 0;
2733 }
2734 
2735 ////////////////////////////////////////////////////////////////////////////////
2736 /// Is pad resizing in opaque mode ?
2737 
2739 {
2740  return fCanvas ? fCanvas->OpaqueResizing() : 0;
2741 }
2742 
2743 ////////////////////////////////////////////////////////////////////////////////
2744 /// Set pad in batch mode.
2745 
2747 {
2748  if (fCanvas) fCanvas->SetBatch(batch);
2749 }
2750 
2751 ////////////////////////////////////////////////////////////////////////////////
2752 /// Set canvas size.
2753 
2755 {
2756  if (fCanvas) fCanvas->SetCanvasSize(ww,wh);
2757 }
2758 
2759 ////////////////////////////////////////////////////////////////////////////////
2760 /// Set cursor type.
2761 
2763 {
2764  if (fCanvas) fCanvas->SetCursor(cursor);
2765 }
2766 
2767 ////////////////////////////////////////////////////////////////////////////////
2768 /// Set double buffer mode ON or OFF.
2769 
2771 {
2772  if (fCanvas) fCanvas->SetDoubleBuffer(mode);
2773 }
2774 
2775 ////////////////////////////////////////////////////////////////////////////////
2776 /// Set selected.
2777 
2779 {
2780  if (fCanvas) fCanvas->SetSelected(obj);
2781 }
2782 
2783 ////////////////////////////////////////////////////////////////////////////////
2784 /// Update pad.
2785 
2787 {
2788  if (fCanvas) fCanvas->Update();
2789 }
2790 
2791 ////////////////////////////////////////////////////////////////////////////////
2792 /// Get frame.
2793 
2795 {
2796  if (!fPrimitives) fPrimitives = new TList;
2798  if (!frame) frame = (TFrame*)GetListOfPrimitives()->FindObject("TFrame");
2799  fFrame = frame;
2800  if (!fFrame) {
2801  if (!frame) fFrame = new TFrame(0,0,1,1);
2802  Int_t framecolor = GetFrameFillColor();
2803  if (!framecolor) framecolor = GetFillColor();
2804  fFrame->SetFillColor(framecolor);
2811  }
2812  return fFrame;
2813 }
2814 
2815 ////////////////////////////////////////////////////////////////////////////////
2816 /// Get primitive.
2817 
2818 TObject *TPad::GetPrimitive(const char *name) const
2819 {
2820  if (!fPrimitives) return 0;
2821  TIter next(fPrimitives);
2822  TObject *found, *obj;
2823  while ((obj=next())) {
2824  if (!strcmp(name, obj->GetName())) return obj;
2825  if (obj->InheritsFrom(TPad::Class())) continue;
2826  found = obj->FindObject(name);
2827  if (found) return found;
2828  }
2829  return 0;
2830 }
2831 
2832 ////////////////////////////////////////////////////////////////////////////////
2833 /// Get a pointer to subpadnumber of this pad.
2834 
2835 TVirtualPad *TPad::GetPad(Int_t subpadnumber) const
2836 {
2837  if (!subpadnumber) {
2838  return (TVirtualPad*)this;
2839  }
2840 
2841  TObject *obj;
2842  if (!fPrimitives) return 0;
2843  TIter next(GetListOfPrimitives());
2844  while ((obj = next())) {
2845  if (obj->InheritsFrom(TVirtualPad::Class())) {
2846  TVirtualPad *pad = (TVirtualPad*)obj;
2847  if (pad->GetNumber() == subpadnumber) return pad;
2848  }
2849  }
2850  return 0;
2851 }
2852 
2853 ////////////////////////////////////////////////////////////////////////////////
2854 /// Return lower and upper bounds of the pad in NDC coordinates.
2855 
2856 void TPad::GetPadPar(Double_t &xlow, Double_t &ylow, Double_t &xup, Double_t &yup)
2857 {
2858  xlow = fXlowNDC;
2859  ylow = fYlowNDC;
2860  xup = fXlowNDC+fWNDC;
2861  yup = fYlowNDC+fHNDC;
2862 }
2863 
2864 ////////////////////////////////////////////////////////////////////////////////
2865 /// Return pad world coordinates range.
2866 
2868 {
2869  x1 = fX1;
2870  y1 = fY1;
2871  x2 = fX2;
2872  y2 = fY2;
2873 }
2874 
2875 ////////////////////////////////////////////////////////////////////////////////
2876 /// Return pad axis coordinates range.
2877 
2879 {
2880  xmin = fUxmin;
2881  ymin = fUymin;
2882  xmax = fUxmax;
2883  ymax = fUymax;
2884 }
2885 
2886 ////////////////////////////////////////////////////////////////////////////////
2887 /// Highlight pad.
2888 /// do not highlight when printing on Postscript
2889 
2891 {
2892  if (gVirtualPS && gVirtualPS->TestBit(kPrintingPS)) return;
2893 
2894  if (color <= 0) return;
2895 
2897 
2898  // We do not want to have active(executable) buttons, etc highlighted
2899  // in this manner, unless we want to edit'em
2900  if (GetMother() && GetMother()->IsEditable() && !InheritsFrom(TButton::Class())) {
2901  //When doing a DrawClone from the GUI you would do
2902  // - select an empty pad -
2903  // - right click on object -
2904  // - select DrawClone on menu -
2905  //
2906  // Without the SetSelectedPad(); in the HighLight function, the
2907  // above instruction lead to the clone to be drawn in the
2908  // same canvas as the original object. This is because the
2909  // 'right clicking' (via TCanvas::HandleInput) changes gPad
2910  // momentarily such that when DrawClone is called, it is
2911  // not the right value (for DrawClone). Should be FIXED.
2912  gROOT->SetSelectedPad(this);
2913  if (GetBorderMode()>0) {
2914  if (set) PaintBorder(-color, kFALSE);
2915  else PaintBorder(-GetFillColor(), kFALSE);
2916  }
2917  }
2918 
2920 }
2921 
2922 ////////////////////////////////////////////////////////////////////////////////
2923 /// List all primitives in pad.
2924 
2925 void TPad::ls(Option_t *option) const
2926 {
2928  std::cout <<IsA()->GetName()<<" fXlowNDC=" <<fXlowNDC<<" fYlowNDC="<<fYlowNDC<<" fWNDC="<<GetWNDC()<<" fHNDC="<<GetHNDC()
2929  <<" Name= "<<GetName()<<" Title= "<<GetTitle()<<" Option="<<option<<std::endl;
2931  if (!fPrimitives) return;
2932  fPrimitives->ls(option);
2934 }
2935 
2936 ////////////////////////////////////////////////////////////////////////////////
2937 /// Increment (i==1) or set (i>1) the number of autocolor in the pad.
2938 
2940 {
2941  if (opt.Index("pfc")>=0 || opt.Index("plc")>=0 || opt.Index("pmc")>=0) {
2942  if (i==1) fNumPaletteColor++;
2943  else fNumPaletteColor = i;
2944  return fNumPaletteColor;
2945  } else {
2946  return 0;
2947  }
2948 }
2949 
2950 ////////////////////////////////////////////////////////////////////////////////
2951 /// Get the next autocolor in the pad.
2952 
2954 {
2955  Int_t i = 0;
2956  Int_t ncolors = gStyle->GetNumberOfColors();
2957  if (fNumPaletteColor>1) {
2958  i = fNextPaletteColor*(ncolors/(fNumPaletteColor-1));
2959  if (i>=ncolors) i = ncolors-1;
2960  }
2963  return gStyle->GetColorPalette(i);
2964 }
2965 
2966 ////////////////////////////////////////////////////////////////////////////////
2967 /// Initialise the grid used to find empty space when adding a box (Legend) in a pad
2968 
2970 {
2971  Int_t const cellSize = 10; // Sive of an individual grid cell in pixels.
2972 
2973  if (fCGnx == 0 && fCGny == 0) {
2974  fCGnx = gPad->GetWw()/cellSize;
2975  fCGny = gPad->GetWh()/cellSize;
2976  } else {
2977  Int_t CGnx = gPad->GetWw()/cellSize;
2978  Int_t CGny = gPad->GetWh()/cellSize;
2979  if (fCGnx != CGnx || fCGny != CGny) {
2980  fCGnx = CGnx;
2981  fCGny = CGny;
2982  delete [] fCollideGrid;
2983  fCollideGrid = 0;
2984  }
2985  }
2986 
2987  // Initialise the collide grid
2988  if (!fCollideGrid) {
2989  fCollideGrid = new Bool_t [fCGnx*fCGny];
2990  for (int i = 0; i<fCGnx; i++) {
2991  for (int j = 0; j<fCGny; j++) {
2992  fCollideGrid[i + j*fCGnx] = kTRUE;
2993  }
2994  }
2995  }
2996 
2997  // Fill the collide grid
2999  Int_t np = l->GetSize();
3000  TObject *o;
3001 
3002  for (int i=0; i<np; i++) {
3003  o = (TObject *) l->At(i);
3004  if (o!=oi) {
3005  if (o->InheritsFrom(TFrame::Class())) { FillCollideGridTFrame(o); continue;}
3006  if (o->InheritsFrom(TBox::Class())) { FillCollideGridTBox(o); continue;}
3007  if (o->InheritsFrom(TH1::Class())) { FillCollideGridTH1(o); continue;}
3008  if (o->InheritsFrom(TGraph::Class())) { FillCollideGridTGraph(o); continue;}
3009  }
3010  }
3011 }
3012 
3013 ////////////////////////////////////////////////////////////////////////////////
3014 /// Check if a box of size w and h collide some primitives in the pad at
3015 /// position i,j
3016 
3018 {
3019  for (int r=i; r<w+i; r++) {
3020  for (int c=j; c<h+j; c++) {
3021  if (!fCollideGrid[r + c*fCGnx]) return kTRUE;
3022  }
3023  }
3024  return kFALSE;
3025 }
3026 
3027 ////////////////////////////////////////////////////////////////////////////////
3028 /// Place a box in NDC space
3029 
3031 {
3032  FillCollideGrid(o);
3033 
3034  Int_t iw = (int)(fCGnx*w);
3035  Int_t ih = (int)(fCGny*h);
3036 
3037  Int_t nxmax = fCGnx-iw-1;
3038  Int_t nymax = fCGny-ih-1;
3039 
3040  for (Int_t i = 0; i<nxmax; i++) {
3041  for (Int_t j = 0; j<=nymax; j++) {
3042  if (Collide(i,j,iw,ih)) {
3043  continue;
3044  } else {
3045  xl = (Double_t)(i)/(Double_t)(fCGnx);
3046  yb = (Double_t)(j)/(Double_t)(fCGny);
3047  return kTRUE;
3048  }
3049  }
3050  }
3051  return kFALSE;
3052 }
3053 
3054 #define NotFree(i, j) fCollideGrid[TMath::Max(TMath::Min(i+j*fCGnx,fCGnx*fCGny),0)] = kFALSE;
3055 
3056 ////////////////////////////////////////////////////////////////////////////////
3057 /// Mark as "not free" the cells along a line.
3058 
3060 {
3061  NotFree(x1, y1);
3062  NotFree(x2, y2);
3063  Int_t i, j, xt, yt;
3064 
3065  // horizontal lines
3066  if (y1==y2) {
3067  for (i=x1+1; i<x2; i++) NotFree(i,y1);
3068  return;
3069  }
3070 
3071  // vertical lines
3072  if (x1==x2) {
3073  for (i=y1+1; i<y2; i++) NotFree(x1,i);
3074  return;
3075  }
3076 
3077  // other lines
3078  if (TMath::Abs(x2-x1)>TMath::Abs(y2-y1)) {
3079  if (x1>x2) {
3080  xt = x1; x1 = x2; x2 = xt;
3081  yt = y1; y1 = y2; y2 = yt;
3082  }
3083  for (i=x1+1; i<x2; i++) {
3084  j = (Int_t)((Double_t)(y2-y1)*(Double_t)((i-x1)/(Double_t)(x2-x1))+y1);
3085  NotFree(i,j);
3086  NotFree(i,(j+1));
3087  }
3088  } else {
3089  if (y1>y2) {
3090  yt = y1; y1 = y2; y2 = yt;
3091  xt = x1; x1 = x2; x2 = xt;
3092  }
3093  for (j=y1+1; j<y2; j++) {
3094  i = (Int_t)((Double_t)(x2-x1)*(Double_t)((j-y1)/(Double_t)(y2-y1))+x1);
3095  NotFree(i,j);
3096  NotFree((i+1),j);
3097  }
3098  }
3099 }
3100 
3101 ////////////////////////////////////////////////////////////////////////////////
3103 {
3104  TBox *b = (TBox *)o;
3105 
3106  Double_t xs = (fX2-fX1)/fCGnx;
3107  Double_t ys = (fY2-fY1)/fCGny;
3108 
3109  Int_t x1 = (Int_t)((b->GetX1()-fX1)/xs);
3110  Int_t x2 = (Int_t)((b->GetX2()-fX1)/xs);
3111  Int_t y1 = (Int_t)((b->GetY1()-fY1)/ys);
3112  Int_t y2 = (Int_t)((b->GetY2()-fY1)/ys);
3113  for (int i = x1; i<=x2; i++) {
3114  for (int j = y1; j<=y2; j++) NotFree(i, j);
3115  }
3116 }
3117 
3118 ////////////////////////////////////////////////////////////////////////////////
3120 {
3121  TFrame *f = (TFrame *)o;
3122 
3123  Double_t xs = (fX2-fX1)/fCGnx;
3124  Double_t ys = (fY2-fY1)/fCGny;
3125 
3126  Int_t x1 = (Int_t)((f->GetX1()-fX1)/xs);
3127  Int_t x2 = (Int_t)((f->GetX2()-fX1)/xs);
3128  Int_t y1 = (Int_t)((f->GetY1()-fY1)/ys);
3129  Int_t y2 = (Int_t)((f->GetY2()-fY1)/ys);
3130  Int_t i;
3131 
3132  for (i = x1; i<=x2; i++) {
3133  NotFree(i, y1);
3134  NotFree(i, (y1-1));
3135  NotFree(i, (y1-2));
3136  }
3137  for (i = y1; i<=y2; i++) {
3138  NotFree(x1, i);
3139  NotFree((x1-1), i);
3140  NotFree((x1-2), i);
3141  }
3142 }
3143 
3144 ////////////////////////////////////////////////////////////////////////////////
3146 {
3147  TGraph *g = (TGraph *)o;
3148 
3149  Double_t xs = (fX2-fX1)/fCGnx;
3150  Double_t ys = (fY2-fY1)/fCGny;
3151 
3152  Int_t n = g->GetN();
3153  Double_t x1, x2, y1, y2;
3154 
3155  for (Int_t i=1; i<n; i++) {
3156  g->GetPoint(i-1,x1,y1);
3157  g->GetPoint(i ,x2,y2);
3158  if (fLogx) {
3159  if (x1 > 0) x1 = TMath::Log10(x1);
3160  else x1 = fUxmin;
3161  if (x2 > 0) x2 = TMath::Log10(x2);
3162  else x2 = fUxmin;
3163  }
3164  if (fLogy) {
3165  if (y1 > 0) y1 = TMath::Log10(y1);
3166  else y1 = fUymin;
3167  if (y2 > 0) y2 = TMath::Log10(y2);
3168  else y2 = fUymin;
3169  }
3170  LineNotFree((int)((x1-fX1)/xs), (int)((x2-fX1)/xs),
3171  (int)((y1-fY1)/ys), (int)((y2-fY1)/ys));
3172  }
3173 }
3174 
3175 ////////////////////////////////////////////////////////////////////////////////
3177 {
3178  TH1 *h = (TH1 *)o;
3179 
3180  if (o->InheritsFrom(TH2::Class())) return;
3181  if (o->InheritsFrom(TH3::Class())) return;
3182 
3183  TString name = h->GetName();
3184  if (name.Index("hframe") >= 0) return;
3185 
3186  Double_t xs = (fX2-fX1)/fCGnx;
3187  Double_t ys = (fY2-fY1)/fCGny;
3188 
3189  bool haserrors = false;
3190  TString drawOption = h->GetDrawOption();
3191  drawOption.ToLower();
3192  drawOption.ReplaceAll("same","");
3193 
3194  if (drawOption.Index("hist") < 0) {
3195  if (drawOption.Index("e") >= 0) haserrors = true;
3196  }
3197 
3198  Int_t nx = h->GetNbinsX();
3199  Int_t x1, y1, y2;
3200  Int_t i, j;
3201  Double_t x1l, y1l, y2l;
3202 
3203  for (i = 1; i<nx; i++) {
3204  if (haserrors) {
3205  x1l = h->GetBinCenter(i);
3206  if (fLogx) {
3207  if (x1l > 0) x1l = TMath::Log10(x1l);
3208  else x1l = fUxmin;
3209  }
3210  x1 = (Int_t)((x1l-fX1)/xs);
3211  y1l = h->GetBinContent(i)-h->GetBinErrorLow(i);
3212  if (fLogy) {
3213  if (y1l > 0) y1l = TMath::Log10(y1l);
3214  else y1l = fUymin;
3215  }
3216  y1 = (Int_t)((y1l-fY1)/ys);
3217  y2l = h->GetBinContent(i)+h->GetBinErrorUp(i);
3218  if (fLogy) {
3219  if (y2l > 0) y2l = TMath::Log10(y2l);
3220  else y2l = fUymin;
3221  }
3222  y2 = (Int_t)((y2l-fY1)/ys);
3223  for (j=y1; j<=y2; j++) {
3224  NotFree(x1, j);
3225  }
3226  }
3227  x1l = h->GetBinLowEdge(i);
3228  if (fLogx) {
3229  if (x1l > 0) x1l = TMath::Log10(x1l);
3230  else x1l = fUxmin;
3231  }
3232  x1 = (Int_t)((x1l-fX1)/xs);
3233  y1l = h->GetBinContent(i);
3234  if (fLogy) {
3235  if (y1l > 0) y1l = TMath::Log10(y1l);
3236  else y1l = fUymin;
3237  }
3238  y1 = (Int_t)((y1l-fY1)/ys);
3239  NotFree(x1, y1);
3240  x1l = h->GetBinLowEdge(i)+h->GetBinWidth(i);
3241  if (fLogx) {
3242  if (x1l > 0) x1l = TMath::Log10(x1l);
3243  else x1l = fUxmin;
3244  }
3245  x1 = (int)((x1l-fX1)/xs);
3246  NotFree(x1, y1);
3247  }
3248 
3249  // Extra objects in the list of function
3250  TPaveStats *ps = (TPaveStats*)h->GetListOfFunctions()->FindObject("stats");
3251  if (ps) FillCollideGridTBox(ps);
3252 }
3253 
3254 ////////////////////////////////////////////////////////////////////////////////
3255 /// This method draws the collide grid on top of the canvas. This is used for
3256 /// debugging only. At some point it will be removed.
3257 
3259 {
3260  auto box = new TBox();
3261  box->SetFillColorAlpha(kRed,0.5);
3262 
3263  Double_t xs = (fX2-fX1)/fCGnx;
3264  Double_t ys = (fY2-fY1)/fCGny;
3265 
3266  Double_t X1L, X2L, Y1L, Y2L;
3267  Double_t t = 0.15;
3268  Double_t Y1, Y2;
3269  Double_t X1 = fX1;
3270  Double_t X2 = X1+xs;
3271 
3272  for (int i = 0; i<fCGnx; i++) {
3273  Y1 = fY1;
3274  Y2 = Y1+ys;
3275  for (int j = 0; j<fCGny; j++) {
3276  if (gPad->GetLogx()) {
3277  X1L = TMath::Power(10,X1);
3278  X2L = TMath::Power(10,X2);
3279  } else {
3280  X1L = X1;
3281  X2L = X2;
3282  }
3283  if (gPad->GetLogy()) {
3284  Y1L = TMath::Power(10,Y1);
3285  Y2L = TMath::Power(10,Y2);
3286  } else {
3287  Y1L = Y1;
3288  Y2L = Y2;
3289  }
3290  if (!fCollideGrid[i + j*fCGnx]) {
3291  box->SetFillColorAlpha(kBlack,t);
3292  box->DrawBox(X1L, Y1L, X2L, Y2L);
3293  } else {
3294  box->SetFillColorAlpha(kRed,t);
3295  box->DrawBox(X1L, Y1L, X2L, Y2L);
3296  }
3297  Y1 = Y2;
3298  Y2 = Y1+ys;
3299  if (t==0.15) t = 0.1;
3300  else t = 0.15;
3301  }
3302  X1 = X2;
3303  X2 = X1+xs;
3304  }
3305 }
3306 
3307 
3308 ////////////////////////////////////////////////////////////////////////////////
3309 /// Convert x from pad to X.
3310 
3312 {
3313  if (fLogx && x < 50) return Double_t(TMath::Exp(2.302585092994*x));
3314  return x;
3315 }
3316 
3317 ////////////////////////////////////////////////////////////////////////////////
3318 /// Convert y from pad to Y.
3319 
3321 {
3322  if (fLogy && y < 50) return Double_t(TMath::Exp(2.302585092994*y));
3323  return y;
3324 }
3325 
3326 ////////////////////////////////////////////////////////////////////////////////
3327 /// Convert x from X to pad.
3328 
3330 {
3331  if (fLogx) {
3332  if (x > 0) x = TMath::Log10(x);
3333  else x = fUxmin;
3334  }
3335  return x;
3336 }
3337 
3338 ////////////////////////////////////////////////////////////////////////////////
3339 /// Convert y from Y to pad.
3340 
3342 {
3343  if (fLogy) {
3344  if (y > 0) y = TMath::Log10(y);
3345  else y = fUymin;
3346  }
3347  return y;
3348 }
3349 
3350 ////////////////////////////////////////////////////////////////////////////////
3351 /// Paint all primitives in pad.
3352 
3353 void TPad::Paint(Option_t * /*option*/)
3354 {
3355  if (!fPrimitives) fPrimitives = new TList;
3357  fViewer3D->PadPaint(this);
3358  Modified(kFALSE);
3359  if (GetGLDevice()!=-1 && gVirtualPS) {
3360  TPad *padsav = (TPad*)gPad;
3361  gPad = this;
3362  gGLManager->PrintViewer(GetViewer3D());
3363  gPad = padsav;
3364  }
3365  return;
3366  }
3367 
3369 
3370  TPad *padsav = (TPad*)gPad;
3371 
3372  fPadPaint = 1;
3373  cd();
3374 
3376  PaintDate();
3377 
3379  TObject *obj;
3380 
3381  Bool_t began3DScene = kFALSE;
3382  while (lnk) {
3383  obj = lnk->GetObject();
3384 
3385  // Create a pad 3D viewer if none exists and we encounter a 3D shape
3386  if (!fViewer3D && obj->InheritsFrom(TAtt3D::Class())) {
3387  GetViewer3D("pad");
3388  }
3389 
3390  // Open a 3D scene if required
3391  if (fViewer3D && !fViewer3D->BuildingScene()) {
3392  fViewer3D->BeginScene();
3393  began3DScene = kTRUE;
3394  }
3395 
3396  obj->Paint(lnk->GetOption());
3397  lnk = (TObjOptLink*)lnk->Next();
3398  }
3399 
3400  if (padsav) padsav->cd();
3401  fPadPaint = 0;
3402  Modified(kFALSE);
3403 
3404  // Close the 3D scene if we opened it. This must be done after modified
3405  // flag is cleared, as some viewers will invoke another paint by marking pad modified again
3406  if (began3DScene) {
3407  fViewer3D->EndScene();
3408  }
3409 }
3410 
3411 ////////////////////////////////////////////////////////////////////////////////
3412 /// Paint the pad border.
3413 /// Draw first a box as a normal filled box
3414 
3416 {
3417  if(color >= 0) {
3418  TAttLine::Modify(); //Change line attributes only if necessary
3419  TAttFill::Modify(); //Change fill area attributes only if necessary
3420 
3421  //With Cocoa we have a transparency. But we also have
3422  //pixmaps, and if you just paint a new content over the old one
3423  //with alpha < 1., you'll be able to see the old content.
3424  if (!gROOT->IsBatch() && gVirtualX->InheritsFrom("TGCocoa") && GetPainter())
3426 
3427  PaintBox(fX1,fY1,fX2,fY2);
3428  }
3429  if (color < 0) color = -color;
3430  // then paint 3d frame (depending on bordermode)
3431  if (IsTransparent()) return;
3432  // Paint a 3D frame around the pad.
3433 
3434  if (fBorderMode == 0) return;
3435  Int_t bordersize = fBorderSize;
3436  if (bordersize <= 0) bordersize = 2;
3437 
3438  const Double_t realBsX = bordersize / (GetAbsWNDC() * GetWw()) * (fX2 - fX1);
3439  const Double_t realBsY = bordersize / (GetAbsHNDC() * GetWh()) * (fY2 - fY1);
3440 
3441  Short_t px1,py1,px2,py2;
3442  Double_t xl, xt, yl, yt;
3443 
3444  // GetDarkColor() and GetLightColor() use GetFillColor()
3445  Color_t oldcolor = GetFillColor();
3446  SetFillColor(color);
3447  TAttFill::Modify();
3448  Color_t light = 0, dark = 0;
3449  if (color != 0) {
3450  light = TColor::GetColorBright(color);
3451  dark = TColor::GetColorDark(color);
3452  }
3453 
3454  // Compute real left bottom & top right of the box in pixels
3455  px1 = XtoPixel(fX1); py1 = YtoPixel(fY1);
3456  px2 = XtoPixel(fX2); py2 = YtoPixel(fY2);
3457  if (px1 < px2) {xl = fX1; xt = fX2; }
3458  else {xl = fX2; xt = fX1;}
3459  if (py1 > py2) {yl = fY1; yt = fY2;}
3460  else {yl = fY2; yt = fY1;}
3461 
3462  Double_t frameXs[7] = {}, frameYs[7] = {};
3463 
3464  if (!IsBatch()) {
3465  // Draw top&left part of the box
3466  frameXs[0] = xl; frameYs[0] = yl;
3467  frameXs[1] = xl + realBsX; frameYs[1] = yl + realBsY;
3468  frameXs[2] = frameXs[1]; frameYs[2] = yt - realBsY;
3469  frameXs[3] = xt - realBsX; frameYs[3] = frameYs[2];
3470  frameXs[4] = xt; frameYs[4] = yt;
3471  frameXs[5] = xl; frameYs[5] = yt;
3472  frameXs[6] = xl; frameYs[6] = yl;
3473 
3474  if (fBorderMode == -1) GetPainter()->SetFillColor(dark);
3475  else GetPainter()->SetFillColor(light);
3476  GetPainter()->DrawFillArea(7, frameXs, frameYs);
3477 
3478  // Draw bottom&right part of the box
3479  frameXs[0] = xl; frameYs[0] = yl;
3480  frameXs[1] = xl + realBsX; frameYs[1] = yl + realBsY;
3481  frameXs[2] = xt - realBsX; frameYs[2] = frameYs[1];
3482  frameXs[3] = frameXs[2]; frameYs[3] = yt - realBsY;
3483  frameXs[4] = xt; frameYs[4] = yt;
3484  frameXs[5] = xt; frameYs[5] = yl;
3485  frameXs[6] = xl; frameYs[6] = yl;
3486 
3487  if (fBorderMode == -1) GetPainter()->SetFillColor(light);
3488  else GetPainter()->SetFillColor(dark);
3489  GetPainter()->DrawFillArea(7, frameXs, frameYs);
3490 
3491  // If this pad is a button, highlight it
3492  if (InheritsFrom(TButton::Class()) && fBorderMode == -1) {
3493  if (TestBit(kFraming)) { // bit set in TButton::SetFraming
3494  if (GetFillColor() != 2) GetPainter()->SetLineColor(2);
3495  else GetPainter()->SetLineColor(4);
3496  GetPainter()->DrawBox(xl + realBsX, yl + realBsY, xt - realBsX, yt - realBsY, TVirtualPadPainter::kHollow);
3497  }
3498  }
3499  GetPainter()->SetFillColor(-1);
3500  SetFillColor(oldcolor);
3501  }
3502 
3503  if (!tops) return;
3504 
3505  PaintBorderPS(xl, yl, xt, yt, fBorderMode, bordersize, dark, light);
3506 }
3507 
3508 ////////////////////////////////////////////////////////////////////////////////
3509 /// Paint a frame border with Postscript.
3510 
3512 {
3513  if (!gVirtualPS) return;
3514  gVirtualPS->DrawFrame(xl, yl, xt, yt, bmode,bsize,dark,light);
3515 }
3516 
3517 ////////////////////////////////////////////////////////////////////////////////
3518 /// Paint the current date and time if the option date is on.
3519 
3521 {
3522  if (fCanvas == this && gStyle->GetOptDate()) {
3523  TDatime dt;
3524  const char *dates;
3525  char iso[16];
3526  if (gStyle->GetOptDate() < 10) {
3527  //by default use format like "Wed Sep 25 17:10:35 2002"
3528  dates = dt.AsString();
3529  } else if (gStyle->GetOptDate() < 20) {
3530  //use ISO format like 2002-09-25
3531  strlcpy(iso,dt.AsSQLString(),16);
3532  dates = iso;
3533  } else {
3534  //use ISO format like 2002-09-25 17:10:35
3535  dates = dt.AsSQLString();
3536  }
3537  TText tdate(gStyle->GetDateX(),gStyle->GetDateY(),dates);
3538  tdate.SetTextSize( gStyle->GetAttDate()->GetTextSize());
3539  tdate.SetTextFont( gStyle->GetAttDate()->GetTextFont());
3540  tdate.SetTextColor(gStyle->GetAttDate()->GetTextColor());
3541  tdate.SetTextAlign(gStyle->GetAttDate()->GetTextAlign());
3542  tdate.SetTextAngle(gStyle->GetAttDate()->GetTextAngle());
3543  tdate.SetNDC();
3544  tdate.Paint();
3545  }
3546 }
3547 
3548 ////////////////////////////////////////////////////////////////////////////////
3549 /// Paint histogram/graph frame.
3550 
3552 {
3553  if (!fPrimitives) fPrimitives = new TList;
3554  TList *glist = GetListOfPrimitives();
3555  TFrame *frame = GetFrame();
3556  frame->SetX1(xmin);
3557  frame->SetX2(xmax);
3558  frame->SetY1(ymin);
3559  frame->SetY2(ymax);
3560  if (!glist->FindObject(fFrame)) {
3561  glist->AddFirst(frame);
3563  }
3564  frame->Paint();
3565 }
3566 
3567 ////////////////////////////////////////////////////////////////////////////////
3568 /// Traverse pad hierarchy and (re)paint only modified pads.
3569 
3571 {
3573  if (IsModified()) {
3574  fViewer3D->PadPaint(this);
3575  Modified(kFALSE);
3576  }
3577  TList *pList = GetListOfPrimitives();
3578  TObjOptLink *lnk = 0;
3579  if (pList) lnk = (TObjOptLink*)pList->FirstLink();
3580  TObject *obj;
3581  while (lnk) {
3582  obj = lnk->GetObject();
3583  if (obj->InheritsFrom(TPad::Class()))
3584  ((TPad*)obj)->PaintModified();
3585  lnk = (TObjOptLink*)lnk->Next();
3586  }
3587  return;
3588  }
3589 
3591 
3592  TPad *padsav = (TPad*)gPad;
3593  TVirtualPS *saveps = gVirtualPS;
3594  if (gVirtualPS) {
3596  }
3597  fPadPaint = 1;
3598  cd();
3599  if (IsModified() || IsTransparent()) {
3600  if ((fFillStyle < 3026) && (fFillStyle > 3000)) {
3601  if (!gPad->IsBatch()) GetPainter()->ClearDrawable();
3602  }
3604  }
3605 
3606  PaintDate();
3607 
3608  TList *pList = GetListOfPrimitives();
3609  TObjOptLink *lnk = 0;
3610  if (pList) lnk = (TObjOptLink*)pList->FirstLink();
3611  TObject *obj;
3612 
3613  Bool_t began3DScene = kFALSE;
3614 
3615  while (lnk) {
3616  obj = lnk->GetObject();
3617  if (obj->InheritsFrom(TPad::Class())) {
3618  ((TPad*)obj)->PaintModified();
3619  } else if (IsModified() || IsTransparent()) {
3620 
3621  // Create a pad 3D viewer if none exists and we encounter a
3622  // 3D shape
3623  if (!fViewer3D && obj->InheritsFrom(TAtt3D::Class())) {
3624  GetViewer3D("pad");
3625  }
3626 
3627  // Open a 3D scene if required
3628  if (fViewer3D && !fViewer3D->BuildingScene()) {
3629  fViewer3D->BeginScene();
3630  began3DScene = kTRUE;
3631  }
3632 
3633  obj->Paint(lnk->GetOption());
3634  }
3635  lnk = (TObjOptLink*)lnk->Next();
3636  }
3637 
3638  if (padsav) padsav->cd();
3639  fPadPaint = 0;
3640  Modified(kFALSE);
3641 
3642  // This must be done after modified flag is cleared, as some
3643  // viewers will invoke another paint by marking pad modified again
3644  if (began3DScene) {
3645  fViewer3D->EndScene();
3646  }
3647 
3648  gVirtualPS = saveps;
3649 }
3650 
3651 ////////////////////////////////////////////////////////////////////////////////
3652 /// Paint box in CurrentPad World coordinates.
3653 ///
3654 /// - if option[0] = 's' the box is forced to be paint with style=0
3655 /// - if option[0] = 'l' the box contour is drawn
3656 
3658 {
3659  if (!gPad->IsBatch()) {
3660  Int_t style0 = GetPainter()->GetFillStyle();
3661  Int_t style = style0;
3662  if (option[0] == 's') {
3663  GetPainter()->SetFillStyle(0);
3664  style = 0;
3665  }
3666  if (style) {
3667  if (style > 3000 && style < 4000) {
3668  if (style < 3026) {
3669  // draw stipples with fFillColor foreground
3670  GetPainter()->DrawBox(x1, y1, x2, y2, TVirtualPadPainter::kFilled);
3671  }
3672 
3673  if (style >= 3100 && style < 4000) {
3674  Double_t xb[4], yb[4];
3675  xb[0] = x1; xb[1] = x1; xb[2] = x2; xb[3] = x2;
3676  yb[0] = y1; yb[1] = y2; yb[2] = y2; yb[3] = y1;
3677  PaintFillAreaHatches(4, xb, yb, style);
3678  return;
3679  }
3680  //special case for TAttFillCanvas
3681  if (GetPainter()->GetFillColor() == 10) {
3682  GetPainter()->SetFillColor(1);
3683  GetPainter()->DrawBox(x1, y1, x2, y2, TVirtualPadPainter::kFilled);
3684  GetPainter()->SetFillColor(10);
3685  }
3686  } else if (style >= 4000 && style <= 4100) {
3687  // For style >=4000 we make the window transparent.
3688  // From 4000 to 4100 the window is 100% transparent to 100% opaque
3689 
3690  //ignore this style option when this is the canvas itself
3691  if (this == fMother) {
3692  //It's clear, that virtual X checks a style (4000) and will render a hollow rect!
3693  const Style_t oldFillStyle = GetPainter()->GetFillStyle();
3694  if (gVirtualX->InheritsFrom("TGCocoa"))
3695  GetPainter()->SetFillStyle(1000);
3696  GetPainter()->DrawBox(x1, y1, x2, y2, TVirtualPadPainter::kFilled);
3697  if (gVirtualX->InheritsFrom("TGCocoa"))
3698  GetPainter()->SetFillStyle(oldFillStyle);
3699  } else {
3700  //draw background by blitting all bottom pads
3701  int px, py;
3702  XYtoAbsPixel(fX1, fY2, px, py);
3703 
3704  if (fMother) {
3705  fMother->CopyBackgroundPixmap(px, py);
3706  CopyBackgroundPixmaps(fMother, this, px, py);
3707  }
3708 
3709  GetPainter()->SetOpacity(style - 4000);
3710  }
3711  } else if (style >= 1000 && style <= 1999) {
3712  GetPainter()->DrawBox(x1, y1, x2, y2, TVirtualPadPainter::kFilled);
3713  } else {
3714  GetPainter()->DrawBox(x1, y1, x2, y2, TVirtualPadPainter::kHollow);
3715  }
3716  if (option[0] == 'l') GetPainter()->DrawBox(x1, y1, x2, y2, TVirtualPadPainter::kHollow);
3717  } else {
3718  GetPainter()->DrawBox(x1, y1, x2, y2, TVirtualPadPainter::kHollow);
3719  if (option[0] == 's') GetPainter()->SetFillStyle(style0);
3720  }
3721  }
3722 
3723  if (gVirtualPS) {
3724  Int_t style0 = gVirtualPS->GetFillStyle();
3725  if (option[0] == 's') {
3727  } else {
3728  if (style0 >= 3100 && style0 < 4000) {
3729  Double_t xb[4], yb[4];
3730  xb[0] = x1; xb[1] = x1; xb[2] = x2; xb[3] = x2;
3731  yb[0] = y1; yb[1] = y2; yb[2] = y2; yb[3] = y1;
3732  PaintFillAreaHatches(4, xb, yb, style0);
3733  return;
3734  }
3735  }
3736  gVirtualPS->DrawBox(x1, y1, x2, y2);
3737  if (option[0] == 'l') {
3739  gVirtualPS->DrawBox(x1, y1, x2, y2);
3740  }
3741  if (option[0] == 's' || option[0] == 'l') gVirtualPS->SetFillStyle(style0);
3742  }
3743 
3744  Modified();
3745 }
3746 
3747 ////////////////////////////////////////////////////////////////////////////////
3748 /// Copy pixmaps of pads laying below pad "stop" into pad "stop". This
3749 /// gives the effect of pad "stop" being transparent.
3750 
3752 {
3753  TObject *obj;
3754  if (!fPrimitives) fPrimitives = new TList;
3755  TIter next(start->GetListOfPrimitives());
3756  while ((obj = next())) {
3757  if (obj->InheritsFrom(TPad::Class())) {
3758  if (obj == stop) break;
3759  ((TPad*)obj)->CopyBackgroundPixmap(x, y);
3760  ((TPad*)obj)->CopyBackgroundPixmaps((TPad*)obj, stop, x, y);
3761  }
3762  }
3763 }
3764 
3765 ////////////////////////////////////////////////////////////////////////////////
3766 /// Copy pixmap of this pad as background of the current pad.
3767 
3769 {
3770  int px, py;
3771  XYtoAbsPixel(fX1, fY2, px, py);
3772  GetPainter()->CopyDrawable(GetPixmapID(), px-x, py-y);
3773 }
3774 
3775 ////////////////////////////////////////////////////////////////////////////////
3776 
3778 {
3779  Warning("TPad::PaintFillArea", "Float_t signature is obsolete. Use Double_t signature.");
3780 }
3781 
3782 ////////////////////////////////////////////////////////////////////////////////
3783 /// Paint fill area in CurrentPad World coordinates.
3784 
3786 {
3787  if (nn <3) return;
3788  Int_t n=0;
3790  if (TestBit(TGraph::kClipFrame)) {
3791  xmin = fUxmin; ymin = fUymin; xmax = fUxmax; ymax = fUymax;
3792  } else {
3793  xmin = fX1; ymin = fY1; xmax = fX2; ymax = fY2;
3794  }
3795 
3796  Int_t nc = 2*nn+1;
3797  Double_t *x = new Double_t[nc];
3798  Double_t *y = new Double_t[nc];
3799  memset(x,0,8*nc);
3800  memset(y,0,8*nc);
3801 
3802  n = ClipPolygon(nn, xx, yy, nc, x, y,xmin,ymin,xmax,ymax);
3803  if (!n) {
3804  delete [] x;
3805  delete [] y;
3806  return;
3807  }
3808 
3809  // Paint the fill area with hatches
3810  Int_t fillstyle = GetPainter()->GetFillStyle();
3811  if (gPad->IsBatch() && gVirtualPS) fillstyle = gVirtualPS->GetFillStyle();
3812  if (fillstyle >= 3100 && fillstyle < 4000) {
3813  PaintFillAreaHatches(nn, x, y, fillstyle);
3814  delete [] x;
3815  delete [] y;
3816  return;
3817  }
3818 
3819  if (!gPad->IsBatch())
3820  // invoke the graphics subsystem
3821  GetPainter()->DrawFillArea(n, x, y);
3822 
3823  if (gVirtualPS) {
3824  gVirtualPS->DrawPS(-n, x, y);
3825  }
3826  delete [] x;
3827  delete [] y;
3828  Modified();
3829 }
3830 
3831 ////////////////////////////////////////////////////////////////////////////////
3832 /// This function paints hatched fill area according to the FillStyle value
3833 /// The convention for the Hatch is the following:
3834 ///
3835 /// `FillStyle = 3ijk`
3836 ///
3837 /// - i (1-9) : specify the space between each hatch
3838 /// 1 = minimum 9 = maximum
3839 /// the final spacing is i*GetHatchesSpacing(). The hatches spacing
3840 /// is set by SetHatchesSpacing()
3841 /// - j (0-9) : specify angle between 0 and 90 degrees
3842 /// * 0 = 0
3843 /// * 1 = 10
3844 /// * 2 = 20
3845 /// * 3 = 30
3846 /// * 4 = 45
3847 /// * 5 = Not drawn
3848 /// * 6 = 60
3849 /// * 7 = 70
3850 /// * 8 = 80
3851 /// * 9 = 90
3852 /// - k (0-9) : specify angle between 90 and 180 degrees
3853 /// * 0 = 180
3854 /// * 1 = 170
3855 /// * 2 = 160
3856 /// * 3 = 150
3857 /// * 4 = 135
3858 /// * 5 = Not drawn
3859 /// * 6 = 120
3860 /// * 7 = 110
3861 /// * 8 = 100
3862 /// * 9 = 90
3863 
3865 {
3866  static Double_t ang1[10] = {0., 10., 20., 30., 45.,5., 60., 70., 80., 90.};
3867  static Double_t ang2[10] = {180.,170.,160.,150.,135.,5.,120.,110.,100., 90.};
3868 
3869  Int_t fasi = FillStyle%1000;
3870  Int_t idSPA = (Int_t)(fasi/100);
3871  Int_t iAng2 = (Int_t)((fasi-100*idSPA)/10);
3872  Int_t iAng1 = fasi%10;
3873  Double_t dy = 0.003*(Double_t)(idSPA)*gStyle->GetHatchesSpacing();
3875  Short_t lws = 0;
3876  Int_t lss = 0;
3877  Int_t lcs = 0;
3878 
3879  // Save the current line attributes
3880  if (!gPad->IsBatch()) {
3881  lws = GetPainter()->GetLineWidth();
3882  lss = GetPainter()->GetLineStyle();
3883  lcs = GetPainter()->GetLineColor();
3884  } else {
3885  if (gVirtualPS) {
3886  lws = gVirtualPS->GetLineWidth();
3887  lss = gVirtualPS->GetLineStyle();
3888  lcs = gVirtualPS->GetLineColor();
3889  }
3890  }
3891 
3892  // Change the current line attributes to draw the hatches
3893  if (!gPad->IsBatch()) {
3894  GetPainter()->SetLineStyle(1);
3897  }
3898  if (gVirtualPS) {
3902  }
3903 
3904  // Draw the hatches
3905  if (ang1[iAng1] != 5.) PaintHatches(dy, ang1[iAng1], nn, xx, yy);
3906  if (ang2[iAng2] != 5.) PaintHatches(dy, ang2[iAng2], nn, xx, yy);
3907 
3908  // Restore the line attributes
3909  if (!gPad->IsBatch()) {
3910  GetPainter()->SetLineStyle(lss);
3911  GetPainter()->SetLineWidth(lws);
3912  GetPainter()->SetLineColor(lcs);
3913  }
3914  if (gVirtualPS) {
3915  gVirtualPS->SetLineStyle(lss);
3916  gVirtualPS->SetLineWidth(lws);
3917  gVirtualPS->SetLineColor(lcs);
3918  }
3919 }
3920 
3921 ////////////////////////////////////////////////////////////////////////////////
3922 /// This routine draw hatches inclined with the
3923 /// angle "angle" and spaced of "dy" in normalized device
3924 /// coordinates in the surface defined by n,xx,yy.
3925 
3927  Int_t nn, Double_t *xx, Double_t *yy)
3928 {
3929  Int_t i, i1, i2, nbi, m, inv;
3930  Double_t ratiox, ratioy, ymin, ymax, yrot, ycur;
3931  const Double_t angr = TMath::Pi()*(180-angle)/180.;
3932  const Double_t epsil = 0.0001;
3933  const Int_t maxnbi = 100;
3934  Double_t xli[maxnbi], xlh[2], ylh[2], xt1, xt2, yt1, yt2;
3935  Double_t ll, x, y, x1, x2, y1, y2, a, b, xi, xip, xin, yi, yip;
3936 
3937  Double_t rwxmin = gPad->GetX1();
3938  Double_t rwxmax = gPad->GetX2();
3939  Double_t rwymin = gPad->GetY1();
3940  Double_t rwymax = gPad->GetY2();
3941  ratiox = 1/(rwxmax-rwxmin);
3942  ratioy = 1/(rwymax-rwymin);
3943 
3944  Double_t sina = TMath::Sin(angr), sinb;
3945  Double_t cosa = TMath::Cos(angr), cosb;
3946  if (TMath::Abs(cosa) <= epsil) cosa=0.;
3947  if (TMath::Abs(sina) <= epsil) sina=0.;
3948  sinb = -sina;
3949  cosb = cosa;
3950 
3951  // Values needed to compute the hatches in TRUE normalized space (NDC)
3952  Int_t iw = gPad->GetWw();
3953  Int_t ih = gPad->GetWh();
3954  Double_t x1p,y1p,x2p,y2p;
3955  gPad->GetPadPar(x1p,y1p,x2p,y2p);
3956  iw = (Int_t)(iw*x2p)-(Int_t)(iw*x1p);
3957  ih = (Int_t)(ih*y2p)-(Int_t)(ih*y1p);
3958  Double_t wndc = TMath::Min(1.,(Double_t)iw/(Double_t)ih);
3959  Double_t hndc = TMath::Min(1.,(Double_t)ih/(Double_t)iw);
3960 
3961  // Search ymin and ymax
3962  ymin = 1.;
3963  ymax = 0.;
3964  for (i=1; i<=nn; i++) {
3965  x = wndc*ratiox*(xx[i-1]-rwxmin);
3966  y = hndc*ratioy*(yy[i-1]-rwymin);
3967  yrot = sina*x+cosa*y;
3968  if (yrot > ymax) ymax = yrot;
3969  if (yrot < ymin) ymin = yrot;
3970  }
3971  ymax = (Double_t)((Int_t)(ymax/dy))*dy;
3972 
3973  for (ycur=ymax; ycur>=ymin; ycur=ycur-dy) {
3974  nbi = 0;
3975  for (i=2; i<=nn+1; i++) {
3976  i2 = i;
3977  i1 = i-1;
3978  if (i == nn+1) i2=1;
3979  x1 = wndc*ratiox*(xx[i1-1]-rwxmin);
3980  y1 = hndc*ratioy*(yy[i1-1]-rwymin);
3981  x2 = wndc*ratiox*(xx[i2-1]-rwxmin);
3982  y2 = hndc*ratioy*(yy[i2-1]-rwymin);
3983  xt1 = cosa*x1-sina*y1;
3984  yt1 = sina*x1+cosa*y1;
3985  xt2 = cosa*x2-sina*y2;
3986  yt2 = sina*x2+cosa*y2;
3987 
3988  // Line segment parallel to oy
3989  if (xt1 == xt2) {
3990  if (yt1 < yt2) {
3991  yi = yt1;
3992  yip = yt2;
3993  } else {
3994  yi = yt2;
3995  yip = yt1;
3996  }
3997  if ((yi <= ycur) && (ycur < yip)) {
3998  nbi++;
3999  if (nbi >= maxnbi) return;
4000  xli[nbi-1] = xt1;
4001  }
4002  continue;
4003  }
4004 
4005  // Line segment parallel to ox
4006  if (yt1 == yt2) {
4007  if (yt1 == ycur) {
4008  nbi++;
4009  if (nbi >= maxnbi) return;
4010  xli[nbi-1] = xt1;
4011  nbi++;
4012  if (nbi >= maxnbi) return;
4013  xli[nbi-1] = xt2;
4014  }
4015  continue;
4016  }
4017 
4018  // Other line segment
4019  a = (yt1-yt2)/(xt1-xt2);
4020  b = (yt2*xt1-xt2*yt1)/(xt1-xt2);
4021  if (xt1 < xt2) {
4022  xi = xt1;
4023  xip = xt2;
4024  } else {
4025  xi = xt2;
4026  xip = xt1;
4027  }
4028  xin = (ycur-b)/a;
4029  if ((xi <= xin) && (xin < xip) &&
4030  (TMath::Min(yt1,yt2) <= ycur) &&
4031  (ycur < TMath::Max(yt1,yt2))) {
4032  nbi++;
4033  if (nbi >= maxnbi) return;
4034  xli[nbi-1] = xin;
4035  }
4036  }
4037 
4038  // Sorting of the x coordinates intersections
4039  inv = 0;
4040  m = nbi-1;
4041 L30:
4042  for (i=1; i<=m; i++) {
4043  if (xli[i] < xli[i-1]) {
4044  inv++;
4045  ll = xli[i-1];
4046  xli[i-1] = xli[i];
4047  xli[i] = ll;
4048  }
4049  }
4050  m--;
4051  if (inv == 0) goto L50;
4052  inv = 0;
4053  goto L30;
4054 
4055  // Draw the hatches
4056 L50:
4057  if (nbi%2 != 0) continue;
4058 
4059  for (i=1; i<=nbi; i=i+2) {
4060  // Rotate back the hatches
4061  xlh[0] = cosb*xli[i-1]-sinb*ycur;
4062  ylh[0] = sinb*xli[i-1]+cosb*ycur;
4063  xlh[1] = cosb*xli[i] -sinb*ycur;
4064  ylh[1] = sinb*xli[i] +cosb*ycur;
4065  // Convert hatches' positions from true NDC to WC
4066  xlh[0] = (xlh[0]/wndc)*(rwxmax-rwxmin)+rwxmin;
4067  ylh[0] = (ylh[0]/hndc)*(rwymax-rwymin)+rwymin;
4068  xlh[1] = (xlh[1]/wndc)*(rwxmax-rwxmin)+rwxmin;
4069  ylh[1] = (ylh[1]/hndc)*(rwymax-rwymin)+rwymin;
4070  gPad->PaintLine(xlh[0], ylh[0], xlh[1], ylh[1]);
4071  }
4072  }
4073 }
4074 
4075 ////////////////////////////////////////////////////////////////////////////////
4076 /// Paint line in CurrentPad World coordinates.
4077 
4079 {
4080  Double_t x[2], y[2];
4081  x[0] = x1; x[1] = x2; y[0] = y1; y[1] = y2;
4082 
4083  //If line is totally clipped, return
4084  if (TestBit(TGraph::kClipFrame)) {
4085  if (Clip(x,y,fUxmin,fUymin,fUxmax,fUymax) == 2) return;
4086  } else {
4087  if (Clip(x,y,fX1,fY1,fX2,fY2) == 2) return;
4088  }
4089 
4090  if (!gPad->IsBatch())
4091  GetPainter()->DrawLine(x[0], y[0], x[1], y[1]);
4092 
4093  if (gVirtualPS) {
4094  gVirtualPS->DrawPS(2, x, y);
4095  }
4096 
4097  Modified();
4098 }
4099 
4100 ////////////////////////////////////////////////////////////////////////////////
4101 /// Paint line in normalized coordinates.
4102 
4104 {
4105  static Double_t xw[2], yw[2];
4106  if (!gPad->IsBatch())
4107  GetPainter()->DrawLineNDC(u1, v1, u2, v2);
4108 
4109  if (gVirtualPS) {
4110  xw[0] = fX1 + u1*(fX2 - fX1);
4111  xw[1] = fX1 + u2*(fX2 - fX1);
4112  yw[0] = fY1 + v1*(fY2 - fY1);
4113  yw[1] = fY1 + v2*(fY2 - fY1);
4114  gVirtualPS->DrawPS(2, xw, yw);
4115  }
4116 
4117  Modified();
4118 }
4119 
4120 ////////////////////////////////////////////////////////////////////////////////
4121 /// Paint 3-D line in the CurrentPad.
4122 
4124 {
4125  if (!fView) return;
4126 
4127  // convert from 3-D to 2-D pad coordinate system
4128  Double_t xpad[6];
4129  Double_t temp[3];
4130  Int_t i;
4131  for (i=0;i<3;i++) temp[i] = p1[i];
4132  fView->WCtoNDC(temp, &xpad[0]);
4133  for (i=0;i<3;i++) temp[i] = p2[i];
4134  fView->WCtoNDC(temp, &xpad[3]);
4135  PaintLine(xpad[0],xpad[1],xpad[3],xpad[4]);
4136 }
4137 
4138 ////////////////////////////////////////////////////////////////////////////////
4139 /// Paint 3-D line in the CurrentPad.
4140 
4142 {
4143  //take into account perspective view
4144  if (!fView) return;
4145  // convert from 3-D to 2-D pad coordinate system
4146  Double_t xpad[6];
4147  Double_t temp[3];
4148  Int_t i;
4149  for (i=0;i<3;i++) temp[i] = p1[i];
4150  fView->WCtoNDC(temp, &xpad[0]);
4151  for (i=0;i<3;i++) temp[i] = p2[i];
4152  fView->WCtoNDC(temp, &xpad[3]);
4153  PaintLine(xpad[0],xpad[1],xpad[3],xpad[4]);
4154 }
4155 
4156 ////////////////////////////////////////////////////////////////////////////////
4157 /// Paint polyline in CurrentPad World coordinates.
4158 
4160 {
4161  if (n < 2) return;
4162 
4164  if (TestBit(TGraph::kClipFrame)) {
4165  xmin = fUxmin; ymin = fUymin; xmax = fUxmax; ymax = fUymax;
4166  } else {
4167  xmin = fX1; ymin = fY1; xmax = fX2; ymax = fY2;
4168  }
4169  Int_t i, i1=-1,np=1;
4170  for (i=0; i<n-1; i++) {
4171  Double_t x1=x[i];
4172  Double_t y1=y[i];
4173  Double_t x2=x[i+1];
4174  Double_t y2=y[i+1];
4175  Int_t iclip = Clip(&x[i],&y[i],xmin,ymin,xmax,ymax);
4176  if (iclip == 2) {
4177  i1 = -1;
4178  continue;
4179  }
4180  np++;
4181  if (i1 < 0) i1 = i;
4182  if (iclip == 0 && i < n-2) continue;
4183  if (!gPad->IsBatch())
4184  GetPainter()->DrawPolyLine(np, &x[i1], &y[i1]);
4185  if (gVirtualPS) {
4186  gVirtualPS->DrawPS(np, &x[i1], &y[i1]);
4187  }
4188  if (iclip) {
4189  x[i] = x1;
4190  y[i] = y1;
4191  x[i+1] = x2;
4192  y[i+1] = y2;
4193  }
4194  i1 = -1;
4195  np = 1;
4196  }
4197 
4198  Modified();
4199 }
4200 
4201 ////////////////////////////////////////////////////////////////////////////////
4202 /// Paint polyline in CurrentPad World coordinates.
4203 ///
4204 /// If option[0] == 'C' no clipping
4205 
4207 {
4208  if (n < 2) return;
4209 
4211  Bool_t mustClip = kTRUE;
4212  if (TestBit(TGraph::kClipFrame)) {
4213  xmin = fUxmin; ymin = fUymin; xmax = fUxmax; ymax = fUymax;
4214  } else {
4215  xmin = fX1; ymin = fY1; xmax = fX2; ymax = fY2;
4216  if (option && (option[0] == 'C')) mustClip = kFALSE;
4217  }
4218 
4219  Int_t i, i1=-1, np=1, iclip=0;
4220 
4221  for (i=0; i < n-1; i++) {
4222  Double_t x1=x[i];
4223  Double_t y1=y[i];
4224  Double_t x2=x[i+1];
4225  Double_t y2=y[i+1];
4226  if (mustClip) {
4227  iclip = Clip(&x[i],&y[i],xmin,ymin,xmax,ymax);
4228  if (iclip == 2) {
4229  i1 = -1;
4230  continue;
4231  }
4232  }
4233  np++;
4234  if (i1 < 0) i1 = i;
4235  if (iclip == 0 && i < n-2) continue;
4236  if (!gPad->IsBatch())
4237  GetPainter()->DrawPolyLine(np, &x[i1], &y[i1]);
4238  if (gVirtualPS) {
4239  gVirtualPS->DrawPS(np, &x[i1], &y[i1]);
4240  }
4241  if (iclip) {
4242  x[i] = x1;
4243  y[i] = y1;
4244  x[i+1] = x2;
4245  y[i+1] = y2;
4246  }
4247  i1 = -1;
4248  np = 1;
4249  }
4250 
4251  Modified();
4252 }
4253 
4254 ////////////////////////////////////////////////////////////////////////////////
4255 /// Paint polyline in CurrentPad NDC coordinates.
4256 
4258 {
4259  if (n <=0) return;
4260 
4261  if (!gPad->IsBatch())
4262  GetPainter()->DrawPolyLineNDC(n, x, y);
4263 
4264  if (gVirtualPS) {
4265  Double_t *xw = new Double_t[n];
4266  Double_t *yw = new Double_t[n];
4267  for (Int_t i=0; i<n; i++) {
4268  xw[i] = fX1 + x[i]*(fX2 - fX1);
4269  yw[i] = fY1 + y[i]*(fY2 - fY1);
4270  }
4271  gVirtualPS->DrawPS(n, xw, yw);
4272  delete [] xw;
4273  delete [] yw;
4274  }
4275  Modified();
4276 }
4277 
4278 ////////////////////////////////////////////////////////////////////////////////
4279 /// Paint 3-D polyline in the CurrentPad.
4280 
4282 {
4283  if (!fView) return;
4284 
4285  // Loop on each individual line
4286  for (Int_t i = 1; i < n; i++)
4287  PaintLine3D(&p[3*i-3], &p[3*i]);
4288 
4289  Modified();
4290 }
4291 
4292 ////////////////////////////////////////////////////////////////////////////////
4293 /// Paint polymarker in CurrentPad World coordinates.
4294 
4296 {
4297  Int_t n = TMath::Abs(nn);
4299  if (nn > 0 || TestBit(TGraph::kClipFrame)) {
4300  xmin = fUxmin; ymin = fUymin; xmax = fUxmax; ymax = fUymax;
4301  } else {
4302  xmin = fX1; ymin = fY1; xmax = fX2; ymax = fY2;
4303  }
4304  Int_t i,i1=-1,np=0;
4305  for (i=0; i<n; i++) {
4306  if (x[i] >= xmin && x[i] <= xmax && y[i] >= ymin && y[i] <= ymax) {
4307  np++;
4308  if (i1 < 0) i1 = i;
4309  if (i < n-1) continue;
4310  }
4311  if (np == 0) continue;
4312  if (!gPad->IsBatch())
4313  GetPainter()->DrawPolyMarker(np, &x[i1], &y[i1]);
4314  if (gVirtualPS) {
4315  gVirtualPS->DrawPolyMarker(np, &x[i1], &y[i1]);
4316  }
4317  i1 = -1;
4318  np = 0;
4319  }
4320  Modified();
4321 }
4322 
4323 ////////////////////////////////////////////////////////////////////////////////
4324 /// Paint polymarker in CurrentPad World coordinates.
4325 
4327 {
4328  Int_t n = TMath::Abs(nn);
4330  if (nn > 0 || TestBit(TGraph::kClipFrame)) {
4331  xmin = fUxmin; ymin = fUymin; xmax = fUxmax; ymax = fUymax;
4332  } else {
4333  xmin = fX1; ymin = fY1; xmax = fX2; ymax = fY2;
4334  }
4335  Int_t i,i1=-1,np=0;
4336  for (i=0; i<n; i++) {
4337  if (x[i] >= xmin && x[i] <= xmax && y[i] >= ymin && y[i] <= ymax) {
4338  np++;
4339  if (i1 < 0) i1 = i;
4340  if (i < n-1) continue;
4341  }
4342  if (np == 0) continue;
4343  if (!gPad->IsBatch())
4344  GetPainter()->DrawPolyMarker(np, &x[i1], &y[i1]);
4345  if (gVirtualPS) {
4346  gVirtualPS->DrawPolyMarker(np, &x[i1], &y[i1]);
4347  }
4348  i1 = -1;
4349  np = 0;
4350  }
4351  Modified();
4352 }
4353 
4354 ////////////////////////////////////////////////////////////////////////////////
4355 /// Paint text in CurrentPad World coordinates.
4356 
4358 {
4359  Modified();
4360 
4361  if (!gPad->IsBatch())
4363 
4364  if (gVirtualPS) gVirtualPS->Text(x, y, text);
4365 }
4366 
4367 ////////////////////////////////////////////////////////////////////////////////
4368 /// Paint text in CurrentPad World coordinates.
4369 
4370 void TPad::PaintText(Double_t x, Double_t y, const wchar_t *text)
4371 {
4372  Modified();
4373 
4374  if (!gPad->IsBatch())
4376 
4377  if (gVirtualPS) gVirtualPS->Text(x, y, text);
4378 }
4379 
4380 ////////////////////////////////////////////////////////////////////////////////
4381 /// Paint text in CurrentPad NDC coordinates.
4382 
4384 {
4385  Modified();
4386 
4387  if (!gPad->IsBatch())
4389 
4390  if (gVirtualPS) {
4391  Double_t x = fX1 + u*(fX2 - fX1);
4392  Double_t y = fY1 + v*(fY2 - fY1);
4393  gVirtualPS->Text(x, y, text);
4394  }
4395 }
4396 
4397 ////////////////////////////////////////////////////////////////////////////////
4398 /// Paint text in CurrentPad NDC coordinates.
4399 
4400 void TPad::PaintTextNDC(Double_t u, Double_t v, const wchar_t *text)
4401 {
4402  Modified();
4403 
4404  if (!gPad->IsBatch())
4406 
4407  if (gVirtualPS) {
4408  Double_t x = fX1 + u*(fX2 - fX1);
4409  Double_t y = fY1 + v*(fY2 - fY1);
4410  gVirtualPS->Text(x, y, text);
4411  }
4412 }
4413 
4414 ////////////////////////////////////////////////////////////////////////////////
4415 /// Search for an object at pixel position px,py.
4416 ///
4417 /// Check if point is in this pad.
4418 ///
4419 /// If yes, check if it is in one of the sub-pads
4420 ///
4421 /// If found in the pad, compute closest distance of approach
4422 /// to each primitive.
4423 ///
4424 /// If one distance of approach is found to be within the limit Distancemaximum
4425 /// the corresponding primitive is selected and the routine returns.
4426 
4427 TPad *TPad::Pick(Int_t px, Int_t py, TObjLink *&pickobj)
4428 {
4429  //the two following statements are necessary under NT (multithreaded)
4430  //when a TCanvas object is being created and a thread calling TPad::Pick
4431  //before the TPad constructor has completed in the other thread
4432  if (gPad == 0) return 0; //Andy Haas
4433  if (GetListOfPrimitives() == 0) return 0; //Andy Haas
4434 
4435  Int_t dist;
4436  // Search if point is in pad itself
4437  Double_t x = AbsPixeltoX(px);
4438  Double_t y = AbsPixeltoY(py);
4439  if (this != gPad->GetCanvas()) {
4440  if (!((x >= fX1 && x <= fX2) && (y >= fY1 && y <= fY2))) return 0;
4441  }
4442 
4443  // search for a primitive in this pad or its sub-pads
4444  static TObjOptLink dummyLink(0,""); //place holder for when no link available
4445  TPad *padsav = (TPad*)gPad;
4446  gPad = this; // since no drawing will be done, don't use cd() for efficiency reasons
4447  TPad *pick = 0;
4448  TPad *picked = this;
4449  pickobj = 0;
4450  if (DistancetoPrimitive(px,py) < fgMaxPickDistance) {
4451  dummyLink.SetObject(this);
4452  pickobj = &dummyLink;
4453  }
4454 
4455  // Loop backwards over the list of primitives. The first non-pad primitive
4456  // found is the selected one. However, we have to keep going down the
4457  // list to see if there is maybe a pad overlaying the primitive. In that
4458  // case look into the pad for a possible primitive. Once a pad has been
4459  // found we can terminate the loop.
4460  Bool_t gotPrim = kFALSE; // true if found a non pad primitive
4462 
4463  //We can have 3d stuff in pad. If canvas prefers to draw
4464  //such stuff with OpenGL, the selection of 3d objects is
4465  //a gl viewer business so, in first cycle we do not
4466  //call DistancetoPrimitive for TAtt3D descendants.
4467  //In case of gl we first try to select 2d object first.
4468 
4469  while (lnk) {
4470  TObject *obj = lnk->GetObject();
4471 
4472  //If canvas prefers GL, all 3d objects must be drawn/selected by
4473  //gl viewer
4474  if (obj->InheritsFrom(TAtt3D::Class()) && fEmbeddedGL) {
4475  lnk = lnk->Prev();
4476  continue;
4477  }
4478 
4479  fPadPointer = obj;
4480  if (obj->InheritsFrom(TPad::Class())) {
4481  pick = ((TPad*)obj)->Pick(px, py, pickobj);
4482  if (pick) {
4483  picked = pick;
4484  break;
4485  }
4486  } else if (!gROOT->GetEditorMode()) {
4487  if (!gotPrim) {
4488  if (!obj->TestBit(kCannotPick)) {
4489  dist = obj->DistancetoPrimitive(px, py);
4490  if (dist < fgMaxPickDistance) {
4491  pickobj = lnk;
4492  gotPrim = kTRUE;
4493  if (dist == 0) break;
4494  }
4495  }
4496  }
4497  }
4498 
4499  lnk = lnk->Prev();
4500  }
4501 
4502  //if no primitive found, check if we have a TView
4503  //if yes, return the view except if you are in the lower or upper X range
4504  //of the pad.
4505  //In case canvas prefers gl, fView existence
4506  //automatically means viewer3d existence. (?)
4507 
4508  if (fView && !gotPrim) {
4509  Double_t dx = 0.05*(fUxmax-fUxmin);
4510  if ((x > fUxmin + dx) && (x < fUxmax-dx)) {
4511 
4512  if (fEmbeddedGL) {
4513  //No 2d stuff was selected, but we have gl-viewer. Let it select an object in
4514  //scene (or select itself). In any case it'll internally call
4515  //gPad->SetSelected(ptr) as, for example, hist painter does.
4516  py -= Int_t((1 - GetHNDC() - GetYlowNDC()) * GetWh());
4517  px -= Int_t(GetXlowNDC() * GetWw());
4518  fViewer3D->DistancetoPrimitive(px, py);
4519  }
4520  else
4521  dummyLink.SetObject(fView);
4522  }
4523  }
4524 
4525  if (picked->InheritsFrom(TButton::Class())) {
4526  TButton *button = (TButton*)picked;
4527  if (!button->IsEditable()) pickobj = 0;
4528  }
4529 
4530  if (TestBit(kCannotPick)) {
4531 
4532  if (picked == this) {
4533  // cannot pick pad itself!
4534  picked = 0;
4535  }
4536 
4537  }
4538 
4539  gPad = padsav;
4540  return picked;
4541 }
4542 
4543 ////////////////////////////////////////////////////////////////////////////////
4544 /// Pop pad to the top of the stack.
4545 
4547 {
4548  if (!fMother) return;
4549  if (!fPrimitives) fPrimitives = new TList;
4550  if (this == fMother->GetListOfPrimitives()->Last()) return;
4551 
4553  TObject *obj;
4554  while ((obj = next()))
4555  if (obj == this) {
4556  char *opt = StrDup(next.GetOption());
4558  fMother->GetListOfPrimitives()->AddLast(this, opt);
4559  delete [] opt;
4560  return;
4561  }
4562 }
4563 
4564 ////////////////////////////////////////////////////////////////////////////////
4565 /// Save Pad contents in a file in one of various formats.
4566 ///
4567 /// - if filename is "", the file produced is padname.ps
4568 /// - if filename starts with a dot, the padname is added in front
4569 /// - if filename contains .eps, an Encapsulated Postscript file is produced
4570 /// - if filename contains .gif, a GIF file is produced
4571 /// - if filename contains .gif+NN, an animated GIF file is produced
4572 /// See comments in TASImage::WriteImage for meaning of NN and other
4573 /// .gif suffix variants
4574 /// - if filename contains .C or .cxx, a C++ macro file is produced
4575 /// - if filename contains .root, a Root file is produced
4576 /// - if filename contains .xml, a XML file is produced
4577 /// - if filename contains .json, a JSON file is produced
4578 ///
4579 /// See comments in TPad::SaveAs or the TPad::Print function below
4580 
4581 void TPad::Print(const char *filename) const
4582 {
4583  ((TPad*)this)->SaveAs(filename);
4584 }
4585 
4586 ////////////////////////////////////////////////////////////////////////////////
4587 /// Auxiliary function. Returns kTRUE if list contains an object inherited
4588 /// from TImage
4589 
4591 {
4592  TIter next(li);
4593  TObject *obj;
4594 
4595  while ((obj = next())) {
4596  if (obj->InheritsFrom(TImage::Class())) {
4597  return kTRUE;
4598  } else if (obj->InheritsFrom(TPad::Class())) {
4599  if (ContainsTImage(((TPad*)obj)->GetListOfPrimitives())) {
4600  return kTRUE;
4601  }
4602  }
4603  }
4604  return kFALSE;
4605 }
4606 
4607 ////////////////////////////////////////////////////////////////////////////////
4608 /// Save Canvas contents in a file in one of various formats.
4609 ///
4610 /// option can be:
4611 /// - 0 as "ps"
4612 /// - "ps" Postscript file is produced (see special cases below)
4613 /// - "Portrait" Postscript file is produced (Portrait)
4614 /// - "Landscape" Postscript file is produced (Landscape)
4615 /// - "Title:" The character string after "Title:" becomes a table
4616 /// of content entry (for PDF files).
4617 /// - "eps" an Encapsulated Postscript file is produced
4618 /// - "Preview" an Encapsulated Postscript file with preview is produced.
4619 /// - "pdf" a PDF file is produced
4620 /// - "svg" a SVG file is produced
4621 /// - "tex" a TeX file is produced
4622 /// - "gif" a GIF file is produced
4623 /// - "gif+NN" an animated GIF file is produced, where NN is delay in 10ms units NOTE: See other variants for looping animation in TASImage::WriteImage
4624 /// - "xpm" a XPM file is produced
4625 /// - "png" a PNG file is produced
4626 /// - "jpg" a JPEG file is produced. NOTE: JPEG's lossy compression will make all sharp edges fuzzy.
4627 /// - "tiff" a TIFF file is produced
4628 /// - "cxx" a C++ macro file is produced
4629 /// - "xml" a XML file
4630 /// - "json" a JSON file
4631 /// - "root" a ROOT binary file
4632 ///
4633 /// filename = 0 - filename is defined by the GetName and its
4634 /// extension is defined with the option
4635 ///
4636 /// When Postscript output is selected (ps, eps), the canvas is saved
4637 /// to filename.ps or filename.eps. The aspect ratio of the canvas is preserved
4638 /// on the Postscript file. When the "ps" option is selected, the Postscript
4639 /// page will be landscape format if the canvas is in landscape format, otherwise
4640 /// portrait format is selected.
4641 ///
4642 /// The physical size of the Postscript page is the one selected in the
4643 /// current style. This size can be modified via TStyle::SetPaperSize.
4644 ///
4645 /// Examples:
4646 /// ~~~ {.cpp}
4647 /// gStyle->SetPaperSize(TStyle::kA4); //default
4648 /// gStyle->SetPaperSize(TStyle::kUSLetter);
4649 /// ~~~
4650 /// where TStyle::kA4 and TStyle::kUSLetter are defined in the enum
4651 /// EPaperSize in TStyle.h
4652 ///
4653 /// An alternative is to call:
4654 /// ~~~ {.cpp}
4655 /// gStyle->SetPaperSize(20,26); same as kA4
4656 /// or gStyle->SetPaperSize(20,24); same as kUSLetter
4657 /// ~~~
4658 /// The above numbers take into account some margins and are in centimeters.
4659 ///
4660 /// The "Preview" option allows to generate a preview (in the TIFF format) within
4661 /// the Encapsulated Postscript file. This preview can be used by programs like
4662 /// MSWord to visualize the picture on screen. The "Preview" option relies on the
4663 /// epstool command (http://www.cs.wisc.edu/~ghost/gsview/epstool.htm).
4664 ///
4665 /// Example:
4666 /// ~~~ {.cpp}
4667 /// canvas->Print("example.eps","Preview");
4668 /// ~~~
4669 /// To generate a Postscript file containing more than one picture, see
4670 /// class TPostScript.
4671 ///
4672 /// ### Writing several canvases to the same Postscript or PDF file:
4673 ///
4674 /// - if the Postscript or PDF file name finishes with "(", the file is not closed
4675 /// - if the Postscript or PDF file name finishes with ")" and the file has been opened
4676 /// with "(", the file is closed.
4677 ///
4678 /// Example:
4679 /// ~~~ {.cpp}
4680 /// {
4681 /// TCanvas c1("c1");
4682 /// h1.Draw();
4683 /// c1.Print("c1.ps("); //write canvas and keep the ps file open
4684 /// h2.Draw();
4685 /// c1.Print("c1.ps"); canvas is added to "c1.ps"
4686 /// h3.Draw();
4687 /// c1.Print("c1.ps)"); canvas is added to "c1.ps" and ps file is closed
4688 /// }
4689 /// ~~~
4690 /// In the previous example replacing "ps" by "pdf" will create a multi-pages PDF file.
4691 ///
4692 /// Note that the following sequence writes the canvas to "c1.ps" and closes the ps file.:
4693 /// ~~~ {.cpp}
4694 /// TCanvas c1("c1");
4695 /// h1.Draw();
4696 /// c1.Print("c1.ps");
4697 /// ~~~
4698 /// The TCanvas::Print("file.ps(") mechanism is very useful, but it can be
4699 /// a little inconvenient to have the action of opening/closing a file
4700 /// being atomic with printing a page. Particularly if pages are being
4701 /// generated in some loop one needs to detect the special cases of first
4702 /// and last page and then munge the argument to Print() accordingly.
4703 ///
4704 /// The "[" and "]" can be used instead of "(" and ")".
4705 ///
4706 /// Example:
4707 /// ~~~ {.cpp}
4708 /// c1.Print("file.ps["); // No actual print, just open file.ps
4709 /// for (int i=0; i<10; ++i) {
4710 /// // fill canvas for context i
4711 /// // ...
4712 ///
4713 /// c1.Print("file.ps"); // actually print canvas to file
4714 /// }// end loop
4715 /// c1.Print("file.ps]"); // No actual print, just close.
4716 /// ~~~
4717 /// As before, the same macro is valid for PDF files.
4718 ///
4719 /// It is possible to print a canvas into an animated GIF file by specifying the
4720 /// file name as "myfile.gif+" or "myfile.gif+NN", where NN*10ms is delay
4721 /// between the subimages' display. If NN is omitted the delay between
4722 /// subimages is zero. Each picture is added in the animation thanks to a loop
4723 /// similar to the following one:
4724 /// ~~~ {.cpp}
4725 /// for (int i=0; i<10; ++i) {
4726 /// // fill canvas for context i
4727 /// // ...
4728 ///
4729 /// c1.Print("file.gif+5"); // print canvas to GIF file with 50ms delays
4730 /// }// end loop
4731 /// ~~~
4732 /// The delay between each frame must be specified in each Print() statement.
4733 /// If the file "myfile.gif" already exists, the new frame are appended at
4734 /// the end of the file. To avoid this, delete it first with gSystem->Unlink(myfile.gif);
4735 /// If you want the gif file to repeat or loop forever, check TASImage::WriteImage documentation
4736 
4737 void TPad::Print(const char *filenam, Option_t *option)
4738 {
4739  TString psname, fs1, fs2;
4740  const char *filename;
4741 
4742  // "[" and "]" are special characters for ExpandPathName. When they are at the end
4743  // of the file name (see help) they must be removed before doing ExpandPathName.
4744  fs1 = filenam;
4745  if (fs1.EndsWith("[")) {
4746  fs1.Replace((fs1.Length()-1),1," ");
4747  fs2 = gSystem->ExpandPathName(fs1.Data());
4748  fs2.Replace((fs2.Length()-1),1,"[");
4749  } else if (fs1.EndsWith("]")) {
4750  fs1.Replace((fs1.Length()-1),1," ");
4751  fs2 = gSystem->ExpandPathName(fs1.Data());
4752  fs2.Replace((fs2.Length()-1),1,"]");
4753  } else {
4754  char* exppath = gSystem->ExpandPathName(fs1.Data());
4755  fs2 = exppath;
4756  delete [] exppath;
4757  }
4758  filename = fs2.Data();
4759 
4760  // Set the default option as "Postscript" (Should be a data member of TPad)
4761  const char *opt_default="ps";
4762 
4763  Int_t lenfil = filename ? strlen(filename) : 0;
4764  TString opt = (!option) ? opt_default : option;
4765  Bool_t image = kFALSE;
4766 
4767  if ( !lenfil ) {
4768  psname = GetName();
4769  psname += opt;
4770  } else {
4771  psname = filename;
4772  }
4773 
4774  // lines below protected against case like c1->SaveAs( "../ps/cs.ps" );
4775  if (psname.BeginsWith('.') && (psname.Contains('/') == 0)) {
4776  psname = GetName();
4777  psname.Append(filename);
4778  psname.Prepend("/");
4779  psname.Prepend(gEnv->GetValue("Canvas.PrintDirectory","."));
4780  }
4781  if (!gPad->IsBatch() && fCanvas)
4783 
4784  // Save pad/canvas in alternative formats
4786  if (strstr(opt, "gif+")) {
4787  gtype = TImage::kAnimGif;
4788  image = kTRUE;
4789  } else if (strstr(opt, "gif")) {
4790  gtype = TImage::kGif;
4791  image = kTRUE;
4792  } else if (strstr(opt, "png")) {
4793  gtype = TImage::kPng;
4794  image = kTRUE;
4795  } else if (strstr(opt, "jpg")) {
4796  gtype = TImage::kJpeg;
4797  image = kTRUE;
4798  } else if (strstr(opt, "tiff")) {
4799  gtype = TImage::kTiff;
4800  image = kTRUE;
4801  } else if (strstr(opt, "xpm")) {
4802  gtype = TImage::kXpm;
4803  image = kTRUE;
4804  } else if (strstr(opt, "bmp")) {
4805  gtype = TImage::kBmp;
4806  image = kTRUE;
4807  }
4808 
4809  Int_t wid = 0;
4810  if (!GetCanvas()) return;
4811  if (!gROOT->IsBatch() && image) {
4812  if ((gtype == TImage::kGif) && !ContainsTImage(fPrimitives)) {
4813  wid = (this == GetCanvas()) ? GetCanvas()->GetCanvasID() : GetPixmapID();
4814  Color_t hc = gPad->GetCanvas()->GetHighLightColor();
4815  gPad->GetCanvas()->SetHighLightColor(-1);
4816  gPad->Modified();
4817  gPad->Update();
4818  GetPainter()->SelectDrawable(wid);
4819  GetPainter()->SaveImage(this, psname.Data(), gtype);
4820  if (!gSystem->AccessPathName(psname.Data())) {
4821  Info("Print", "GIF file %s has been created", psname.Data());
4822  }
4823  gPad->GetCanvas()->SetHighLightColor(hc);
4824  return;
4825  }
4826  if (gtype != TImage::kUnknown) {
4827  Color_t hc = gPad->GetCanvas()->GetHighLightColor();
4828  gPad->GetCanvas()->SetHighLightColor(-1);
4829  gPad->Modified();
4830  gPad->Update();
4831  if (gVirtualX->InheritsFrom("TGQt")) {
4832  wid = (this == GetCanvas()) ? GetCanvas()->GetCanvasID() : GetPixmapID();
4833  gVirtualX->WritePixmap(wid,UtoPixel(1.),VtoPixel(0.),(char *)psname.Data());
4834  } else {
4835  Int_t saver = gErrorIgnoreLevel;
4837  gVirtualX->Update(1);
4838  gSystem->Sleep(30); // synchronize
4839  GetPainter()->SaveImage(this, psname, gtype);
4840  gErrorIgnoreLevel = saver;
4841  }
4842  if (!gSystem->AccessPathName(psname)) {
4843  Info("Print", "file %s has been created", psname.Data());
4844  }
4845  gPad->GetCanvas()->SetHighLightColor(hc);
4846  } else {
4847  Warning("Print", "Unsupported image format %s", psname.Data());
4848  }
4849  return;
4850  }
4851 
4852  //==============Save pad/canvas as a C++ script==============================
4853  if (strstr(opt,"cxx")) {
4854  GetCanvas()->SaveSource(psname, "");
4855  return;
4856  }
4857 
4858  //==============Save pad/canvas as a root file===============================
4859  if (strstr(opt,"root")) {
4860  if (gDirectory) gDirectory->SaveObjectAs(this,psname.Data(),"");
4861  return;
4862  }
4863 
4864  //==============Save pad/canvas as a XML file================================
4865  if (strstr(opt,"xml")) {
4866  // Plugin XML driver
4867  if (gDirectory) gDirectory->SaveObjectAs(this,psname.Data(),"");
4868  return;
4869  }
4870 
4871  //==============Save pad/canvas as a JSON file================================
4872  if (strstr(opt,"json")) {
4873  if (gDirectory) gDirectory->SaveObjectAs(this,psname.Data(),"");
4874  return;
4875  }
4876 
4877  //==============Save pad/canvas as a SVG file================================
4878  if (strstr(opt,"svg")) {
4879  gVirtualPS = (TVirtualPS*)gROOT->GetListOfSpecials()->FindObject(psname);
4880 
4881  Bool_t noScreen = kFALSE;
4882  if (!GetCanvas()->IsBatch() && GetCanvas()->GetCanvasID() == -1) {
4883  noScreen = kTRUE;
4884  GetCanvas()->SetBatch(kTRUE);
4885  }
4886 
4887  TPad *padsav = (TPad*)gPad;
4888  cd();
4889 
4890  if (!gVirtualPS) {
4891  // Plugin Postscript/SVG driver
4892  TPluginHandler *h;
4893  if ((h = gROOT->GetPluginManager()->FindHandler("TVirtualPS", "svg"))) {
4894  if (h->LoadPlugin() == -1)
4895  return;
4896  h->ExecPlugin(0);
4897  }
4898  }
4899 
4900  // Create a new SVG file
4901  if (gVirtualPS) {
4902  gVirtualPS->SetName(psname);
4903  gVirtualPS->Open(psname);
4905  gVirtualPS->NewPage();
4906  }
4907  Paint();
4908  if (noScreen) GetCanvas()->SetBatch(kFALSE);
4909 
4910  if (!gSystem->AccessPathName(psname)) Info("Print", "SVG file %s has been created", psname.Data());
4911 
4912  delete gVirtualPS;
4913  gVirtualPS = 0;
4914  padsav->cd();
4915 
4916  return;
4917  }
4918 
4919  //==============Save pad/canvas as a TeX file================================
4920  if (strstr(opt,"tex")) {
4921  gVirtualPS = (TVirtualPS*)gROOT->GetListOfSpecials()->FindObject(psname);
4922 
4923  Bool_t noScreen = kFALSE;
4924  if (!GetCanvas()->IsBatch() && GetCanvas()->GetCanvasID() == -1) {
4925  noScreen = kTRUE;
4926  GetCanvas()->SetBatch(kTRUE);
4927  }
4928 
4929  TPad *padsav = (TPad*)gPad;
4930  cd();
4931 
4932  if (!gVirtualPS) {
4933  // Plugin Postscript/SVG driver
4934  TPluginHandler *h;
4935  if ((h = gROOT->GetPluginManager()->FindHandler("TVirtualPS", "tex"))) {
4936  if (h->LoadPlugin() == -1)
4937  return;
4938  h->ExecPlugin(0);
4939  }
4940  }
4941 
4942  // Create a new TeX file
4943  if (gVirtualPS) {
4944  gVirtualPS->SetName(psname);
4945  gVirtualPS->Open(psname);
4947  gVirtualPS->NewPage();
4948  }
4949  Paint();
4950  if (noScreen) GetCanvas()->SetBatch(kFALSE);
4951 
4952  if (!gSystem->AccessPathName(psname)) Info("Print", "TeX file %s has been created", psname.Data());
4953 
4954  delete gVirtualPS;
4955  gVirtualPS = 0;
4956  padsav->cd();
4957 
4958  return;
4959  }
4960 
4961  //==============Save pad/canvas as a Postscript file=========================
4962 
4963  // in case we read directly from a Root file and the canvas
4964  // is not on the screen, set batch mode
4965 
4966  Bool_t mustOpen = kTRUE;
4967  Bool_t mustClose = kTRUE;
4968  Bool_t copen=kFALSE, cclose=kFALSE, copenb=kFALSE, ccloseb=kFALSE;
4969  if (!image) {
4970  // The parenthesis mechanism is only valid for PS and PDF files.
4971  copen = psname.EndsWith("("); if (copen) psname[psname.Length()-1] = 0;
4972  cclose = psname.EndsWith(")"); if (cclose) psname[psname.Length()-1] = 0;
4973  copenb = psname.EndsWith("["); if (copenb) psname[psname.Length()-1] = 0;
4974  ccloseb = psname.EndsWith("]"); if (ccloseb) psname[psname.Length()-1] = 0;
4975  }
4976  gVirtualPS = (TVirtualPS*)gROOT->GetListOfSpecials()->FindObject(psname);
4977  if (gVirtualPS) {mustOpen = kFALSE; mustClose = kFALSE;}
4978  if (copen || copenb) mustClose = kFALSE;
4979  if (cclose || ccloseb) mustClose = kTRUE;
4980 
4981  Bool_t noScreen = kFALSE;
4982  if (!GetCanvas()->IsBatch() && GetCanvas()->GetCanvasID() == -1) {
4983  noScreen = kTRUE;
4984  GetCanvas()->SetBatch(kTRUE);
4985  }
4986  Int_t pstype = 111;
4987  Double_t xcanvas = GetCanvas()->XtoPixel(GetCanvas()->GetX2());
4988  Double_t ycanvas = GetCanvas()->YtoPixel(GetCanvas()->GetY1());
4989  Double_t ratio = ycanvas/xcanvas;
4990  if (ratio < 1) pstype = 112;
4991  if (strstr(opt,"Portrait")) pstype = 111;
4992  if (strstr(opt,"Landscape")) pstype = 112;
4993  if (strstr(opt,"eps")) pstype = 113;
4994  if (strstr(opt,"Preview")) pstype = 113;
4995  TPad *padsav = (TPad*)gPad;
4996  cd();
4997  TVirtualPS *psave = gVirtualPS;
4998 
4999  if (!gVirtualPS || mustOpen) {
5000  // Plugin Postscript driver
5001  TPluginHandler *h;
5002  if (strstr(opt,"pdf") || strstr(opt,"Title:")) {
5003  if ((h = gROOT->GetPluginManager()->FindHandler("TVirtualPS", "pdf"))) {
5004  if (h->LoadPlugin() == -1) return;
5005  h->ExecPlugin(0);
5006  }
5007  } else if (image) {
5008  // Plugin TImageDump driver
5009  if ((h = gROOT->GetPluginManager()->FindHandler("TVirtualPS", "image"))) {
5010  if (h->LoadPlugin() == -1) return;
5011  h->ExecPlugin(0);
5012  }
5013  } else {
5014  if ((h = gROOT->GetPluginManager()->FindHandler("TVirtualPS", "ps"))) {
5015  if (h->LoadPlugin() == -1) return;
5016  h->ExecPlugin(0);
5017  }
5018  }
5019 
5020  // Create a new Postscript, PDF or image file
5021  if (gVirtualPS) gVirtualPS->SetName(psname);
5022  const Ssiz_t titlePos = opt.Index("Title:");
5023  if (titlePos != kNPOS) {
5024  if (gVirtualPS) gVirtualPS->SetTitle(opt.Data()+titlePos+6);
5025  opt.Replace(titlePos,opt.Length(),"pdf");
5026  }
5027  if (gVirtualPS) gVirtualPS->Open(psname,pstype);
5029  if (!copenb) {
5030  if (!strstr(opt,"pdf") || image) {
5031  if (gVirtualPS) gVirtualPS->NewPage();
5032  }
5033  Paint();
5034  }
5035  if (noScreen) GetCanvas()->SetBatch(kFALSE);
5036 
5037  if (mustClose) {
5038  gROOT->GetListOfSpecials()->Remove(gVirtualPS);
5039  delete gVirtualPS;
5040  gVirtualPS = psave;
5041  } else {
5042  gROOT->GetListOfSpecials()->Add(gVirtualPS);
5043  gVirtualPS = 0;
5044  }
5045 
5046  if (!gSystem->AccessPathName(psname)) {
5047  if (!copen) Info("Print", "%s file %s has been created", opt.Data(), psname.Data());
5048  else Info("Print", "%s file %s has been created using the current canvas", opt.Data(), psname.Data());
5049  }
5050  } else {
5051  // Append to existing Postscript, PDF or GIF file
5052  if (!ccloseb) {
5053  gVirtualPS->NewPage();
5054  Paint();
5055  }
5056  const Ssiz_t titlePos = opt.Index("Title:");
5057  if (titlePos != kNPOS) {
5058  gVirtualPS->SetTitle(opt.Data()+titlePos+6);
5059  opt.Replace(titlePos,opt.Length(),"pdf");
5060  } else {
5061  gVirtualPS->SetTitle("PDF");
5062  }
5063  if (mustClose) {
5064  if (cclose) Info("Print", "Current canvas added to %s file %s and file closed", opt.Data(), psname.Data());
5065  else Info("Print", "%s file %s has been closed", opt.Data(), psname.Data());
5066  gROOT->GetListOfSpecials()->Remove(gVirtualPS);
5067  delete gVirtualPS;
5068  gVirtualPS = 0;
5069  } else {
5070  Info("Print", "Current canvas added to %s file %s", opt.Data(), psname.Data());
5071  gVirtualPS = 0;
5072  }
5073  }
5074 
5075  if (strstr(opt,"Preview")) gSystem->Exec(Form("epstool --quiet -t6p %s %s",psname.Data(),psname.Data()));
5076 
5077  padsav->cd();
5078 }
5079 
5080 ////////////////////////////////////////////////////////////////////////////////
5081 /// Set world coordinate system for the pad.
5082 /// Emits signal "RangeChanged()", in the slot get the range
5083 /// via GetRange().
5084 
5086 {
5087  if ((x1 >= x2) || (y1 >= y2)) {
5088  Error("Range", "illegal world coordinates range: x1=%f, y1=%f, x2=%f, y2=%f",x1,y1,x2,y2);
5089  return;
5090  }
5091 
5092  fUxmin = x1;
5093  fUxmax = x2;
5094  fUymin = y1;
5095  fUymax = y2;
5096 
5097  if (fX1 == x1 && fY1 == y1 && fX2 == x2 && fY2 == y2) return;
5098 
5099  fX1 = x1;
5100  fY1 = y1;
5101  fX2 = x2;
5102  fY2 = y2;
5103 
5104  // compute pad conversion coefficients
5105  ResizePad();
5106 
5107  if (gPad == this)
5108  GetPainter()->InvalidateCS();
5109 
5110  // emit signal
5111  RangeChanged();
5112 }
5113 
5114 ////////////////////////////////////////////////////////////////////////////////
5115 /// Set axis coordinate system for the pad.
5116 /// The axis coordinate system is a subset of the world coordinate system
5117 /// xmin,ymin is the origin of the current coordinate system,
5118 /// xmax is the end of the X axis, ymax is the end of the Y axis.
5119 /// By default a margin of 10 per cent is left on all sides of the pad
5120 /// Emits signal "RangeAxisChanged()", in the slot get the axis range
5121 /// via GetRangeAxis().
5122 
5124 {
5125  if ((xmin >= xmax) || (ymin >= ymax)) {
5126  Error("RangeAxis", "illegal axis coordinates range: xmin=%f, ymin=%f, xmax=%f, ymax=%f",
5127  xmin, ymin, xmax, ymax);
5128  return;
5129  }
5130 
5131  fUxmin = xmin;
5132  fUymin = ymin;
5133  fUxmax = xmax;
5134  fUymax = ymax;
5135 
5136  // emit signal
5137  RangeAxisChanged();
5138 }
5139 
5140 ////////////////////////////////////////////////////////////////////////////////
5141 /// Recursively remove object from a pad and its sub-pads.
5142 
5144 {
5145  if (obj == fCanvas->GetSelected()) fCanvas->SetSelected(0);
5146  if (obj == fCanvas->GetClickSelected()) fCanvas->SetClickSelected(0);
5147  if (obj == fView) fView = 0;
5148  if (!fPrimitives) return;
5149  Int_t nold = fPrimitives->GetSize();
5151  if (nold != fPrimitives->GetSize()) fModified = kTRUE;
5152 }
5153 
5154 ////////////////////////////////////////////////////////////////////////////////
5155 /// Redraw the frame axis
5156 /// Redrawing axis may be necessary in case of superimposed histograms
5157 /// when one or more histograms have a fill color
5158 /// Instead of calling this function, it may be more convenient
5159 /// to call directly h1->Draw("sameaxis") where h1 is the pointer
5160 /// to the first histogram drawn in the pad.
5161 ///
5162 /// By default, if the pad has the options gridx or/and gridy activated,
5163 /// the grid is not drawn by this function.
5164 /// if option="g" is specified, this will force the drawing of the grid
5165 /// on top of the picture
5166 
5168 {
5169  // get first histogram in the list of primitives
5170  TString opt = option;
5171  opt.ToLower();
5172 
5173  TPad *padsav = (TPad*)gPad;
5174  cd();
5175 
5176  if (!fPrimitives) fPrimitives = new TList;
5177  TIter next(fPrimitives);
5178  TObject *obj;
5179  while ((obj = next())) {
5180  if (obj->InheritsFrom(TH1::Class())) {
5181  TH1 *hobj = (TH1*)obj;
5182  if (opt.Contains("g")) hobj->DrawCopy("sameaxig");
5183  else hobj->DrawCopy("sameaxis");
5184  return;
5185  }
5186  if (obj->InheritsFrom(TMultiGraph::Class())) {
5187  TMultiGraph *mg = (TMultiGraph*)obj;
5188  if (mg) {
5189  TH1F *h1f = mg->GetHistogram();
5190  if (h1f) h1f->DrawCopy("sameaxis");
5191  }
5192  return;
5193  }
5194  if (obj->InheritsFrom(TGraph::Class())) {
5195  TGraph *g = (TGraph*)obj;
5196  if (g) g->GetHistogram()->DrawCopy("sameaxis");
5197  return;
5198  }
5199  if (obj->InheritsFrom(THStack::Class())) {
5200  THStack *hs = (THStack*)obj;
5201  if (hs) {
5202  TH1 *h1 = hs->GetHistogram();
5203  if (h1) h1->DrawCopy("sameaxis");
5204  }
5205  return;
5206  }
5207  }
5208 
5209  if (padsav) padsav->cd();
5210 }
5211 
5212 ////////////////////////////////////////////////////////////////////////////////
5213 /// Compute pad conversion coefficients.
5214 ///
5215 /// ### Conversion from x to px
5216 ///
5217 /// \f[\frac{x-xmin}{xrange} = \frac{px-pxlow}{pxrange}\f]
5218 /// with:
5219 /// \f[ xrange = xmax-xmin \f]
5220 /// \f[ pxrange = pxmax-pxmin \f]
5221 ///
5222 /// \f[
5223 /// \Rightarrow px = \frac{pxrange(x-xmin)}{xrange} + pxlow = fXtoPixelk + fXtoPixel \times x
5224 /// \f]
5225 ///
5226 /// \f[
5227 /// \Rightarrow fXtoPixelk = pxlow - pxrange \frac{xmin}{xrange}
5228 /// \f]
5229 /// \f[
5230 /// fXtoPixel = \frac{pxrange}{xrange}
5231 /// \f]
5232 /// where:
5233 /// \f[
5234 /// pxlow = fAbsXlowNDC \times fCw
5235 /// \f]
5236 /// \f[
5237 /// pxrange = fAbsWNDC \times fCw
5238 /// \f]
5239 ///
5240 /// ### Conversion from y to py
5241 ///
5242 /// \f[\frac{y-ymin}{yrange} = \frac{py-pylow}{pyrange}\f]
5243 /// with:
5244 /// \f[ yrange = ymax-ymin \f]
5245 /// \f[ pyrange = pymax-pymin \f]
5246 ///
5247 /// \f[
5248 /// \Rightarrow py = \frac{pyrange(y-xmin)}{yrange} + pylow = fYtoPixelk + fYtoPixel \times y
5249 /// \f]
5250 ///
5251 /// \f[
5252 /// \Rightarrow fYtoPixelk = pylow - pyrange \frac{ymin}{yrange}
5253 /// \f]
5254 /// \f[
5255 /// fYtoPixel = \frac{pyrange}{yrange}
5256 /// \f]
5257 /// where:
5258 /// \f[
5259 /// pylow = fAbsYlowNDC \times fCh
5260 /// \f]
5261 /// \f[
5262 /// pyrange = fAbsHNDC \times fCh
5263 /// \f]
5264 ///
5265 /// ### Conversion from px to x
5266 ///
5267 /// \f[
5268 /// \Rightarrow x = \frac{xrange(px-pxlow)}{pxrange}+ xmin = fPixeltoXk + fPixeltoX \times px
5269 /// \f]
5270 ///
5271 /// \f[
5272 /// \Rightarrow fPixeltoXk = xmin - pxlow \times\frac{xrange}{pxrange}
5273 /// \f]
5274 /// \f[
5275 /// fPixeltoX = \frac{xrange}{pxrange}
5276 /// \f]
5277 ///
5278 /// ### Conversion from py to y
5279 ///
5280 /// \f[
5281 /// \Rightarrow y = \frac{yrange(py-pylow)}{pyrange}+ ymin = fPixeltoYk + fPixeltoY \times py
5282 /// \f]
5283 ///
5284 /// \f[
5285 /// \Rightarrow fPixeltoYk = ymin - pylow \times\frac{yrange}{pyrange}
5286 /// \f]
5287 /// \f[
5288 /// fPixeltoY = \frac{yrange}{pyrange}
5289 /// \f]
5290 ///
5291 /// ### Computation of the coefficients in case of LOG scales
5292 ///
5293 /// #### Conversion from pixel coordinates to world coordinates
5294 ///
5295 /// \f[
5296 /// u = \frac{Log(x) - Log(xmin)}{Log(xmax) - Log(xmin)} = \frac{Log(x/xmin)}{Log(xmax/xmin)} = \frac{px - pxlow}{pxrange}
5297 /// \f]
5298 ///
5299 /// \f[ \Rightarrow Log(\frac{x}{xmin}) = u \times Log(\frac{xmax}{xmin}) \f]
5300 /// \f[ x = xmin \times e^{(u \times Log(\frac{xmax}{xmin})} \f]
5301 /// Let:
5302 /// \f[ alfa = \frac{Log(\frac{xmax}{xmin})}{fAbsWNDC} \f]
5303 ///
5304 /// \f[ x = xmin \times e^{(-alfa \times pxlow)} + e^{(alfa \times px)} \f]
5305 /// \f[ x = fPixeltoXk \times e^{(fPixeltoX \times px)} \f]
5306 /// \f[ ==> fPixeltoXk = xmin \times e^{(-alfa*pxlow)} \f]
5307 /// \f[ fPixeltoX = alfa \f]
5308 ///
5309 /// \f[
5310 /// v = \frac{Log(y) - Log(ymin)}{Log(ymax) - Log(ymin)} = \frac{Log(y/ymin)}{Log(ymax/ymin)} = \frac{py - pylow}{pyrange}
5311 /// \f]
5312 /// Let:
5313 /// \f[ beta = Log(\frac{ymax}{ymin}) \f]
5314 /// \f[ Log(\frac{y}{ymin}) = beta \times pylow - beta \times py \f]
5315 /// \f[ \frac{y}{ymin} = e^{(beta \times pylow - beta \times py)} \f]
5316 /// \f[ y = ymin \times e^{(beta \times pylow)} \times e^{(-beta \times py)}\f]
5317 /// \f[ \Rightarrow y = fPixeltoYk \times e^{(fPixeltoY \times py)} \f]
5318 /// \f[ fPixeltoYk = ymin \times e^{(beta \times pylow)} \f]
5319 /// \f[ fPixeltoY = -beta \f]
5320 ///
5321 /// #### Conversion from World coordinates to pixel coordinates
5322 ///
5323 /// \f[ px = pxlow + u*pxrange \f]
5324 /// \f[ = pxlow + Log(x/xmin)/alfa \f]
5325 /// \f[ = pxlow -Log(xmin)/alfa + Log(x)/alfa \f]
5326 /// \f[ = fXtoPixelk + fXtoPixel*Log(x) \f]
5327 /// \f[ \Rightarrow fXtoPixelk = pxlow -Log(xmin)/alfa \f]
5328 /// \f[ \Rightarrow fXtoPixel = 1/alfa \f]
5329 ///
5330 /// \f[ py = pylow - Log(y/ymin)/beta \f]
5331 /// \f[ = fYtoPixelk + fYtoPixel*Log(y) \f]
5332 /// \f[ \Rightarrow fYtoPixelk = pylow - Log(ymin)/beta \f]
5333 /// \f[ fYtoPixel = 1/beta \f]
5334 
5336 {
5337  // Recompute subpad positions in case pad has been moved/resized
5338  TPad *parent = fMother;
5339  if (this == gPad->GetCanvas()) {
5342  fAbsWNDC = fWNDC;
5343  fAbsHNDC = fHNDC;
5344  }
5345  else {
5346  fAbsXlowNDC = fXlowNDC*parent->GetAbsWNDC() + parent->GetAbsXlowNDC();
5347  fAbsYlowNDC = fYlowNDC*parent->GetAbsHNDC() + parent->GetAbsYlowNDC();
5348  fAbsWNDC = fWNDC*parent->GetAbsWNDC();
5349  fAbsHNDC = fHNDC*parent->GetAbsHNDC();
5350  }
5351 
5352  Double_t ww = (Double_t)gPad->GetWw();
5353  Double_t wh = (Double_t)gPad->GetWh();
5354  Double_t pxlow = fAbsXlowNDC*ww;
5355  Double_t pylow = (1-fAbsYlowNDC)*wh;
5356  Double_t pxrange = fAbsWNDC*ww;
5357  Double_t pyrange = -fAbsHNDC*wh;
5358 
5359  // Linear X axis
5360  Double_t rounding = 0.00005;
5361  Double_t xrange = fX2 - fX1;
5362  fXtoAbsPixelk = rounding + pxlow - pxrange*fX1/xrange; //origin at left
5363  fXtoPixelk = rounding + -pxrange*fX1/xrange;
5364  fXtoPixel = pxrange/xrange;
5365  fAbsPixeltoXk = fX1 - pxlow*xrange/pxrange;
5366  fPixeltoXk = fX1;
5367  fPixeltoX = xrange/pxrange;
5368  // Linear Y axis
5369  Double_t yrange = fY2 - fY1;
5370  fYtoAbsPixelk = rounding + pylow - pyrange*fY1/yrange; //origin at top
5371  fYtoPixelk = rounding + -pyrange - pyrange*fY1/yrange;
5372  fYtoPixel = pyrange/yrange;
5373  fAbsPixeltoYk = fY1 - pylow*yrange/pyrange;
5374  fPixeltoYk = fY1;
5375  fPixeltoY = yrange/pyrange;