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