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