Logo ROOT   6.30.04
Reference Guide
 All Namespaces Files Pages
TPad.cxx
Go to the documentation of this file.
1 // @(#)root/gpad:$Id$
2 // Author: Rene Brun 12/12/94
3 
4 /*************************************************************************
5  * Copyright (C) 1995-2000, Rene Brun and Fons Rademakers. *
6  * All rights reserved. *
7  * *
8  * For the licensing terms see $ROOTSYS/LICENSE. *
9  * For the list of contributors see $ROOTSYS/README/CREDITS. *
10  *************************************************************************/
11 
12 #include <string.h>
13 #include <stdlib.h>
14 
15 #include "Riostream.h"
16 #include "TROOT.h"
17 #include "TError.h"
18 #include "TMath.h"
19 #include "TSystem.h"
20 #include "TStyle.h"
21 #include "TH1.h"
22 #include "TH2.h"
23 #include "TH3.h"
24 #include "TClass.h"
25 #include "TBaseClass.h"
26 #include "TClassTable.h"
27 #include "TVirtualPS.h"
28 #include "TVirtualX.h"
29 #include "TVirtualViewer3D.h"
30 #include "TView.h"
31 #include "TPoint.h"
32 #include "TGraph.h"
33 #include "TMultiGraph.h"
34 #include "THStack.h"
35 #include "TPaveText.h"
36 #include "TPaveStats.h"
37 #include "TGroupButton.h"
38 #include "TBrowser.h"
39 #include "TVirtualGL.h"
40 #include "TString.h"
41 #include "TDataMember.h"
42 #include "TMethod.h"
43 #include "TDataType.h"
44 #include "TFrame.h"
45 #include "TExec.h"
46 #include "TDatime.h"
47 #include "TColor.h"
48 #include "TCanvas.h"
49 #include "TPluginManager.h"
50 #include "TEnv.h"
51 #include "TImage.h"
52 #include "TViewer3DPad.h"
53 #include "TCreatePrimitives.h"
54 #include "TLegend.h"
55 #include "TAtt3D.h"
56 #include "TObjString.h"
57 #include "TApplication.h"
58 #include "TVirtualPadPainter.h"
59 
60 #include "TVirtualMutex.h"
61 
62 static Int_t gReadLevel = 0;
63 
64 Int_t TPad::fgMaxPickDistance = 5;
65 
66 ClassImpQ(TPad)
67 
68 /** \class TPad
69 \ingroup gpad
70 
71 The most important graphics class in the ROOT system.
72 
73 A Pad is contained in a Canvas.
74 
75 A Pad may contain other pads (unlimited pad hierarchy).
76 
77 A pad is a linked list of primitives of any type (graphics objects,
78 histograms, detectors, tracks, etc.).
79 
80 Adding a new element into a pad is in general performed by the Draw
81 member function of the object classes.
82 
83 It is important to realize that the pad is a linked list of references
84 to the original object.
85 For example, in case of a histogram, the histogram.Draw() operation
86 only stores a reference to the histogram object and not a graphical
87 representation of this histogram.
88 When the mouse is used to change (say the bin content), the bin content
89 of the original histogram is changed.
90 
91 The convention used in ROOT is that a Draw operation only adds
92 a reference to the object. The effective drawing is performed
93 when the canvas receives a signal to be painted.
94 
95 \image html gpad_pad1.png
96 
97 This signal is generally sent when typing carriage return in the
98 command input or when a graphical operation has been performed on one
99 of the pads of this canvas.
100 When a Canvas/Pad is repainted, the member function Paint for all
101 objects in the Pad linked list is invoked.
102 
103 \image html gpad_pad2.png
104 
105 When the mouse is moved on the Pad, The member function DistancetoPrimitive
106 is called for all the elements in the pad. DistancetoPrimitive returns
107 the distance in pixels to this object.
108 
109 When the object is within the distance window, the member function
110 ExecuteEvent is called for this object.
111 
112 In ExecuteEvent, move, changes can be performed on the object.
113 
114 For examples of DistancetoPrimitive and ExecuteEvent functions,
115 see classes
116 ~~~ {.cpp}
117  TLine::DistancetoPrimitive, TLine::ExecuteEvent
118  TBox::DistancetoPrimitive, TBox::ExecuteEvent
119  TH1::DistancetoPrimitive, TH1::ExecuteEvent
120 ~~~
121 A Pad supports linear and log scales coordinate systems.
122 The transformation coefficients are explained in TPad::ResizePad.
123 */
124 
125 ////////////////////////////////////////////////////////////////////////////////
126 /// Pad default constructor.
127 
128 TPad::TPad()
129 {
130  fModified = kTRUE;
131  fTip = nullptr;
132  fPadPointer = nullptr;
133  fPrimitives = nullptr;
134  fExecs = nullptr;
135  fCanvas = nullptr;
136  fPadPaint = 0;
137  fPixmapID = -1;
138  fGLDevice = -1;
139  fCopyGLDevice = kFALSE;
140  fEmbeddedGL = kFALSE;
141  fTheta = 30;
142  fPhi = 30;
143  fNumber = 0;
144  fAbsCoord = kFALSE;
145  fEditable = kTRUE;
146  fCrosshair = 0;
147  fCrosshairPos = 0;
148  fPadView3D = nullptr;
149  fMother = (TPad*)gPad;
150 
151  fAbsHNDC = 0.;
152  fAbsPixeltoXk = 0.;
153  fAbsPixeltoYk = 0.;
154  fAbsWNDC = 0.;
155  fAbsXlowNDC = 0.;
156  fAbsYlowNDC = 0.;
157  fBorderMode = 0;
158  fBorderSize = 0;
159  fPixeltoX = 0;
160  fPixeltoXk = 0.;
161  fPixeltoY = 0.;
162  fPixeltoYk = 0.;
163  fUtoAbsPixelk = 0.;
164  fUtoPixel = 0.;
165  fUtoPixelk = 0.;
166  fVtoAbsPixelk = 0.;
167  fVtoPixel = 0.;
168  fVtoPixelk = 0.;
169  fXtoAbsPixelk = 0.;
170  fXtoPixel = 0.;
171  fXtoPixelk = 0.;
172  fYtoAbsPixelk = 0.;
173  fYtoPixel = 0.;
174  fYtoPixelk = 0.;
175  fXUpNDC = 0.;
176  fYUpNDC = 0.;
177 
178  fFixedAspectRatio = kFALSE;
179  fAspectRatio = 0.;
180 
181  fNumPaletteColor = 0;
182  fNextPaletteColor = 0;
183  fCollideGrid = nullptr;
184  fCGnx = 0;
185  fCGny = 0;
186 
187  fLogx = 0;
188  fLogy = 0;
189  fLogz = 0;
190  fGridx = 0;
191  fGridy = 0;
192  fTickx = 0;
193  fTicky = 0;
194  fFrame = nullptr;
195  fView = nullptr;
196 
197  fUxmin = fUymin = fUxmax = fUymax = 0;
198 
199  // Set default world coordinates to NDC [0,1]
200  fX1 = 0;
201  fX2 = 1;
202  fY1 = 0;
203  fY2 = 1;
204 
205  // Set default pad range
206  fXlowNDC = 0;
207  fYlowNDC = 0;
208  fWNDC = 1;
209  fHNDC = 1;
210 
211  fViewer3D = nullptr;
212  SetBit(kMustCleanup);
213 
214  // the following line is temporarily disabled. It has side effects
215  // when the pad is a TDrawPanelHist or a TFitPanel.
216  // the line was supposed to fix a problem with DrawClonePad
217  // gROOT->SetSelectedPad(this);
218 }
219 
220 ////////////////////////////////////////////////////////////////////////////////
221 /// Pad constructor.
222 ///
223 /// A pad is a linked list of primitives.
224 /// A pad is contained in a canvas. It may contain other pads.
225 /// A pad has attributes. When a pad is created, the attributes
226 /// defined in the current style are copied to the pad attributes.
227 ///
228 /// \param[in] name pad name
229 /// \param[in] title pad title
230 /// \param[in] xlow [0,1] is the position of the bottom left point of the pad
231 /// expressed in the mother pad reference system
232 /// \param[in] ylow [0,1] is the Y position of this point.
233 /// \param[in] xup [0,1] is the x position of the top right point of the pad
234 /// expressed in the mother pad reference system
235 /// \param[in] yup [0,1] is the Y position of this point.
236 /// \param[in] color pad color
237 /// \param[in] bordersize border size in pixels
238 /// \param[in] bordermode border mode
239 /// - bordermode = -1 box looks as it is behind the screen
240 /// - bordermode = 0 no special effects
241 /// - bordermode = 1 box looks as it is in front of the screen
242 
243 TPad::TPad(const char *name, const char *title, Double_t xlow,
244  Double_t ylow, Double_t xup, Double_t yup,
245  Color_t color, Short_t bordersize, Short_t bordermode)
246  : TVirtualPad(name,title,xlow,ylow,xup,yup,color,bordersize,bordermode)
247 {
248  fModified = kTRUE;
249  fTip = nullptr;
250  fBorderSize = bordersize;
251  fBorderMode = bordermode;
252  if (gPad) fCanvas = gPad->GetCanvas();
253  else fCanvas = (TCanvas*)this;
254  fMother = (TPad*)gPad;
255  fPrimitives = new TList;
256  fExecs = new TList;
257  fPadPointer = nullptr;
258  fTheta = 30;
259  fPhi = 30;
260  fGridx = gStyle->GetPadGridX();
261  fGridy = gStyle->GetPadGridY();
262  fTickx = gStyle->GetPadTickX();
263  fTicky = gStyle->GetPadTickY();
264  fFrame = nullptr;
265  fView = nullptr;
266  fPadPaint = 0;
267  fPadView3D = nullptr;
268  fPixmapID = -1; // -1 means pixmap will be created by ResizePad()
269  fCopyGLDevice = kFALSE;
270  fEmbeddedGL = kFALSE;
271  fNumber = 0;
272  fAbsCoord = kFALSE;
273  fEditable = kTRUE;
274  fCrosshair = 0;
275  fCrosshairPos = 0;
276 
277  fVtoAbsPixelk = 0.;
278  fVtoPixelk = 0.;
279  fVtoPixel = 0.;
280  fAbsPixeltoXk = 0.;
281  fPixeltoXk = 0.;
282  fPixeltoX = 0;
283  fAbsPixeltoYk = 0.;
284  fPixeltoYk = 0.;
285  fPixeltoY = 0.;
286  fXlowNDC = 0;
287  fYlowNDC = 0;
288  fWNDC = 1;
289  fHNDC = 1;
290  fXUpNDC = 0.;
291  fYUpNDC = 0.;
292  fAbsXlowNDC = 0.;
293  fAbsYlowNDC = 0.;
294  fAbsWNDC = 0.;
295  fAbsHNDC = 0.;
296  fXtoAbsPixelk = 0.;
297  fXtoPixelk = 0.;
298  fXtoPixel = 0.;
299  fYtoAbsPixelk = 0.;
300  fYtoPixelk = 0.;
301  fYtoPixel = 0.;
302  fUtoAbsPixelk = 0.;
303  fUtoPixelk = 0.;
304  fUtoPixel = 0.;
305 
306  fUxmin = fUymin = fUxmax = fUymax = 0;
307  fLogx = gStyle->GetOptLogx();
308  fLogy = gStyle->GetOptLogy();
309  fLogz = gStyle->GetOptLogz();
310 
311  fFixedAspectRatio = kFALSE;
312  fAspectRatio = 0.;
313 
314  fNumPaletteColor = 0;
315  fNextPaletteColor = 0;
316  fCollideGrid = nullptr;
317  fCGnx = 0;
318  fCGny = 0;
319 
320  fViewer3D = nullptr;
321 
322  fGLDevice = fCanvas->GetGLDevice();
323  // Set default world coordinates to NDC [0,1]
324  fX1 = 0;
325  fX2 = 1;
326  fY1 = 0;
327  fY2 = 1;
328 
329  if (!gPad) {
330  Error("TPad", "You must create a TCanvas before creating a TPad");
331  MakeZombie();
332  return;
333  }
334 
335  TPad *padsav = (TPad*)gPad;
336 
337  if ((xlow < 0) || (xlow > 1) || (ylow < 0) || (ylow > 1)) {
338  Error("TPad", "illegal bottom left position: x=%f, y=%f", xlow, ylow);
339  goto zombie;
340  }
341  if ((xup < 0) || (xup > 1) || (yup < 0) || (yup > 1)) {
342  Error("TPad", "illegal top right position: x=%f, y=%f", xup, yup);
343  goto zombie;
344  }
345 
346  fLogx = gStyle->GetOptLogx();
347  fLogy = gStyle->GetOptLogy();
348  fLogz = gStyle->GetOptLogz();
349 
350  fUxmin = fUymin = fUxmax = fUymax = 0;
351 
352  // Set pad parameters and Compute conversion coefficients
353  SetPad(name, title, xlow, ylow, xup, yup, color, bordersize, bordermode);
354  Range(0, 0, 1, 1);
355  SetBit(kMustCleanup);
356  SetBit(kCanDelete);
357 
358  padsav->cd();
359  return;
360 
361 zombie:
362  // error in creating pad occurred, make this pad a zombie
363  MakeZombie();
364  padsav->cd();
365 }
366 
367 
368 ////////////////////////////////////////////////////////////////////////////////
369 /// Pad destructor.
370 
371 TPad::~TPad()
372 {
373  if (!TestBit(kNotDeleted)) return;
374  Close();
375  CloseToolTip(fTip);
376  DeleteToolTip(fTip);
377  auto primitives = fPrimitives;
378  // In some cases, fPrimitives has the kMustCleanup bit set which will lead
379  // its destructor to call RecursiveRemove and since this pad is still
380  // likely to be (indirectly) in the list of cleanups, we must set
381  // fPrimitives to nullptr to avoid TPad::RecursiveRemove from calling
382  // a member function of a partially destructed object.
383  fPrimitives = nullptr;
384  delete primitives;
385  SafeDelete(fExecs);
386  delete fViewer3D;
387  if (fCollideGrid) delete [] fCollideGrid;
388 
389  // Required since we overload TObject::Hash.
390  ROOT::CallRecursiveRemoveIfNeeded(*this);
391 }
392 
393 ////////////////////////////////////////////////////////////////////////////////
394 /// Add a new TExec object to the list of Execs.
395 ///
396 /// When an event occurs in the pad (mouse click, etc) the list of C++ commands
397 /// in the list of Execs are executed via TPad::AutoExec.
398 ///
399 /// When a pad event occurs (mouse move, click, etc) all the commands
400 /// contained in the fExecs list are executed in the order found in the list.
401 ///
402 /// This facility is activated by default. It can be deactivated by using
403 /// the canvas "Option" menu.
404 ///
405 /// The following examples of TExec commands are provided in the tutorials:
406 /// macros exec1.C and exec2.C.
407 ///
408 /// ### Example1 of use of exec1.C
409 /// ~~~ {.cpp}
410 /// Root > TFile f("hsimple.root")
411 /// Root > hpx.Draw()
412 /// Root > c1.AddExec("ex1",".x exec1.C")
413 /// ~~~
414 ///
415 /// At this point you can use the mouse to click on the contour of
416 /// the histogram hpx. When the mouse is clicked, the bin number and its
417 /// contents are printed.
418 ///
419 /// ### Example2 of use of exec1.C
420 /// ~~~ {.cpp}
421 /// Root > TFile f("hsimple.root")
422 /// Root > hpxpy.Draw()
423 /// Root > c1.AddExec("ex2",".x exec2.C")
424 /// ~~~
425 ///
426 /// When moving the mouse in the canvas, a second canvas shows the
427 /// projection along X of the bin corresponding to the Y position
428 /// of the mouse. The resulting histogram is fitted with a gaussian.
429 /// A "dynamic" line shows the current bin position in Y.
430 /// This more elaborated example can be used as a starting point
431 /// to develop more powerful interactive applications exploiting the C++
432 /// interpreter as a development engine.
433 
434 void TPad::AddExec(const char *name, const char*command)
435 {
436  if (!fExecs) fExecs = new TList;
437  TExec *ex = new TExec(name,command);
438  fExecs->Add(ex);
439 }
440 
441 ////////////////////////////////////////////////////////////////////////////////
442 /// Execute the list of Execs when a pad event occurs.
443 
444 void TPad::AutoExec()
445 {
446  if (GetCrosshair()) DrawCrosshair();
447 
448  if (!fExecs) fExecs = new TList;
449  TIter next(fExecs);
450  TExec *exec;
451  while ((exec = (TExec*)next())) {
452  exec->Exec();
453  }
454 }
455 
456 ////////////////////////////////////////////////////////////////////////////////
457 /// Browse pad.
458 
459 void TPad::Browse(TBrowser *b)
460 {
461  cd();
462  if (fPrimitives) fPrimitives->Browse(b);
463 }
464 
465 ////////////////////////////////////////////////////////////////////////////////
466 /// Build a legend from the graphical objects in the pad.
467 ///
468 /// A simple method to build automatically a TLegend from the primitives in a TPad.
469 ///
470 /// Only those deriving from TAttLine, TAttMarker and TAttFill are added, excluding
471 /// TPave and TFrame derived classes.
472 ///
473 /// \return The built TLegend
474 ///
475 /// \param[in] x1, y1, x2, y2 The TLegend coordinates
476 /// \param[in] title The legend title. By default it is " "
477 /// \param[in] option The TLegend option
478 ///
479 /// The caller program owns the returned TLegend.
480 ///
481 /// If the pad contains some TMultiGraph or THStack the individual
482 /// graphs or histograms in them are added to the TLegend.
483 ///
484 /// ### Automatic placement of the legend
485 /// If `x1` is equal to `x2` and `y1` is equal to `y2` the legend will be automatically
486 /// placed to avoid overlapping with the existing primitives already displayed.
487 /// `x1` is considered as the width of the legend and `y1` the height. By default
488 /// the legend is automatically placed with width = `x1`= `x2` = 0.3 and
489 /// height = `y1`= `y2` = 0.21.
490 
491 TLegend *TPad::BuildLegend(Double_t x1, Double_t y1, Double_t x2, Double_t y2,
492  const char* title, Option_t *option)
493 {
494  TList *lop=GetListOfPrimitives();
495  if (!lop) return 0;
496  TLegend *leg=0;
497  TIter next(lop);
498  TString mes;
499  TObject *o=0;
500  TString opt("");
501  while( (o=next()) ) {
502  if((o->InheritsFrom(TAttLine::Class()) || o->InheritsFrom(TAttMarker::Class()) ||
503  o->InheritsFrom(TAttFill::Class())) &&
504  ( !(o->InheritsFrom(TFrame::Class())) && !(o->InheritsFrom(TPave::Class())) )) {
505  if (!leg) leg = new TLegend(x1, y1, x2, y2, title);
506  if (o->InheritsFrom(TNamed::Class()) && strlen(((TNamed *)o)->GetTitle()))
507  mes = ((TNamed *)o)->GetTitle();
508  else if (strlen(o->GetName()))
509  mes = o->GetName();
510  else
511  mes = o->ClassName();
512  if (strlen(option)) {
513  opt = option;
514  } else {
515  if (o->InheritsFrom(TAttLine::Class())) opt += "l";
516  if (o->InheritsFrom(TAttMarker::Class())) opt += "p";
517  if (o->InheritsFrom(TAttFill::Class())) opt += "f";
518  }
519  leg->AddEntry(o,mes.Data(),opt.Data());
520  } else if ( o->InheritsFrom(TMultiGraph::Class() ) ) {
521  if (!leg) leg = new TLegend(x1, y1, x2, y2, title);
522  TList * grlist = ((TMultiGraph *)o)->GetListOfGraphs();
523  TIter nextgraph(grlist);
524  TGraph * gr;
525  TObject * obj;
526  while ((obj = nextgraph())) {
527  gr = (TGraph*) obj;
528  if (strlen(gr->GetTitle())) mes = gr->GetTitle();
529  else if (strlen(gr->GetName())) mes = gr->GetName();
530  else mes = gr->ClassName();
531  if (strlen(option)) opt = option;
532  else opt = "lpf";
533  leg->AddEntry( obj, mes.Data(), opt );
534  }
535  } else if ( o->InheritsFrom(THStack::Class() ) ) {
536  if (!leg) leg = new TLegend(x1, y1, x2, y2, title);
537  TList * hlist = ((THStack *)o)->GetHists();
538  TIter nexthist(hlist);
539  TH1 * hist;
540  TObject * obj;
541  while ((obj = nexthist())) {
542  hist = (TH1*) obj;
543  if (strlen(hist->GetTitle())) mes = hist->GetTitle();
544  else if (strlen(hist->GetName())) mes = hist->GetName();
545  else mes = hist->ClassName();
546  if (strlen(option)) opt = option;
547  else opt = "lpf";
548  leg->AddEntry( obj, mes.Data(), opt );
549  }
550  }
551  }
552  if (leg) {
553  TVirtualPad *gpadsave;
554  gpadsave = gPad;
555  this->cd();
556  leg->Draw();
557  gpadsave->cd();
558  } else {
559  Info("BuildLegend(void)","No object to build a TLegend.");
560  }
561  return leg;
562 }
563 
564 ////////////////////////////////////////////////////////////////////////////////
565 /// Set Current pad.
566 ///
567 /// When a canvas/pad is divided via TPad::Divide, one can directly
568 /// set the current path to one of the subdivisions.
569 /// See TPad::Divide for the convention to number sub-pads.
570 ///
571 /// Returns the new current pad, or 0 in case of failure.
572 ///
573 /// For example:
574 /// ~~~ {.cpp}
575 /// c1.Divide(2,3); // create 6 pads (2 divisions along x, 3 along y).
576 /// ~~~
577 /// To set the current pad to the bottom right pad, do
578 /// ~~~ {.cpp}
579 /// c1.cd(6);
580 /// ~~~
581 /// Note1: c1.cd() is equivalent to c1.cd(0) and sets the current pad
582 /// to c1 itself.
583 ///
584 /// Note2: after a statement like c1.cd(6), the global variable gPad
585 /// points to the current pad. One can use gPad to set attributes
586 /// of the current pad.
587 ///
588 /// Note3: One can get a pointer to one of the sub-pads of pad with:
589 /// TPad *subpad = (TPad*)pad->GetPad(subpadnumber);
590 
591 TVirtualPad *TPad::cd(Int_t subpadnumber)
592 {
593  if (!subpadnumber) {
594  gPad = this;
595  if (!gPad->IsBatch() && GetPainter()) GetPainter()->SelectDrawable(fPixmapID);
596  return gPad;
597  }
598 
599  TObject *obj;
600  if (!fPrimitives) fPrimitives = new TList;
601  TIter next(fPrimitives);
602  while ((obj = next())) {
603  if (obj->InheritsFrom(TPad::Class())) {
604  Int_t n = ((TPad*)obj)->GetNumber();
605  if (n == subpadnumber) {
606  return ((TPad*)obj)->cd();
607  }
608  }
609  }
610  return 0;
611 }
612 
613 ////////////////////////////////////////////////////////////////////////////////
614 /// Delete all pad primitives.
615 ///
616 /// If the bit kClearAfterCR has been set for this pad, the Clear function
617 /// will execute only after having pressed a CarriageReturn
618 /// Set the bit with `mypad->SetBit(TPad::kClearAfterCR)`
619 
620 void TPad::Clear(Option_t *option)
621 {
622  if (!IsEditable()) return;
623 
624  R__LOCKGUARD(gROOTMutex);
625 
626  if (!fPadPaint) {
627  SafeDelete(fView);
628  if (fPrimitives) fPrimitives->Clear(option);
629  if (fFrame) {
630  if (fFrame->TestBit(kNotDeleted)) delete fFrame;
631  fFrame = nullptr;
632  }
633  }
634  if (fCanvas) fCanvas->Cleared(this);
635 
636  cd();
637 
638  if (TestBit(kClearAfterCR)) {
639  // Intentional do not use the return value of getchar,
640  // we just want to get it and forget it
641  getchar();
642  }
643 
644  if (!gPad->IsBatch()) GetPainter()->ClearDrawable();
645  if (gVirtualPS && gPad == gPad->GetCanvas()) gVirtualPS->NewPage();
646 
647  PaintBorder(GetFillColor(), kTRUE);
648  fCrosshairPos = 0;
649  fNumPaletteColor = 0;
650  if (fCollideGrid) {
651  delete [] fCollideGrid;
652  fCollideGrid = nullptr;
653  fCGnx = 0;
654  fCGny = 0;
655  }
656  ResetBit(TGraph::kClipFrame);
657 }
658 
659 ////////////////////////////////////////////////////////////////////////////////
660 /// Clipping routine: Cohen Sutherland algorithm.
661 ///
662 /// - If Clip ==2 the segment is outside the boundary.
663 /// - If Clip ==1 the segment has one point outside the boundary.
664 /// - If Clip ==0 the segment is inside the boundary.
665 ///
666 /// \param[in] x[],y[] Segment coordinates (2 points)
667 /// \param[in] xclipl,yclipb,xclipr,yclipt Clipping boundary
668 /// \param[out] x[],y[] New segment coordinates( 2 points)
669 
670 Int_t TPad::Clip(Float_t *x, Float_t *y, Float_t xclipl, Float_t yclipb, Float_t xclipr, Float_t yclipt)
671 {
672  const Float_t kP=10000;
673  Int_t clip = 0;
674 
675  for (Int_t i=0;i<2;i++) {
676  if (TMath::Abs(xclipl-x[i]) <= TMath::Abs(xclipr-xclipl)/kP) x[i] = xclipl;
677  if (TMath::Abs(xclipr-x[i]) <= TMath::Abs(xclipr-xclipl)/kP) x[i] = xclipr;
678  if (TMath::Abs(yclipb-y[i]) <= TMath::Abs(yclipt-yclipb)/kP) y[i] = yclipb;
679  if (TMath::Abs(yclipt-y[i]) <= TMath::Abs(yclipt-yclipb)/kP) y[i] = yclipt;
680  }
681 
682  // Compute the first endpoint codes.
683  Int_t code1 = ClippingCode(x[0],y[0],xclipl,yclipb,xclipr,yclipt);
684  Int_t code2 = ClippingCode(x[1],y[1],xclipl,yclipb,xclipr,yclipt);
685 
686  Double_t xt=0, yt=0;
687  Int_t clipped = 0; //this variable could be used in a future version
688  while(code1 + code2) {
689  clipped = 1;
690 
691  // The line lies entirely outside the clipping boundary
692  if (code1&code2) {
693  clip = 2;
694  return clip;
695  }
696 
697  // The line is subdivided into several parts
698  Int_t ic = code1;
699  if (ic == 0) ic = code2;
700  if (ic & 0x1) {
701  yt = y[0] + (y[1]-y[0])*(xclipl-x[0])/(x[1]-x[0]);
702  xt = xclipl;
703  }
704  if (ic & 0x2) {
705  yt = y[0] + (y[1]-y[0])*(xclipr-x[0])/(x[1]-x[0]);
706  xt = xclipr;
707  }
708  if (ic & 0x4) {
709  xt = x[0] + (x[1]-x[0])*(yclipb-y[0])/(y[1]-y[0]);
710  yt = yclipb;
711  }
712  if (ic & 0x8) {
713  xt = x[0] + (x[1]-x[0])*(yclipt-y[0])/(y[1]-y[0]);
714  yt = yclipt;
715  }
716  if (ic == code1) {
717  x[0] = xt;
718  y[0] = yt;
719  code1 = ClippingCode(xt,yt,xclipl,yclipb,xclipr,yclipt);
720  } else {
721  x[1] = xt;
722  y[1] = yt;
723  code2 = ClippingCode(xt,yt,xclipl,yclipb,xclipr,yclipt);
724  }
725  }
726  clip = clipped;
727  return clip;
728 }
729 
730 ////////////////////////////////////////////////////////////////////////////////
731 /// Clipping routine: Cohen Sutherland algorithm.
732 ///
733 /// - If Clip ==2 the segment is outside the boundary.
734 /// - If Clip ==1 the segment has one point outside the boundary.
735 /// - If Clip ==0 the segment is inside the boundary.
736 ///
737 /// \param[in] x[],y[] Segment coordinates (2 points)
738 /// \param[in] xclipl,yclipb,xclipr,yclipt Clipping boundary
739 /// \param[out] x[],y[] New segment coordinates(2 points)
740 
741 Int_t TPad::Clip(Double_t *x, Double_t *y, Double_t xclipl, Double_t yclipb, Double_t xclipr, Double_t yclipt)
742 {
743  const Double_t kP=10000;
744  Int_t clip = 0;
745 
746  for (Int_t i=0;i<2;i++) {
747  if (TMath::Abs(xclipl-x[i]) <= TMath::Abs(xclipr-xclipl)/kP) x[i] = xclipl;
748  if (TMath::Abs(xclipr-x[i]) <= TMath::Abs(xclipr-xclipl)/kP) x[i] = xclipr;
749  if (TMath::Abs(yclipb-y[i]) <= TMath::Abs(yclipt-yclipb)/kP) y[i] = yclipb;
750  if (TMath::Abs(yclipt-y[i]) <= TMath::Abs(yclipt-yclipb)/kP) y[i] = yclipt;
751  }
752 
753  // Compute the first endpoint codes.
754  Int_t code1 = 0;
755  if (x[0] < xclipl) code1 = code1 | 0x1;
756  if (x[0] > xclipr) code1 = code1 | 0x2;
757  if (y[0] < yclipb) code1 = code1 | 0x4;
758  if (y[0] > yclipt) code1 = code1 | 0x8;
759  Int_t code2 = 0;
760  if (x[1] < xclipl) code2 = code2 | 0x1;
761  if (x[1] > xclipr) code2 = code2 | 0x2;
762  if (y[1] < yclipb) code2 = code2 | 0x4;
763  if (y[1] > yclipt) code2 = code2 | 0x8;
764 
765  Double_t xt=0, yt=0;
766  Int_t clipped = 0; //this variable could be used in a future version
767  while(code1 + code2) {
768  clipped = 1;
769 
770  // The line lies entirely outside the clipping boundary
771  if (code1&code2) {
772  clip = 2;
773  return clip;
774  }
775 
776  // The line is subdivided into several parts
777  Int_t ic = code1;
778  if (ic == 0) ic = code2;
779  if (ic & 0x1) {
780  yt = y[0] + (y[1]-y[0])*(xclipl-x[0])/(x[1]-x[0]);
781  xt = xclipl;
782  }
783  if (ic & 0x2) {
784  yt = y[0] + (y[1]-y[0])*(xclipr-x[0])/(x[1]-x[0]);
785  xt = xclipr;
786  }
787  if (ic & 0x4) {
788  xt = x[0] + (x[1]-x[0])*(yclipb-y[0])/(y[1]-y[0]);
789  yt = yclipb;
790  }
791  if (ic & 0x8) {
792  xt = x[0] + (x[1]-x[0])*(yclipt-y[0])/(y[1]-y[0]);
793  yt = yclipt;
794  }
795  if (ic == code1) {
796  x[0] = xt;
797  y[0] = yt;
798  code1 = ClippingCode(xt,yt,xclipl,yclipb,xclipr,yclipt);
799  } else {
800  x[1] = xt;
801  y[1] = yt;
802  code2 = ClippingCode(xt,yt,xclipl,yclipb,xclipr,yclipt);
803  }
804  }
805  clip = clipped;
806  return clip;
807 }
808 
809 ////////////////////////////////////////////////////////////////////////////////
810 /// Compute the endpoint codes for TPad::Clip.
811 
812 Int_t TPad::ClippingCode(Double_t x, Double_t y, Double_t xcl1, Double_t ycl1, Double_t xcl2, Double_t ycl2)
813 {
814  Int_t code = 0;
815  if (x < xcl1) code = code | 0x1;
816  if (x > xcl2) code = code | 0x2;
817  if (y < ycl1) code = code | 0x4;
818  if (y > ycl2) code = code | 0x8;
819  return code;
820 }
821 
822 ////////////////////////////////////////////////////////////////////////////////
823 /// Clip polygon using the Sutherland-Hodgman algorithm.
824 ///
825 /// \param[in] n Number of points in the polygon to
826 /// be clipped
827 /// \param[in] x[n],y[n] Polygon do be clipped vertices
828 /// \param[in] xclipl,yclipb,xclipr,yclipt Clipping boundary
829 /// \param[out] nn Number of points in xc and yc
830 /// \param[out] xc,yc Clipped polygon vertices. The Int_t
831 /// returned by this function is
832 /// the number of points in the clipped
833 /// polygon. These vectors must
834 /// be allocated by the calling function.
835 /// A size of 2*n for each is
836 /// enough.
837 ///
838 /// Sutherland and Hodgman's polygon-clipping algorithm uses a divide-and-conquer
839 /// strategy: It solves a series of simple and identical problems that, when
840 /// combined, solve the overall problem. The simple problem is to clip a polygon
841 /// against a single infinite clip edge. Four clip edges, each defining one boundary
842 /// of the clip rectangle, successively clip a polygon against a clip rectangle.
843 ///
844 /// Steps of Sutherland-Hodgman's polygon-clipping algorithm:
845 ///
846 /// * Polygons can be clipped against each edge of the window one at a time.
847 /// Windows/edge intersections, if any, are easy to find since the X or Y coordinates
848 /// are already known.
849 /// * Vertices which are kept after clipping against one window edge are saved for
850 /// clipping against the remaining edges.
851 /// * Note that the number of vertices usually changes and will often increases.
852 ///
853 /// The clip boundary determines a visible and invisible region. The edges from
854 /// vertex i to vertex i+1 can be one of four types:
855 ///
856 /// * Case 1 : Wholly inside visible region - save endpoint
857 /// * Case 2 : Exit visible region - save the intersection
858 /// * Case 3 : Wholly outside visible region - save nothing
859 /// * Case 4 : Enter visible region - save intersection and endpoint
860 
861 Int_t TPad::ClipPolygon(Int_t n, Double_t *x, Double_t *y, Int_t nn, Double_t *xc, Double_t *yc, Double_t xclipl, Double_t yclipb, Double_t xclipr, Double_t yclipt)
862 {
863  Int_t nc, nc2;
864  Double_t x1, y1, x2, y2, slope; // Segment to be clipped
865 
866  Double_t *xc2 = new Double_t[nn];
867  Double_t *yc2 = new Double_t[nn];
868 
869  // Clip against the left boundary
870  x1 = x[n-1]; y1 = y[n-1];
871  nc2 = 0;
872  Int_t i;
873  for (i=0; i<n; i++) {
874  x2 = x[i]; y2 = y[i];
875  if (x1 == x2) {
876  slope = 0;
877  } else {
878  slope = (y2-y1)/(x2-x1);
879  }
880  if (x1 >= xclipl) {
881  if (x2 < xclipl) {
882  xc2[nc2] = xclipl; yc2[nc2++] = slope*(xclipl-x1)+y1;
883  } else {
884  xc2[nc2] = x2; yc2[nc2++] = y2;
885  }
886  } else {
887  if (x2 >= xclipl) {
888  xc2[nc2] = xclipl; yc2[nc2++] = slope*(xclipl-x1)+y1;
889  xc2[nc2] = x2; yc2[nc2++] = y2;
890  }
891  }
892  x1 = x2; y1 = y2;
893  }
894 
895  // Clip against the top boundary
896  x1 = xc2[nc2-1]; y1 = yc2[nc2-1];
897  nc = 0;
898  for (i=0; i<nc2; i++) {
899  x2 = xc2[i]; y2 = yc2[i];
900  if (y1 == y2) {
901  slope = 0;
902  } else {
903  slope = (x2-x1)/(y2-y1);
904  }
905  if (y1 <= yclipt) {
906  if (y2 > yclipt) {
907  xc[nc] = x1+(yclipt-y1)*slope; yc[nc++] = yclipt;
908  } else {
909  xc[nc] = x2; yc[nc++] = y2;
910  }
911  } else {
912  if (y2 <= yclipt) {
913  xc[nc] = x1+(yclipt-y1)*slope; yc[nc++] = yclipt;
914  xc[nc] = x2; yc[nc++] = y2;
915  }
916  }
917  x1 = x2; y1 = y2;
918  }
919 
920  if (nc>0) {
921 
922  // Clip against the right boundary
923  x1 = xc[nc-1]; y1 = yc[nc-1];
924  nc2 = 0;
925  for (i=0; i<nc; i++) {
926  x2 = xc[i]; y2 = yc[i];
927  if (x1 == x2) {
928  slope = 0;
929  } else {
930  slope = (y2-y1)/(x2-x1);
931  }
932  if (x1 <= xclipr) {
933  if (x2 > xclipr) {
934  xc2[nc2] = xclipr; yc2[nc2++] = slope*(xclipr-x1)+y1;
935  } else {
936  xc2[nc2] = x2; yc2[nc2++] = y2;
937  }
938  } else {
939  if (x2 <= xclipr) {
940  xc2[nc2] = xclipr; yc2[nc2++] = slope*(xclipr-x1)+y1;
941  xc2[nc2] = x2; yc2[nc2++] = y2;
942  }
943  }
944  x1 = x2; y1 = y2;
945  }
946 
947  // Clip against the bottom boundary
948  x1 = xc2[nc2-1]; y1 = yc2[nc2-1];
949  nc = 0;
950  for (i=0; i<nc2; i++) {
951  x2 = xc2[i]; y2 = yc2[i];
952  if (y1 == y2) {
953  slope = 0;
954  } else {
955  slope = (x2-x1)/(y2-y1);
956  }
957  if (y1 >= yclipb) {
958  if (y2 < yclipb) {
959  xc[nc] = x1+(yclipb-y1)*slope; yc[nc++] = yclipb;
960  } else {
961  xc[nc] = x2; yc[nc++] = y2;
962  }
963  } else {
964  if (y2 >= yclipb) {
965  xc[nc] = x1+(yclipb-y1)*slope; yc[nc++] = yclipb;
966  xc[nc] = x2; yc[nc++] = y2;
967  }
968  }
969  x1 = x2; y1 = y2;
970  }
971  }
972 
973  delete [] xc2;
974  delete [] yc2;
975 
976  if (nc < 3) nc =0;
977  return nc;
978 }
979 
980 ////////////////////////////////////////////////////////////////////////////////
981 /// Delete all primitives in pad and pad itself.
982 /// Pad cannot be used anymore after this call.
983 /// Emits signal "Closed()".
984 
985 void TPad::Close(Option_t *)
986 {
987  if (!TestBit(kNotDeleted)) return;
988  if (!fMother) return;
989  if (!fMother->TestBit(kNotDeleted)) return;
990 
991  if (fPrimitives)
992  fPrimitives->Clear();
993  if (fView) {
994  if (fView->TestBit(kNotDeleted)) delete fView;
995  fView = nullptr;
996  }
997  if (fFrame) {
998  if (fFrame->TestBit(kNotDeleted)) delete fFrame;
999  fFrame = nullptr;
1000  }
1001 
1002  // emit signal
1003  if (IsA() != TCanvas::Class())
1004  Closed();
1005 
1006  if (fPixmapID != -1) {
1007  if (gPad) {
1008  if (!gPad->IsBatch())
1009  GetPainter()->DestroyDrawable(fPixmapID);
1010  }
1011  fPixmapID = -1;
1012 
1013  if (!gROOT->GetListOfCanvases()) return;
1014  if (fMother == this) {
1015  gROOT->GetListOfCanvases()->Remove(this);
1016  return; // in case of TCanvas
1017  }
1018 
1019  // remove from the mother's list of primitives
1020  if (fMother) {
1021  if (fMother->GetListOfPrimitives())
1022  fMother->GetListOfPrimitives()->Remove(this);
1023 
1024  if (gPad == this) fMother->cd();
1025  }
1026 
1027  if (fCanvas->GetPadSave() == this)
1028  fCanvas->ClearPadSave();
1029  if (fCanvas->GetSelectedPad() == this)
1030  fCanvas->SetSelectedPad(0);
1031  if (fCanvas->GetClickSelectedPad() == this)
1032  fCanvas->SetClickSelectedPad(0);
1033  }
1034 
1035  fMother = nullptr;
1036  if (gROOT->GetSelectedPad() == this) gROOT->SetSelectedPad(nullptr);
1037 }
1038 
1039 ////////////////////////////////////////////////////////////////////////////////
1040 /// Copy the pixmap of the pad to the canvas.
1041 
1042 void TPad::CopyPixmap()
1043 {
1044  int px, py;
1045  XYtoAbsPixel(fX1, fY2, px, py);
1046 
1047  if (fPixmapID != -1)
1048  GetPainter()->CopyDrawable(fPixmapID, px, py);
1049 
1050  if (this == gPad) HighLight(gPad->GetHighLightColor());
1051 }
1052 
1053 ////////////////////////////////////////////////////////////////////////////////
1054 /// Copy the sub-pixmaps of the pad to the canvas.
1055 
1056 void TPad::CopyPixmaps()
1057 {
1058  TObject *obj;
1059  if (!fPrimitives) fPrimitives = new TList;
1060  TIter next(GetListOfPrimitives());
1061  while ((obj = next())) {
1062  if (obj->InheritsFrom(TPad::Class())) {
1063  ((TPad*)obj)->CopyPixmap();
1064  ((TPad*)obj)->CopyPixmaps();
1065  }
1066  }
1067 }
1068 
1069 ////////////////////////////////////////////////////////////////////////////////
1070 /// Remove TExec name from the list of Execs.
1071 
1072 void TPad::DeleteExec(const char *name)
1073 {
1074  if (!fExecs) fExecs = new TList;
1075  TExec *ex = (TExec*)fExecs->FindObject(name);
1076  if (!ex) return;
1077  fExecs->Remove(ex);
1078  delete ex;
1079 }
1080 
1081 ////////////////////////////////////////////////////////////////////////////////
1082 /// Compute distance from point px,py to a box.
1083 ///
1084 /// Compute the closest distance of approach from point px,py to the
1085 /// edges of this pad.
1086 /// The distance is computed in pixels units.
1087 
1088 Int_t TPad::DistancetoPrimitive(Int_t px, Int_t py)
1089 {
1090  Int_t pxl, pyl, pxt, pyt;
1091  Int_t px1 = gPad->XtoAbsPixel(fX1);
1092  Int_t py1 = gPad->YtoAbsPixel(fY1);
1093  Int_t px2 = gPad->XtoAbsPixel(fX2);
1094  Int_t py2 = gPad->YtoAbsPixel(fY2);
1095  if (px1 < px2) {pxl = px1; pxt = px2;}
1096  else {pxl = px2; pxt = px1;}
1097  if (py1 < py2) {pyl = py1; pyt = py2;}
1098  else {pyl = py2; pyt = py1;}
1099 
1100  // Are we inside the box?
1101  // ======================
1102  if ( (px > pxl && px < pxt) && (py > pyl && py < pyt) ) {
1103  if (GetFillStyle()) return 0; //*-* if pad is filled
1104  }
1105 
1106  // Are we on the edges?
1107  // ====================
1108  Int_t dxl = TMath::Abs(px - pxl);
1109  if (py < pyl) dxl += pyl - py;
1110  if (py > pyt) dxl += py - pyt;
1111  Int_t dxt = TMath::Abs(px - pxt);
1112  if (py < pyl) dxt += pyl - py;
1113  if (py > pyt) dxt += py - pyt;
1114  Int_t dyl = TMath::Abs(py - pyl);
1115  if (px < pxl) dyl += pxl - px;
1116  if (px > pxt) dyl += px - pxt;
1117  Int_t dyt = TMath::Abs(py - pyt);
1118  if (px < pxl) dyt += pxl - px;
1119  if (px > pxt) dyt += px - pxt;
1120 
1121  Int_t distance = dxl;
1122  if (dxt < distance) distance = dxt;
1123  if (dyl < distance) distance = dyl;
1124  if (dyt < distance) distance = dyt;
1125 
1126  return distance - Int_t(0.5*fLineWidth);
1127 }
1128 
1129 ////////////////////////////////////////////////////////////////////////////////
1130 /// Automatic pad generation by division.
1131 ///
1132 /// - The current canvas is divided in nx by ny equal divisions (pads).
1133 /// - xmargin is the space along x between pads in percent of canvas.
1134 /// - ymargin is the space along y between pads in percent of canvas.
1135 /// - color is the color of the new pads. If 0, color is the canvas color.
1136 ///
1137 /// Pads are automatically named `canvasname_n` where `n` is the division number
1138 /// starting from top left pad.
1139 ///
1140 /// Example if canvasname=c1 , nx=2, ny=3:
1141 ///
1142 /// \image html gpad_pad3.png
1143 ///
1144 /// Once a pad is divided into sub-pads, one can set the current pad
1145 /// to a subpad with a given division number as illustrated above
1146 /// with TPad::cd(subpad_number).
1147 ///
1148 /// For example, to set the current pad to c1_4, one can do:
1149 /// ~~~ {.cpp}
1150 /// c1->cd(4)
1151 /// ~~~
1152 /// __Note1:__ c1.cd() is equivalent to c1.cd(0) and sets the current pad
1153 /// to c1 itself.
1154 ///
1155 /// __Note2:__ after a statement like c1.cd(6), the global variable gPad
1156 /// points to the current pad. One can use gPad to set attributes
1157 /// of the current pad.
1158 ///
1159 /// __Note3:__ in case xmargin <=0 and ymargin <= 0, there is no space
1160 /// between pads. The current pad margins are recomputed to
1161 /// optimize the layout.
1162 
1163 void TPad::Divide(Int_t nx, Int_t ny, Float_t xmargin, Float_t ymargin, Int_t color)
1164 {
1165  if (!IsEditable()) return;
1166 
1167 
1168  if (gThreadXAR) {
1169  void *arr[7];
1170  arr[1] = this; arr[2] = (void*)&nx;arr[3] = (void*)& ny;
1171  arr[4] = (void*)&xmargin; arr[5] = (void *)& ymargin; arr[6] = (void *)&color;
1172  if ((*gThreadXAR)("PDCD", 7, arr, 0)) return;
1173  }
1174 
1175  TPad *padsav = (TPad*)gPad;
1176  cd();
1177  if (nx <= 0) nx = 1;
1178  if (ny <= 0) ny = 1;
1179  Int_t ix,iy;
1180  Double_t x1,y1,x2,y2;
1181  Double_t dx,dy;
1182  TPad *pad;
1183  Int_t nchname = strlen(GetName())+6;
1184  Int_t nchtitle = strlen(GetTitle())+6;
1185  char *name = new char [nchname];
1186  char *title = new char [nchtitle];
1187  Int_t n = 0;
1188  if (color == 0) color = GetFillColor();
1189  if (xmargin > 0 && ymargin > 0) {
1190  //general case
1191  dy = 1/Double_t(ny);
1192  dx = 1/Double_t(nx);
1193  for (iy=0;iy<ny;iy++) {
1194  y2 = 1 - iy*dy - ymargin;
1195  y1 = y2 - dy + 2*ymargin;
1196  if (y1 < 0) y1 = 0;
1197  if (y1 > y2) continue;
1198  for (ix=0;ix<nx;ix++) {
1199  x1 = ix*dx + xmargin;
1200  x2 = x1 +dx -2*xmargin;
1201  if (x1 > x2) continue;
1202  n++;
1203  snprintf(name,nchname,"%s_%d",GetName(),n);
1204  pad = new TPad(name,name,x1,y1,x2,y2,color);
1205  pad->SetNumber(n);
1206  pad->Draw();
1207  }
1208  }
1209  } else {
1210  // special case when xmargin <= 0 && ymargin <= 0
1211  Double_t xl = GetLeftMargin();
1212  Double_t xr = GetRightMargin();
1213  Double_t yb = GetBottomMargin();
1214  Double_t yt = GetTopMargin();
1215  xl /= (1-xl+xr)*nx;
1216  xr /= (1-xl+xr)*nx;
1217  yb /= (1-yb+yt)*ny;
1218  yt /= (1-yb+yt)*ny;
1219  SetLeftMargin(xl);
1220  SetRightMargin(xr);
1221  SetBottomMargin(yb);
1222  SetTopMargin(yt);
1223  dx = (1-xl-xr)/nx;
1224  dy = (1-yb-yt)/ny;
1225  Int_t number = 0;
1226  for (Int_t i=0;i<nx;i++) {
1227  x1 = i*dx+xl;
1228  x2 = x1 + dx;
1229  if (i == 0) x1 = 0;
1230  if (i == nx-1) x2 = 1-xr;
1231  for (Int_t j=0;j<ny;j++) {
1232  number = j*nx + i +1;
1233  y2 = 1 -j*dy -yt;
1234  y1 = y2 - dy;
1235  if (j == 0) y2 = 1-yt;
1236  if (j == ny-1) y1 = 0;
1237  snprintf(name,nchname,"%s_%d",GetName(),number);
1238  snprintf(title,nchtitle,"%s_%d",GetTitle(),number);
1239  pad = new TPad(name,title,x1,y1,x2,y2);
1240  pad->SetNumber(number);
1241  pad->SetBorderMode(0);
1242  if (i == 0) pad->SetLeftMargin(xl*nx);
1243  else pad->SetLeftMargin(0);
1244  pad->SetRightMargin(0);
1245  pad->SetTopMargin(0);
1246  if (j == ny-1) pad->SetBottomMargin(yb*ny);
1247  else pad->SetBottomMargin(0);
1248  pad->Draw();
1249  }
1250  }
1251  }
1252  delete [] name;
1253  delete [] title;
1254  Modified();
1255  if (padsav) padsav->cd();
1256 }
1257 
1258 ////////////////////////////////////////////////////////////////////////////////
1259 /// "n" is the total number of sub-pads. The number of sub-pads along the X
1260 /// and Y axis are computed according to the square root of n.
1261 
1262 void TPad::DivideSquare(Int_t n, Float_t xmargin, Float_t ymargin, Int_t color)
1263 {
1264  Int_t w = 1, h = 1;
1265 
1266  if (fCanvas->GetWindowWidth() > fCanvas->GetWindowHeight()) {
1267  w = TMath::Ceil(TMath::Sqrt(n));
1268  h = TMath::Floor(TMath::Sqrt(n));
1269  if (w*h < n) w++;
1270  } else {
1271  h = TMath::Ceil(TMath::Sqrt(n));
1272  w = TMath::Floor(TMath::Sqrt(n));
1273  if (w*h < n) h++;
1274  }
1275 
1276  Divide( w, h, xmargin, ymargin, color);
1277 }
1278 
1279 ////////////////////////////////////////////////////////////////////////////////
1280 /// Draw Pad in Current pad (re-parent pad if necessary).
1281 
1282 void TPad::Draw(Option_t *option)
1283 {
1284  // if no canvas opened yet create a default canvas
1285  if (!gPad) {
1286  gROOT->MakeDefCanvas();
1287  }
1288 
1289  // pad cannot be in itself and it can only be in one other pad at a time
1290  if (!fPrimitives) fPrimitives = new TList;
1291  if (gPad != this) {
1292  if (fMother && fMother->TestBit(kNotDeleted)) fMother->GetListOfPrimitives()->Remove(this);
1293  TPad *oldMother = fMother;
1294  fCanvas = gPad->GetCanvas();
1295  //
1296  fMother = (TPad*)gPad;
1297  if (oldMother != fMother || fPixmapID == -1) ResizePad();
1298  }
1299 
1300  Paint();
1301 
1302  if (gPad->IsRetained() && gPad != this && fMother)
1303  fMother->GetListOfPrimitives()->Add(this, option);
1304 }
1305 
1306 ////////////////////////////////////////////////////////////////////////////////
1307 /// Draw class inheritance tree of the class to which obj belongs.
1308 ///
1309 /// If a class B inherits from a class A, description of B is drawn
1310 /// on the right side of description of A.
1311 ///
1312 /// Member functions overridden by B are shown in class A with a blue line
1313 /// crossing-out the corresponding member function.
1314 
1315 void TPad::DrawClassObject(const TObject *classobj, Option_t *option)
1316 {
1317  char dname[256];
1318  const Int_t kMAXLEVELS = 10;
1319  TClass *clevel[kMAXLEVELS], *cl, *cll;
1320  TBaseClass *base, *cinherit;
1321  TText *ptext = 0;
1322  TString opt=option;
1323  Double_t x,y,dy,y1,v1,v2,dv;
1324  Int_t nd,nf,nc,nkd,nkf,i,j;
1325  TPaveText *pt;
1326  Int_t maxlev = 4;
1327  if (opt.Contains("2")) maxlev = 2;
1328  if (opt.Contains("3")) maxlev = 3;
1329  if (opt.Contains("5")) maxlev = 5;
1330  if (opt.Contains("6")) maxlev = 6;
1331  if (opt.Contains("7")) maxlev = 7;
1332 
1333  // Clear and Set Pad range
1334  Double_t xpad = 20.5;
1335  Double_t ypad = 27.5;
1336  Clear();
1337  Range(0,0,xpad,ypad);
1338 
1339  // Find number of levels
1340  Int_t nlevel = 0;
1341  TClass *obj = (TClass*)classobj;
1342  clevel[nlevel] = obj;
1343  TList *lbase = obj->GetListOfBases();
1344  while(lbase) {
1345  base = (TBaseClass*)lbase->First();
1346  if (!base) break;
1347  if ( base->GetClassPointer() == 0) break;
1348  nlevel++;
1349  clevel[nlevel] = base->GetClassPointer();
1350  lbase = clevel[nlevel]->GetListOfBases();
1351  if (nlevel >= maxlev-1) break;
1352  }
1353  Int_t maxelem = 0;
1354  Int_t ncdraw = 0;
1355  Int_t ilevel, nelem;
1356  for (ilevel=nlevel;ilevel>=0;ilevel--) {
1357  cl = clevel[ilevel];
1358  nelem = cl->GetNdata() + cl->GetNmethods();
1359  if (nelem > maxelem) maxelem = nelem;
1360  nc = (nelem/50) + 1;
1361  ncdraw += nc;
1362  }
1363 
1364  Double_t tsizcm = 0.40;
1365  Double_t x1 = 0.25;
1366  Double_t x2 = 0;
1367  Double_t dx = 3.5;
1368  if (ncdraw > 4) {
1369  dx = dx - 0.42*Double_t(ncdraw-5);
1370  if (dx < 1.3) dx = 1.3;
1371  tsizcm = tsizcm - 0.03*Double_t(ncdraw-5);
1372  if (tsizcm < 0.27) tsizcm = 0.27;
1373  }
1374  Double_t tsiz = 1.2*tsizcm/ypad;
1375 
1376  // Now loop on levels
1377  for (ilevel=nlevel;ilevel>=0;ilevel--) {
1378  cl = clevel[ilevel];
1379  nelem = cl->GetNdata() + cl->GetNmethods();
1380  if (nelem > maxelem) maxelem = nelem;
1381  nc = (nelem/50) + 1;
1382  dy = 0.45;
1383  if (ilevel < nlevel) x1 = x2 + 0.5;
1384  x2 = x1 + nc*dx;
1385  v2 = ypad - 0.5;
1386  lbase = cl->GetListOfBases();
1387  cinherit = 0;
1388  if (lbase) cinherit = (TBaseClass*)lbase->First();
1389 
1390  do {
1391  nd = cl->GetNdata();
1392  nf = cl->GetNmethods() - 2; //do not show default constructor and destructor
1393  if (cl->GetListOfMethods()->FindObject("Dictionary")) {
1394  nf -= 6; // do not count the Dictionary/ClassDef functions
1395  }
1396  nkf= nf/nc +1;
1397  nkd= nd/nc +1;
1398  if (nd == 0) nkd=0;
1399  if (nf == 0) nkf=0;
1400  y1 = v2 - 0.7;
1401  v1 = y1 - Double_t(nkf+nkd+nc-1)*dy;
1402  dv = v2 - v1;
1403 
1404  // Create a new PaveText
1405  pt = new TPaveText(x1,v1,x2,v2);
1406  pt->SetBit(kCanDelete);
1407  pt->SetFillColor(19);
1408  pt->Draw();
1409  pt->SetTextColor(4);
1410  pt->SetTextFont(61);
1411  pt->SetTextAlign(12);
1412  pt->SetTextSize(tsiz);
1413  TBox *box = pt->AddBox(0,(y1+0.01-v1)/dv,0,(v2-0.01-v1)/dv);
1414  if (box) box->SetFillColor(17);
1415  pt->AddLine(0,(y1-v1)/dv,0,(y1-v1)/dv);
1416  TText *title = pt->AddText(0.5,(0.5*(y1+v2)-v1)/dv,(char*)cl->GetName());
1417  title->SetTextAlign(22);
1418  title->SetTextSize(0.6*(v2-y1)/ypad);
1419 
1420  // Draw data Members
1421  i = 0;
1422  x = 0.03;
1423  y = y1 + 0.5*dy;
1424  TDataMember *d;
1425  TIter nextd(cl->GetListOfDataMembers());
1426  while ((d = (TDataMember *) nextd())) {
1427  if (i >= nkd) { i = 1; y = y1 - 0.5*dy; x += 1/Double_t(nc); }
1428  else { i++; y -= dy; }
1429 
1430  // Take in account the room the array index will occupy
1431 
1432  Int_t dim = d->GetArrayDim();
1433  Int_t indx = 0;
1434  snprintf(dname,256,"%s",d->GetName());
1435  Int_t ldname = 0;
1436  while (indx < dim ){
1437  ldname = strlen(dname);
1438  snprintf(&dname[ldname],256-ldname,"[%d]",d->GetMaxIndex(indx));
1439  indx++;
1440  }
1441  pt->AddText(x,(y-v1)/dv,dname);
1442  }
1443 
1444  // Draw a separator line
1445  Double_t ysep;
1446  if (nd) {
1447  ysep = y1 - Double_t(nkd)*dy;
1448  pt->AddLine(0,(ysep-v1)/dv,0,(ysep-v1)/dv);
1449  ysep -= 0.5*dy;
1450  } else ysep = y1;
1451 
1452  // Draw Member Functions
1453  Int_t fcount = 0;
1454  i = 0;
1455  x = 0.03;
1456  y = ysep + 0.5*dy;
1457  TMethod *m;
1458  TIter nextm(cl->GetListOfMethods());
1459  while ((m = (TMethod *) nextm())) {
1460  if (
1461  !strcmp( m->GetName(), "Dictionary" ) ||
1462  !strcmp( m->GetName(), "Class_Version" ) ||
1463  !strcmp( m->GetName(), "DeclFileName" ) ||
1464  !strcmp( m->GetName(), "DeclFileLine" ) ||
1465  !strcmp( m->GetName(), "ImplFileName" ) ||
1466  !strcmp( m->GetName(), "ImplFileLine" )
1467  ) continue;
1468  fcount++;
1469  if (fcount > nf) break;
1470  if (i >= nkf) { i = 1; y = ysep - 0.5*dy; x += 1/Double_t(nc); }
1471  else { i++; y -= dy; }
1472 
1473  ptext = pt->AddText(x,(y-v1)/dv,m->GetName());
1474  // Check if method is overloaded in a derived class
1475  // If yes, Change the color of the text to blue
1476  for (j=ilevel-1;j>=0;j--) {
1477  if (cl == clevel[ilevel]) {
1478  if (clevel[j]->GetMethodAny((char*)m->GetName())) {
1479  ptext->SetTextColor(15);
1480  break;
1481  }
1482  }
1483  }
1484  }
1485 
1486  // Draw second inheritance classes for this class
1487  cll = 0;
1488  if (cinherit) {
1489  cinherit = (TBaseClass*)lbase->After(cinherit);
1490  if (cinherit) {
1491  cl = cinherit->GetClassPointer();
1492  cll = cl;
1493  v2 = v1 -0.4;
1494  dy = 0.35;
1495  }
1496  }
1497  } while (cll);
1498  }
1499  Update();
1500 }
1501 
1502 ////////////////////////////////////////////////////////////////////////////////
1503 /// Function called to draw a crosshair in the canvas
1504 ///
1505 /// Example:
1506 /// ~~~ {.cpp}
1507 /// Root > TFile f("hsimple.root");
1508 /// Root > hpxpy.Draw();
1509 /// Root > c1.SetCrosshair();
1510 /// ~~~
1511 /// When moving the mouse in the canvas, a crosshair is drawn
1512 ///
1513 /// - if the canvas fCrosshair = 1 , the crosshair spans the full canvas
1514 /// - if the canvas fCrosshair > 1 , the crosshair spans only the pad
1515 
1516 void TPad::DrawCrosshair()
1517 {
1518  if (gPad->GetEvent() == kMouseEnter) return;
1519 
1520  TPad *cpad = (TPad*)gPad;
1521  TCanvas *canvas = cpad->GetCanvas();
1522  canvas->FeedbackMode(kTRUE);
1523 
1524  //erase old position and draw a line at current position
1525  Int_t pxmin,pxmax,pymin,pymax,pxold,pyold,px,py;
1526  pxold = fCrosshairPos%10000;
1527  pyold = fCrosshairPos/10000;
1528  px = cpad->GetEventX();
1529  py = cpad->GetEventY()+1;
1530  if (canvas->GetCrosshair() > 1) { //crosshair only in the current pad
1531  pxmin = cpad->XtoAbsPixel(fX1);
1532  pxmax = cpad->XtoAbsPixel(fX2);
1533  pymin = cpad->YtoAbsPixel(fY1);
1534  pymax = cpad->YtoAbsPixel(fY2);
1535  } else { //default; crosshair spans the full canvas
1536  pxmin = 0;
1537  pxmax = canvas->GetWw();
1538  pymin = 0;
1539  pymax = cpad->GetWh();
1540  }
1541  if(pxold) gVirtualX->DrawLine(pxold,pymin,pxold,pymax);
1542  if(pyold) gVirtualX->DrawLine(pxmin,pyold,pxmax,pyold);
1543  if (cpad->GetEvent() == kButton1Down ||
1544  cpad->GetEvent() == kButton1Up ||
1545  cpad->GetEvent() == kMouseLeave) {
1546  fCrosshairPos = 0;
1547  return;
1548  }
1549  gVirtualX->DrawLine(px,pymin,px,pymax);
1550  gVirtualX->DrawLine(pxmin,py,pxmax,py);
1551  fCrosshairPos = px + 10000*py;
1552 }
1553 
1554 ////////////////////////////////////////////////////////////////////////////////
1555 /// Draw an empty pad frame with X and Y axis.
1556 ///
1557 /// \return The pointer to the histogram used to draw the frame.
1558 ///
1559 /// \param[in] xmin X axis lower limit
1560 /// \param[in] xmax X axis upper limit
1561 /// \param[in] ymin Y axis lower limit
1562 /// \param[in] ymax Y axis upper limit
1563 /// \param[in] title Pad title.If title is of the form "stringt;stringx;stringy"
1564 /// the pad title is set to stringt, the x axis title to
1565 /// stringx, the y axis title to stringy.
1566 ///
1567 /// #### Example:
1568 ///
1569 /// Begin_Macro(source)
1570 /// {
1571 /// auto c = new TCanvas("c","c",200,10,500,300);
1572 ///
1573 /// const Int_t n = 50;
1574 /// auto g = new TGraph();
1575 /// for (Int_t i=0;i<n;i++) g->SetPoint(i,i*0.1,100*sin(i*0.1+0.2));
1576 ///
1577 /// auto frame = c->DrawFrame(0, -110, 2, 110);
1578 /// frame->GetXaxis()->SetTitle("X axis");
1579 ///
1580 /// g->Draw("L*");
1581 /// }
1582 /// End_Macro
1583 
1584 TH1F *TPad::DrawFrame(Double_t xmin, Double_t ymin, Double_t xmax, Double_t ymax, const char *title)
1585 {
1586  if (!IsEditable()) return 0;
1587  TPad *padsav = (TPad*)gPad;
1588  if (this != padsav) {
1589  Warning("DrawFrame","Must be called for the current pad only");
1590  return padsav->DrawFrame(xmin,ymin,xmax,ymax,title);
1591  }
1592 
1593  cd();
1594 
1595  TH1F *hframe = (TH1F*)FindObject("hframe");
1596  if (hframe) delete hframe;
1597  Int_t nbins = 1000;
1598  //if log scale in X, use variable bin size linear with log(x)
1599  //this gives a better precision when zooming on the axis
1600  if (fLogx && xmin > 0 && xmax > xmin) {
1601  Double_t xminl = TMath::Log(xmin);
1602  Double_t xmaxl = TMath::Log(xmax);
1603  Double_t dx = (xmaxl-xminl)/nbins;
1604  Double_t *xbins = new Double_t[nbins+1];
1605  xbins[0] = xmin;
1606  for (Int_t i=1;i<=nbins;i++) {
1607  xbins[i] = TMath::Exp(xminl+i*dx);
1608  }
1609  hframe = new TH1F("hframe",title,nbins,xbins);
1610  delete [] xbins;
1611  } else {
1612  hframe = new TH1F("hframe",title,nbins,xmin,xmax);
1613  }
1614  hframe->SetBit(TH1::kNoStats);
1615  hframe->SetBit(kCanDelete);
1616  hframe->SetMinimum(ymin);
1617  hframe->SetMaximum(ymax);
1618  hframe->GetYaxis()->SetLimits(ymin,ymax);
1619  hframe->SetDirectory(0);
1620  hframe->Draw(" ");
1621  Update();
1622  if (padsav) padsav->cd();
1623  return hframe;
1624 }
1625 
1626 ////////////////////////////////////////////////////////////////////////////////
1627 /// Static function to Display Color Table in a pad.
1628 
1629 void TPad::DrawColorTable()
1630 {
1631  Int_t i, j;
1632  Int_t color;
1633  Double_t xlow, ylow, xup, yup, hs, ws;
1634  Double_t x1, y1, x2, y2;
1635  x1 = y1 = 0;
1636  x2 = y2 = 20;
1637 
1638  gPad->SetFillColor(0);
1639  gPad->Clear();
1640  gPad->Range(x1,y1,x2,y2);
1641 
1642  TText *text = new TText(0,0,"");
1643  text->SetTextFont(61);
1644  text->SetTextSize(0.07);
1645  text->SetTextAlign(22);
1646 
1647  TBox *box = new TBox();
1648 
1649  // Draw color table boxes.
1650  hs = (y2-y1)/Double_t(5);
1651  ws = (x2-x1)/Double_t(10);
1652  for (i=0;i<10;i++) {
1653  xlow = x1 + ws*(Double_t(i)+0.1);
1654  xup = x1 + ws*(Double_t(i)+0.9);
1655  for (j=0;j<5;j++) {
1656  ylow = y1 + hs*(Double_t(j)+0.1);
1657  yup = y1 + hs*(Double_t(j)+0.9);
1658  color = 10*j + i;
1659  box->SetFillStyle(1001);
1660  box->SetFillColor(color);
1661  box->DrawBox(xlow, ylow, xup, yup);
1662  box->SetFillStyle(0);
1663  box->SetLineColor(1);
1664  box->DrawBox(xlow, ylow, xup, yup);
1665  if (color == 1) text->SetTextColor(0);
1666  else text->SetTextColor(1);
1667  text->DrawText(0.5*(xlow+xup), 0.5*(ylow+yup), Form("%d",color));
1668  }
1669  }
1670 }
1671 
1672 ////////////////////////////////////////////////////////////////////////////////
1673 /// Execute action corresponding to one event.
1674 ///
1675 /// This member function is called when a TPad object is clicked.
1676 ///
1677 /// If the mouse is clicked in one of the 4 corners of the pad (pA,pB,pC,pD)
1678 /// the pad is resized with the rubber rectangle.
1679 ///
1680 /// If the mouse is clicked inside the pad, the pad is moved.
1681 ///
1682 /// If the mouse is clicked on the 4 edges (pL,pR,pTop,pBot), the pad is scaled
1683 /// parallel to this edge.
1684 ///
1685 /// \image html gpad_pad4.png
1686 ///
1687 /// Note that this function duplicates on purpose the functionality
1688 /// already implemented in TBox::ExecuteEvent.
1689 /// If somebody modifies this function, may be similar changes should also
1690 /// be applied to TBox::ExecuteEvent.
1691 
1692 void TPad::ExecuteEvent(Int_t event, Int_t px, Int_t py)
1693 {
1694  const Int_t kMaxDiff = 5;
1695  const Int_t kMinSize = 20;
1696  static Int_t pxorg, pyorg;
1697  static Int_t px1, px2, py1, py2, pxl, pyl, pxt, pyt, pxold, pyold;
1698  static Int_t px1p, px2p, py1p, py2p, pxlp, pylp, pxtp, pytp;
1699  static Bool_t pA, pB, pC, pD, pTop, pL, pR, pBot, pINSIDE;
1700  Int_t wx, wy;
1701  Bool_t opaque = OpaqueMoving();
1702  Bool_t ropaque = OpaqueResizing();
1703  Bool_t fixedr = HasFixedAspectRatio();
1704 
1705  if (!IsEditable() && event != kMouseEnter) return;
1706  TVirtualPad *parent = GetMother();
1707  if (!parent->IsEditable()) return;
1708 
1709  HideToolTip(event);
1710 
1711  if (fXlowNDC < 0 && event != kButton1Down) return;
1712  if (fYlowNDC < 0 && event != kButton1Down) return;
1713 
1714  // keep old mouse position
1715  if (event == kButton1Down) {
1716  pxorg = px;
1717  pyorg = py;
1718  }
1719 
1720  Int_t newcode = gROOT->GetEditorMode();
1721  if (newcode)
1722  pA = pB = pC = pD = pTop = pL = pR = pBot = pINSIDE = kFALSE;
1723  switch (newcode) {
1724  case kPad:
1725  TCreatePrimitives::Pad(event,px,py,0);
1726  break;
1727  case kMarker:
1728  case kText:
1729  TCreatePrimitives::Text(event,px,py,newcode);
1730  break;
1731  case kLine:
1732  TCreatePrimitives::Line(event,px,py,kLine);
1733  break;
1734  case kArrow:
1735  TCreatePrimitives::Line(event,px,py,kArrow);
1736  break;
1737  case kCurlyLine:
1738  TCreatePrimitives::Line(event,px,py,kCurlyLine);
1739  break;
1740  case kCurlyArc:
1741  TCreatePrimitives::Line(event,px,py,kCurlyArc);
1742  break;
1743  case kPolyLine:
1744  TCreatePrimitives::PolyLine(event,px,py,kPolyLine);
1745  break;
1746  case kCutG:
1747  TCreatePrimitives::PolyLine(event,px,py,kCutG);
1748  break;
1749  case kArc:
1750  TCreatePrimitives::Ellipse(event,px,py,kArc);
1751  break;
1752  case kEllipse:
1753  TCreatePrimitives::Ellipse(event,px,py,kEllipse);
1754  break;
1755  case kButton:
1756  case kPave:
1757  case kPaveLabel:
1758  case kPaveText:
1759  case kPavesText:
1760  case kDiamond:
1761  TCreatePrimitives::Pave(event,px,py,newcode);
1762  return;
1763  default:
1764  break;
1765  }
1766  if (newcode) return;
1767 
1768  switch (event) {
1769 
1770  case kMouseEnter:
1771  if (fTip)
1772  ResetToolTip(fTip);
1773  break;
1774 
1775  case kArrowKeyPress:
1776  case kButton1Down:
1777 
1778  fXUpNDC = fXlowNDC + fWNDC;
1779  fYUpNDC = fYlowNDC + fHNDC;
1780 
1781  GetPainter()->SetLineColor(-1);
1782  TAttLine::Modify(); //Change line attributes only if necessary
1783  if (GetFillColor())
1784  GetPainter()->SetLineColor(GetFillColor());
1785  else
1786  GetPainter()->SetLineColor(1);
1787  GetPainter()->SetLineWidth(2);
1788 
1789  // No break !!!
1790 
1791  case kMouseMotion:
1792 
1793  px1 = XtoAbsPixel(fX1);
1794  py1 = YtoAbsPixel(fY1);
1795  px2 = XtoAbsPixel(fX2);
1796  py2 = YtoAbsPixel(fY2);
1797 
1798  if (px1 < px2) {
1799  pxl = px1;
1800  pxt = px2;
1801  } else {
1802  pxl = px2;
1803  pxt = px1;
1804  }
1805  if (py1 < py2) {
1806  pyl = py1;
1807  pyt = py2;
1808  } else {
1809  pyl = py2;
1810  pyt = py1;
1811  }
1812 
1813  px1p = parent->XtoAbsPixel(parent->GetX1()) + parent->GetBorderSize();
1814  py1p = parent->YtoAbsPixel(parent->GetY1()) - parent->GetBorderSize();
1815  px2p = parent->XtoAbsPixel(parent->GetX2()) - parent->GetBorderSize();
1816  py2p = parent->YtoAbsPixel(parent->GetY2()) + parent->GetBorderSize();
1817 
1818  if (px1p < px2p) {
1819  pxlp = px1p;
1820  pxtp = px2p;
1821  } else {
1822  pxlp = px2p;
1823  pxtp = px1p;
1824  }
1825  if (py1p < py2p) {
1826  pylp = py1p;
1827  pytp = py2p;
1828  } else {
1829  pylp = py2p;
1830  pytp = py1p;
1831  }
1832 
1833  pA = pB = pC = pD = pTop = pL = pR = pBot = pINSIDE = kFALSE;
1834 
1835  // case pA
1836  if (TMath::Abs(px - pxl) <= kMaxDiff && TMath::Abs(py - pyl) <= kMaxDiff) {
1837  pxold = pxl; pyold = pyl; pA = kTRUE;
1838  SetCursor(kTopLeft);
1839  }
1840  // case pB
1841  if (TMath::Abs(px - pxt) <= kMaxDiff && TMath::Abs(py - pyl) <= kMaxDiff) {
1842  pxold = pxt; pyold = pyl; pB = kTRUE;
1843  SetCursor(kTopRight);
1844  }
1845  // case pC
1846  if (TMath::Abs(px - pxt) <= kMaxDiff && TMath::Abs(py - pyt) <= kMaxDiff) {
1847  pxold = pxt; pyold = pyt; pC = kTRUE;
1848  SetCursor(kBottomRight);
1849  }
1850  // case pD
1851  if (TMath::Abs(px - pxl) <= kMaxDiff && TMath::Abs(py - pyt) <= kMaxDiff) {
1852  pxold = pxl; pyold = pyt; pD = kTRUE;
1853  SetCursor(kBottomLeft);
1854  }
1855 
1856  if ((px > pxl+kMaxDiff && px < pxt-kMaxDiff) &&
1857  TMath::Abs(py - pyl) < kMaxDiff) { // top edge
1858  pxold = pxl; pyold = pyl; pTop = kTRUE;
1859  SetCursor(kTopSide);
1860  }
1861 
1862  if ((px > pxl+kMaxDiff && px < pxt-kMaxDiff) &&
1863  TMath::Abs(py - pyt) < kMaxDiff) { // bottom edge
1864  pxold = pxt; pyold = pyt; pBot = kTRUE;
1865  SetCursor(kBottomSide);
1866  }
1867 
1868  if ((py > pyl+kMaxDiff && py < pyt-kMaxDiff) &&
1869  TMath::Abs(px - pxl) < kMaxDiff) { // left edge
1870  pxold = pxl; pyold = pyl; pL = kTRUE;
1871  SetCursor(kLeftSide);
1872  }
1873 
1874  if ((py > pyl+kMaxDiff && py < pyt-kMaxDiff) &&
1875  TMath::Abs(px - pxt) < kMaxDiff) { // right edge
1876  pxold = pxt; pyold = pyt; pR = kTRUE;
1877  SetCursor(kRightSide);
1878  }
1879 
1880  if ((px > pxl+kMaxDiff && px < pxt-kMaxDiff) &&
1881  (py > pyl+kMaxDiff && py < pyt-kMaxDiff)) { // inside box
1882  pxold = px; pyold = py; pINSIDE = kTRUE;
1883  if (event == kButton1Down)
1884  SetCursor(kMove);
1885  else
1886  SetCursor(kCross);
1887  }
1888 
1889  fResizing = kFALSE;
1890  if (pA || pB || pC || pD || pTop || pL || pR || pBot)
1891  fResizing = kTRUE;
1892 
1893  if (!pA && !pB && !pC && !pD && !pTop && !pL && !pR && !pBot && !pINSIDE)
1894  SetCursor(kCross);
1895 
1896  break;
1897 
1898  case kArrowKeyRelease:
1899  case kButton1Motion:
1900 
1901  if (TestBit(kCannotMove)) break;
1902  wx = wy = 0;
1903 
1904  if (pA) {
1905  if (!ropaque) gVirtualX->DrawBox(pxold, pyt, pxt, pyold, TVirtualX::kHollow);
1906  if (px > pxt-kMinSize) { px = pxt-kMinSize; wx = px; }
1907  if (py > pyt-kMinSize) { py = pyt-kMinSize; wy = py; }
1908  if (px < pxlp) { px = pxlp; wx = px; }
1909  if (py < pylp) { py = pylp; wy = py; }
1910  if (fixedr) {
1911  Double_t dy = Double_t(TMath::Abs(pxt-px))/parent->UtoPixel(1.) /
1912  fAspectRatio;
1913  Int_t npy2 = pyt - TMath::Abs(parent->VtoAbsPixel(dy) -
1914  parent->VtoAbsPixel(0));
1915  if (npy2 < pylp) {
1916  px = pxold;
1917  py = pyold;
1918  } else
1919  py = npy2;
1920 
1921  wx = wy = 0;
1922  }
1923  if (!ropaque) gVirtualX->DrawBox(px, pyt, pxt, py, TVirtualX::kHollow);
1924  }
1925  if (pB) {
1926  if (!ropaque) gVirtualX->DrawBox(pxl , pyt, pxold, pyold, TVirtualX::kHollow);
1927  if (px < pxl+kMinSize) { px = pxl+kMinSize; wx = px; }
1928  if (py > pyt-kMinSize) { py = pyt-kMinSize; wy = py; }
1929  if (px > pxtp) { px = pxtp; wx = px; }
1930  if (py < pylp) { py = pylp; wy = py; }
1931  if (fixedr) {
1932  Double_t dy = Double_t(TMath::Abs(pxl-px))/parent->UtoPixel(1.) /
1933  fAspectRatio;
1934  Int_t npy2 = pyt - TMath::Abs(parent->VtoAbsPixel(dy) -
1935  parent->VtoAbsPixel(0));
1936  if (npy2 < pylp) {
1937  px = pxold;
1938  py = pyold;
1939  } else
1940  py = npy2;
1941 
1942  wx = wy = 0;
1943  }
1944  if (!ropaque) gVirtualX->DrawBox(pxl , pyt, px , py, TVirtualX::kHollow);
1945  }
1946  if (pC) {
1947  if (!ropaque) gVirtualX->DrawBox(pxl , pyl, pxold, pyold, TVirtualX::kHollow);
1948  if (px < pxl+kMinSize) { px = pxl+kMinSize; wx = px; }
1949  if (py < pyl+kMinSize) { py = pyl+kMinSize; wy = py; }
1950  if (px > pxtp) { px = pxtp; wx = px; }
1951  if (py > pytp) { py = pytp; wy = py; }
1952  if (fixedr) {
1953  Double_t dy = Double_t(TMath::Abs(pxl-px))/parent->UtoPixel(1.) /
1954  fAspectRatio;
1955  Int_t npy2 = pyl + TMath::Abs(parent->VtoAbsPixel(dy) -
1956  parent->VtoAbsPixel(0));
1957  if (npy2 > pytp) {
1958  px = pxold;
1959  py = pyold;
1960  } else
1961  py = npy2;
1962 
1963  wx = wy = 0;
1964  }
1965  if (!ropaque) gVirtualX->DrawBox(pxl, pyl, px, py, TVirtualX::kHollow);
1966  }
1967  if (pD) {
1968  if (!ropaque) gVirtualX->DrawBox(pxold, pyold, pxt, pyl, TVirtualX::kHollow);
1969  if (px > pxt-kMinSize) { px = pxt-kMinSize; wx = px; }
1970  if (py < pyl+kMinSize) { py = pyl+kMinSize; wy = py; }
1971  if (px < pxlp) { px = pxlp; wx = px; }
1972  if (py > pytp) { py = pytp; wy = py; }
1973  if (fixedr) {
1974  Double_t dy = Double_t(TMath::Abs(pxt-px))/parent->UtoPixel(1.) /
1975  fAspectRatio;
1976  Int_t npy2 = pyl + TMath::Abs(parent->VtoAbsPixel(dy) -
1977  parent->VtoAbsPixel(0));
1978  if (npy2 > pytp) {
1979  px = pxold;
1980  py = pyold;
1981  } else
1982  py = npy2;
1983 
1984  wx = wy = 0;
1985  }
1986  if (!ropaque) gVirtualX->DrawBox(px, py, pxt, pyl, TVirtualX::kHollow);
1987  }
1988  if (pTop) {
1989  if (!ropaque) gVirtualX->DrawBox(px1, py1, px2, py2, TVirtualX::kHollow);
1990  py2 += py - pyold;
1991  if (py2 > py1-kMinSize) { py2 = py1-kMinSize; wy = py2; }
1992  if (py2 < py2p) { py2 = py2p; wy = py2; }
1993  if (fixedr) {
1994  Double_t dx = Double_t(TMath::Abs(py2-py1))/parent->VtoPixel(0) *
1995  fAspectRatio;
1996  Int_t npx2 = px1 + parent->UtoPixel(dx);
1997  if (npx2 > px2p)
1998  py2 -= py - pyold;
1999  else
2000  px2 = npx2;
2001  }
2002  if (!ropaque) gVirtualX->DrawBox(px1, py1, px2, py2, TVirtualX::kHollow);
2003  }
2004  if (pBot) {
2005  if (!ropaque) gVirtualX->DrawBox(px1, py1, px2, py2, TVirtualX::kHollow);
2006  py1 += py - pyold;
2007  if (py1 < py2+kMinSize) { py1 = py2+kMinSize; wy = py1; }
2008  if (py1 > py1p) { py1 = py1p; wy = py1; }
2009  if (fixedr) {
2010  Double_t dx = Double_t(TMath::Abs(py2-py1))/parent->VtoPixel(0) *
2011  fAspectRatio;
2012  Int_t npx2 = px1 + parent->UtoPixel(dx);
2013  if (npx2 > px2p)
2014  py1 -= py - pyold;
2015  else
2016  px2 = npx2;
2017  }
2018  if (!ropaque) gVirtualX->DrawBox(px1, py1, px2, py2, TVirtualX::kHollow);
2019  }
2020  if (pL) {
2021  if (!ropaque) gVirtualX->DrawBox(px1, py1, px2, py2, TVirtualX::kHollow);
2022  px1 += px - pxold;
2023  if (px1 > px2-kMinSize) { px1 = px2-kMinSize; wx = px1; }
2024  if (px1 < px1p) { px1 = px1p; wx = px1; }
2025  if (fixedr) {
2026  Double_t dy = Double_t(TMath::Abs(px2-px1))/parent->UtoPixel(1.) /
2027  fAspectRatio;
2028  Int_t npy2 = py1 - TMath::Abs(parent->VtoAbsPixel(dy) -
2029  parent->VtoAbsPixel(0));
2030  if (npy2 < py2p)
2031  px1 -= px - pxold;
2032  else
2033  py2 = npy2;
2034  }
2035  if (!ropaque) gVirtualX->DrawBox(px1, py1, px2, py2, TVirtualX::kHollow);
2036  }
2037  if (pR) {
2038  if (!ropaque) gVirtualX->DrawBox(px1, py1, px2, py2, TVirtualX::kHollow);
2039  px2 += px - pxold;
2040  if (px2 < px1+kMinSize) { px2 = px1+kMinSize; wx = px2; }
2041  if (px2 > px2p) { px2 = px2p; wx = px2; }
2042  if (fixedr) {
2043  Double_t dy = Double_t(TMath::Abs(px2-px1))/parent->UtoPixel(1.) /
2044  fAspectRatio;
2045  Int_t npy2 = py1 - TMath::Abs(parent->VtoAbsPixel(dy) -
2046  parent->VtoAbsPixel(0));
2047  if (npy2 < py2p)
2048  px2 -= px - pxold;
2049  else
2050  py2 = npy2;
2051  }
2052  if (!ropaque) gVirtualX->DrawBox(px1, py1, px2, py2, TVirtualX::kHollow);
2053  }
2054  if (pINSIDE) {
2055  if (!opaque) gVirtualX->DrawBox(px1, py1, px2, py2, TVirtualX::kHollow); // draw the old box
2056  Int_t dx = px - pxold;
2057  Int_t dy = py - pyold;
2058  px1 += dx; py1 += dy; px2 += dx; py2 += dy;
2059  if (px1 < px1p) { dx = px1p - px1; px1 += dx; px2 += dx; wx = px+dx; }
2060  if (px2 > px2p) { dx = px2 - px2p; px1 -= dx; px2 -= dx; wx = px-dx; }
2061  if (py1 > py1p) { dy = py1 - py1p; py1 -= dy; py2 -= dy; wy = py-dy; }
2062  if (py2 < py2p) { dy = py2p - py2; py1 += dy; py2 += dy; wy = py+dy; }
2063  if (!opaque) gVirtualX->DrawBox(px1, py1, px2, py2, TVirtualX::kHollow); // draw the new box
2064  }
2065 
2066  if (wx || wy) {
2067  if (wx) px = wx;
2068  if (wy) py = wy;
2069  gVirtualX->Warp(px, py);
2070  }
2071 
2072  pxold = px;
2073  pyold = py;
2074 
2075  Double_t x1, y1, x2, y2;
2076  x1 = x2 = y1 = y2 = 0;
2077 
2078  if ((!fResizing && opaque) || (fResizing && ropaque)) {
2079  if (pA) {
2080  x1 = AbsPixeltoX(pxold);
2081  y1 = AbsPixeltoY(pyt);
2082  x2 = AbsPixeltoX(pxt);
2083  y2 = AbsPixeltoY(pyold);
2084  }
2085  if (pB) {
2086  x1 = AbsPixeltoX(pxl);
2087  y1 = AbsPixeltoY(pyt);
2088  x2 = AbsPixeltoX(pxold);
2089  y2 = AbsPixeltoY(pyold);
2090  }
2091  if (pC) {
2092  x1 = AbsPixeltoX(pxl);
2093  y1 = AbsPixeltoY(pyold);
2094  x2 = AbsPixeltoX(pxold);
2095  y2 = AbsPixeltoY(pyl);
2096  }
2097  if (pD) {
2098  x1 = AbsPixeltoX(pxold);
2099  y1 = AbsPixeltoY(pyold);
2100  x2 = AbsPixeltoX(pxt);
2101  y2 = AbsPixeltoY(pyl);
2102  }
2103  if (pTop || pBot || pL || pR || pINSIDE) {
2104  x1 = AbsPixeltoX(px1);
2105  y1 = AbsPixeltoY(py1);
2106  x2 = AbsPixeltoX(px2);
2107  y2 = AbsPixeltoY(py2);
2108  }
2109 
2110  if (px != pxorg || py != pyorg) {
2111 
2112  // Get parent corners pixels coordinates
2113  Int_t parentpx1 = fMother->XtoAbsPixel(parent->GetX1());
2114  Int_t parentpx2 = fMother->XtoAbsPixel(parent->GetX2());
2115  Int_t parentpy1 = fMother->YtoAbsPixel(parent->GetY1());
2116  Int_t parentpy2 = fMother->YtoAbsPixel(parent->GetY2());
2117 
2118  // Get pad new corners pixels coordinates
2119  Int_t apx1 = XtoAbsPixel(x1); if (apx1 < parentpx1) {apx1 = parentpx1; }
2120  Int_t apx2 = XtoAbsPixel(x2); if (apx2 > parentpx2) {apx2 = parentpx2; }
2121  Int_t apy1 = YtoAbsPixel(y1); if (apy1 > parentpy1) {apy1 = parentpy1; }
2122  Int_t apy2 = YtoAbsPixel(y2); if (apy2 < parentpy2) {apy2 = parentpy2; }
2123 
2124  // Compute new pad positions in the NDC space of parent
2125  fXlowNDC = Double_t(apx1 - parentpx1)/Double_t(parentpx2 - parentpx1);
2126  fYlowNDC = Double_t(apy1 - parentpy1)/Double_t(parentpy2 - parentpy1);
2127  fWNDC = Double_t(apx2 - apx1)/Double_t(parentpx2 - parentpx1);
2128  fHNDC = Double_t(apy2 - apy1)/Double_t(parentpy2 - parentpy1);
2129  }
2130 
2131  // Reset pad parameters and recompute conversion coefficients
2132  ResizePad();
2133 
2134  if (pINSIDE) gPad->ShowGuidelines(this, event);
2135  if (pTop) gPad->ShowGuidelines(this, event, 't', true);
2136  if (pBot) gPad->ShowGuidelines(this, event, 'b', true);
2137  if (pL) gPad->ShowGuidelines(this, event, 'l', true);
2138  if (pR) gPad->ShowGuidelines(this, event, 'r', true);
2139  if (pA) gPad->ShowGuidelines(this, event, '1', true);
2140  if (pB) gPad->ShowGuidelines(this, event, '2', true);
2141  if (pC) gPad->ShowGuidelines(this, event, '3', true);
2142  if (pD) gPad->ShowGuidelines(this, event, '4', true);
2143 
2144  Modified(kTRUE);
2145  }
2146 
2147  break;
2148 
2149  case kButton1Up:
2150 
2151  if (gROOT->IsEscaped()) {
2152  gROOT->SetEscape(kFALSE);
2153  break;
2154  }
2155 
2156  if (opaque||ropaque) {
2157  ShowGuidelines(this, event);
2158  } else {
2159  x1 = x2 = y1 = y2 = 0;
2160 
2161  if (pA) {
2162  x1 = AbsPixeltoX(pxold);
2163  y1 = AbsPixeltoY(pyt);
2164  x2 = AbsPixeltoX(pxt);
2165  y2 = AbsPixeltoY(pyold);
2166  }
2167  if (pB) {
2168  x1 = AbsPixeltoX(pxl);
2169  y1 = AbsPixeltoY(pyt);
2170  x2 = AbsPixeltoX(pxold);
2171  y2 = AbsPixeltoY(pyold);
2172  }
2173  if (pC) {
2174  x1 = AbsPixeltoX(pxl);
2175  y1 = AbsPixeltoY(pyold);
2176  x2 = AbsPixeltoX(pxold);
2177  y2 = AbsPixeltoY(pyl);
2178  }
2179  if (pD) {
2180  x1 = AbsPixeltoX(pxold);
2181  y1 = AbsPixeltoY(pyold);
2182  x2 = AbsPixeltoX(pxt);
2183  y2 = AbsPixeltoY(pyl);
2184  }
2185  if (pTop || pBot || pL || pR || pINSIDE) {
2186  x1 = AbsPixeltoX(px1);
2187  y1 = AbsPixeltoY(py1);
2188  x2 = AbsPixeltoX(px2);
2189  y2 = AbsPixeltoY(py2);
2190  }
2191 
2192  if (pA || pB || pC || pD || pTop || pL || pR || pBot)
2193  Modified(kTRUE);
2194 
2195  gVirtualX->SetLineColor(-1);
2196  gVirtualX->SetLineWidth(-1);
2197 
2198  if (px != pxorg || py != pyorg) {
2199 
2200  // Get parent corners pixels coordinates
2201  Int_t parentpx1 = fMother->XtoAbsPixel(parent->GetX1());
2202  Int_t parentpx2 = fMother->XtoAbsPixel(parent->GetX2());
2203  Int_t parentpy1 = fMother->YtoAbsPixel(parent->GetY1());
2204  Int_t parentpy2 = fMother->YtoAbsPixel(parent->GetY2());
2205 
2206  // Get pad new corners pixels coordinates
2207  Int_t apx1 = XtoAbsPixel(x1); if (apx1 < parentpx1) {apx1 = parentpx1; }
2208  Int_t apx2 = XtoAbsPixel(x2); if (apx2 > parentpx2) {apx2 = parentpx2; }
2209  Int_t apy1 = YtoAbsPixel(y1); if (apy1 > parentpy1) {apy1 = parentpy1; }
2210  Int_t apy2 = YtoAbsPixel(y2); if (apy2 < parentpy2) {apy2 = parentpy2; }
2211 
2212  // Compute new pad positions in the NDC space of parent
2213  fXlowNDC = Double_t(apx1 - parentpx1)/Double_t(parentpx2 - parentpx1);
2214  fYlowNDC = Double_t(apy1 - parentpy1)/Double_t(parentpy2 - parentpy1);
2215  fWNDC = Double_t(apx2 - apx1)/Double_t(parentpx2 - parentpx1);
2216  fHNDC = Double_t(apy2 - apy1)/Double_t(parentpy2 - parentpy1);
2217  }
2218 
2219  // Reset pad parameters and recompute conversion coefficients
2220  ResizePad();
2221 
2222 
2223  // emit signal
2224  RangeChanged();
2225  }
2226 
2227  break;
2228 
2229  case kButton1Locate:
2230 
2231  ExecuteEvent(kButton1Down, px, py);
2232 
2233  while (1) {
2234  px = py = 0;
2235  event = gVirtualX->RequestLocator(1, 1, px, py);
2236 
2237  ExecuteEvent(kButton1Motion, px, py);
2238 
2239  if (event != -1) { // button is released
2240  ExecuteEvent(kButton1Up, px, py);
2241  return;
2242  }
2243  }
2244 
2245  case kButton2Down:
2246 
2247  Pop();
2248  break;
2249 
2250  }
2251 }
2252 
2253 ////////////////////////////////////////////////////////////////////////////////
2254 /// Execute action corresponding to one event for a TAxis object
2255 /// (called by TAxis::ExecuteEvent.)
2256 /// This member function is called when an axis is clicked with the locator
2257 ///
2258 /// The axis range is set between the position where the mouse is pressed
2259 /// and the position where it is released.
2260 ///
2261 /// If the mouse position is outside the current axis range when it is released
2262 /// the axis is unzoomed with the corresponding proportions.
2263 ///
2264 /// Note that the mouse does not need to be in the pad or even canvas
2265 /// when it is released.
2266 
2267 void TPad::ExecuteEventAxis(Int_t event, Int_t px, Int_t py, TAxis *axis)
2268 {
2269  if (!IsEditable()) return;
2270 
2271  SetCursor(kHand);
2272 
2273  TView *view = GetView();
2274  static Int_t axisNumber;
2275  static Double_t ratio1, ratio2;
2276  static Int_t px1old, py1old, px2old, py2old;
2277  Int_t bin1, bin2, first, last;
2278  Double_t temp, xmin,xmax;
2279  Bool_t opaque = gPad->OpaqueMoving();
2280  static TBox *zoombox;
2281  Double_t zbx1=0,zbx2=0,zby1=0,zby2=0;
2282 
2283  // The CONT4 option, used to paint TH2, is a special case; it uses a 3D
2284  // drawing technique to paint a 2D plot.
2285  TString opt = axis->GetParent()->GetDrawOption();
2286  opt.ToLower();
2287  Bool_t kCont4 = kFALSE;
2288  if (strstr(opt,"cont4")) {
2289  view = 0;
2290  kCont4 = kTRUE;
2291  }
2292 
2293  switch (event) {
2294 
2295  case kButton1Down:
2296  axisNumber = 1;
2297  if (!strcmp(axis->GetName(),"xaxis")) {
2298  axisNumber = 1;
2299  if (!IsVertical()) axisNumber = 2;
2300  }
2301  if (!strcmp(axis->GetName(),"yaxis")) {
2302  axisNumber = 2;
2303  if (!IsVertical()) axisNumber = 1;
2304  }
2305  if (!strcmp(axis->GetName(),"zaxis")) {
2306  axisNumber = 3;
2307  }
2308  if (view) {
2309  view->GetDistancetoAxis(axisNumber, px, py, ratio1);
2310  } else {
2311  if (axisNumber == 1) {
2312  ratio1 = (AbsPixeltoX(px) - GetUxmin())/(GetUxmax() - GetUxmin());
2313  px1old = XtoAbsPixel(GetUxmin()+ratio1*(GetUxmax() - GetUxmin()));
2314  py1old = YtoAbsPixel(GetUymin());
2315  px2old = px1old;
2316  py2old = YtoAbsPixel(GetUymax());
2317  } else if (axisNumber == 2) {
2318  ratio1 = (AbsPixeltoY(py) - GetUymin())/(GetUymax() - GetUymin());
2319  py1old = YtoAbsPixel(GetUymin()+ratio1*(GetUymax() - GetUymin()));
2320  px1old = XtoAbsPixel(GetUxmin());
2321  px2old = XtoAbsPixel(GetUxmax());
2322  py2old = py1old;
2323  } else {
2324  ratio1 = (AbsPixeltoY(py) - GetUymin())/(GetUymax() - GetUymin());
2325  py1old = YtoAbsPixel(GetUymin()+ratio1*(GetUymax() - GetUymin()));
2326  px1old = XtoAbsPixel(GetUxmax());
2327  px2old = XtoAbsPixel(GetX2());
2328  py2old = py1old;
2329  }
2330  if (!opaque) {
2331  gVirtualX->DrawBox(px1old, py1old, px2old, py2old, TVirtualX::kHollow);
2332  } else {
2333  if (axisNumber == 1) {
2334  zbx1 = AbsPixeltoX(px1old);
2335  zbx2 = AbsPixeltoX(px2old);
2336  zby1 = GetUymin();
2337  zby2 = GetUymax();
2338  } else if (axisNumber == 2) {
2339  zbx1 = GetUxmin();
2340  zbx2 = GetUxmax();
2341  zby1 = AbsPixeltoY(py1old);
2342  zby2 = AbsPixeltoY(py2old);
2343  }
2344  if (GetLogx()) {
2345  zbx1 = TMath::Power(10,zbx1);
2346  zbx2 = TMath::Power(10,zbx2);
2347  }
2348  if (GetLogy()) {
2349  zby1 = TMath::Power(10,zby1);
2350  zby2 = TMath::Power(10,zby2);
2351  }
2352  zoombox = new TBox(zbx1, zby1, zbx2, zby2);
2353  Int_t ci = TColor::GetColor("#7d7dff");
2354  TColor *zoomcolor = gROOT->GetColor(ci);
2355  if (!TCanvas::SupportAlpha() || !zoomcolor) zoombox->SetFillStyle(3002);
2356  else zoomcolor->SetAlpha(0.5);
2357  zoombox->SetFillColor(ci);
2358  zoombox->Draw();
2359  gPad->Modified();
2360  gPad->Update();
2361  }
2362  }
2363  if (!opaque) gVirtualX->SetLineColor(-1);
2364  // No break !!!
2365 
2366  case kButton1Motion:
2367  if (view) {
2368  view->GetDistancetoAxis(axisNumber, px, py, ratio2);
2369  } else {
2370  if (!opaque) gVirtualX->DrawBox(px1old, py1old, px2old, py2old, TVirtualX::kHollow);
2371  if (axisNumber == 1) {
2372  ratio2 = (AbsPixeltoX(px) - GetUxmin())/(GetUxmax() - GetUxmin());
2373  px2old = XtoAbsPixel(GetUxmin()+ratio2*(GetUxmax() - GetUxmin()));
2374  } else {
2375  ratio2 = (AbsPixeltoY(py) - GetUymin())/(GetUymax() - GetUymin());
2376  py2old = YtoAbsPixel(GetUymin()+ratio2*(GetUymax() - GetUymin()));
2377  }
2378  if (!opaque) {
2379  gVirtualX->DrawBox(px1old, py1old, px2old, py2old, TVirtualX::kHollow);
2380  } else {
2381  if (axisNumber == 1) {
2382  zbx1 = AbsPixeltoX(px1old);
2383  zbx2 = AbsPixeltoX(px2old);
2384  zby1 = GetUymin();
2385  zby2 = GetUymax();
2386  } else if (axisNumber == 2) {
2387  zbx1 = GetUxmin();
2388  zbx2 = GetUxmax();
2389  zby1 = AbsPixeltoY(py1old);
2390  zby2 = AbsPixeltoY(py2old);
2391  }
2392  if (GetLogx()) {
2393  zbx1 = TMath::Power(10,zbx1);
2394  zbx2 = TMath::Power(10,zbx2);
2395  }
2396  if (GetLogy()) {
2397  zby1 = TMath::Power(10,zby1);
2398  zby2 = TMath::Power(10,zby2);
2399  }
2400  if (zoombox) {
2401  zoombox->SetX1(zbx1);
2402  zoombox->SetY1(zby1);
2403  zoombox->SetX2(zbx2);
2404  zoombox->SetY2(zby2);
2405  }
2406  gPad->Modified();
2407  gPad->Update();
2408  }
2409  }
2410  break;
2411 
2412  case kWheelUp:
2413  bin1 = axis->GetFirst()+1;
2414  bin2 = axis->GetLast()-1;
2415  bin1 = TMath::Max(bin1, 1);
2416  bin2 = TMath::Min(bin2, axis->GetNbins());
2417  if (bin2>bin1) {
2418  axis->SetRange(bin1,bin2);
2419  gPad->Modified();
2420  gPad->Update();
2421  }
2422  break;
2423 
2424  case kWheelDown:
2425  bin1 = axis->GetFirst()-1;
2426  bin2 = axis->GetLast()+1;
2427  bin1 = TMath::Max(bin1, 1);
2428  bin2 = TMath::Min(bin2, axis->GetNbins());
2429  if (bin2>bin1) {
2430  axis->SetRange(bin1,bin2);
2431  gPad->Modified();
2432  gPad->Update();
2433  }
2434  break;
2435 
2436  case kButton1Up:
2437  if (gROOT->IsEscaped()) {
2438  gROOT->SetEscape(kFALSE);
2439  if (opaque && zoombox) {
2440  zoombox->Delete();
2441  zoombox = 0;
2442  }
2443  break;
2444  }
2445 
2446  if (view) {
2447  view->GetDistancetoAxis(axisNumber, px, py, ratio2);
2448  if (ratio1 > ratio2) {
2449  temp = ratio1;
2450  ratio1 = ratio2;
2451  ratio2 = temp;
2452  }
2453  if (ratio2 - ratio1 > 0.05) {
2454  TH1 *hobj = (TH1*)axis->GetParent();
2455  if (axisNumber == 3 && hobj && hobj->GetDimension() != 3) {
2456  Float_t zmin = hobj->GetMinimum();
2457  Float_t zmax = hobj->GetMaximum();
2458  if(GetLogz()){
2459  if (zmin <= 0 && zmax > 0) zmin = TMath::Min((Double_t)1,
2460  (Double_t)0.001*zmax);
2461  zmin = TMath::Log10(zmin);
2462  zmax = TMath::Log10(zmax);
2463  }
2464  Float_t newmin = zmin + (zmax-zmin)*ratio1;
2465  Float_t newmax = zmin + (zmax-zmin)*ratio2;
2466  if(newmin < zmin)newmin = hobj->GetBinContent(hobj->GetMinimumBin());
2467  if(newmax > zmax)newmax = hobj->GetBinContent(hobj->GetMaximumBin());
2468  if(GetLogz()){
2469  newmin = TMath::Exp(2.302585092994*newmin);
2470  newmax = TMath::Exp(2.302585092994*newmax);
2471  }
2472  hobj->SetMinimum(newmin);
2473  hobj->SetMaximum(newmax);
2474  hobj->SetBit(TH1::kIsZoomed);
2475  } else {
2476  first = axis->GetFirst();
2477  last = axis->GetLast();
2478  bin1 = first + Int_t((last-first+1)*ratio1);
2479  bin2 = first + Int_t((last-first+1)*ratio2);
2480  bin1 = TMath::Max(bin1, 1);
2481  bin2 = TMath::Min(bin2, axis->GetNbins());
2482  axis->SetRange(bin1, bin2);
2483  }
2484  delete view;
2485  SetView(0);
2486  Modified(kTRUE);
2487  }
2488  } else {
2489  if (axisNumber == 1) {
2490  ratio2 = (AbsPixeltoX(px) - GetUxmin())/(GetUxmax() - GetUxmin());
2491  xmin = GetUxmin() +ratio1*(GetUxmax() - GetUxmin());
2492  xmax = GetUxmin() +ratio2*(GetUxmax() - GetUxmin());
2493  if (GetLogx() && !kCont4) {
2494  xmin = PadtoX(xmin);
2495  xmax = PadtoX(xmax);
2496  }
2497  } else if (axisNumber == 2) {
2498  ratio2 = (AbsPixeltoY(py) - GetUymin())/(GetUymax() - GetUymin());
2499  xmin = GetUymin() +ratio1*(GetUymax() - GetUymin());
2500  xmax = GetUymin() +ratio2*(GetUymax() - GetUymin());
2501  if (GetLogy() && !kCont4) {
2502  xmin = PadtoY(xmin);
2503  xmax = PadtoY(xmax);
2504  }
2505  } else {
2506  ratio2 = (AbsPixeltoY(py) - GetUymin())/(GetUymax() - GetUymin());
2507  xmin = ratio1;
2508  xmax = ratio2;
2509  }
2510  if (xmin > xmax) {
2511  temp = xmin;
2512  xmin = xmax;
2513  xmax = temp;
2514  temp = ratio1;
2515  ratio1 = ratio2;
2516  ratio2 = temp;
2517  }
2518 
2519  // xmin and xmax need to be adjusted in case of CONT4.
2520  if (kCont4) {
2521  Double_t low = axis->GetBinLowEdge(axis->GetFirst());
2522  Double_t up = axis->GetBinUpEdge(axis->GetLast());
2523  Double_t xmi = GetUxmin();
2524  Double_t xma = GetUxmax();
2525  xmin = ((xmin-xmi)/(xma-xmi))*(up-low)+low;
2526  xmax = ((xmax-xmi)/(xma-xmi))*(up-low)+low;
2527  }
2528 
2529  if (!strcmp(axis->GetName(),"xaxis")) axisNumber = 1;
2530  if (!strcmp(axis->GetName(),"yaxis")) axisNumber = 2;
2531  if (ratio2 - ratio1 > 0.05) {
2532  //update object owning this axis
2533  TH1 *hobj1 = (TH1*)axis->GetParent();
2534  bin1 = axis->FindFixBin(xmin);
2535  bin2 = axis->FindFixBin(xmax);
2536  bin1 = TMath::Max(bin1, 1);
2537  bin2 = TMath::Min(bin2, axis->GetNbins());
2538  if (axisNumber == 1) axis->SetRange(bin1,bin2);
2539  if (axisNumber == 2 && hobj1) {
2540  if (hobj1->GetDimension() == 1) {
2541  if (hobj1->GetNormFactor() != 0) {
2542  Double_t norm = hobj1->GetSumOfWeights()/hobj1->GetNormFactor();
2543  xmin *= norm;
2544  xmax *= norm;
2545  }
2546  hobj1->SetMinimum(xmin);
2547  hobj1->SetMaximum(xmax);
2548  hobj1->SetBit(TH1::kIsZoomed);
2549  } else {
2550  axis->SetRange(bin1,bin2);
2551  }
2552  }
2553  //update all histograms in the pad
2554  TIter next(GetListOfPrimitives());
2555  TObject *obj;
2556  while ((obj= next())) {
2557  if (!obj->InheritsFrom(TH1::Class())) continue;
2558  TH1 *hobj = (TH1*)obj;
2559  if (hobj == hobj1) continue;
2560  bin1 = hobj->GetXaxis()->FindFixBin(xmin);
2561  bin2 = hobj->GetXaxis()->FindFixBin(xmax);
2562  if (axisNumber == 1) {
2563  hobj->GetXaxis()->SetRange(bin1,bin2);
2564  } else if (axisNumber == 2) {
2565  if (hobj->GetDimension() == 1) {
2566  Double_t xxmin = xmin;
2567  Double_t xxmax = xmax;
2568  if (hobj->GetNormFactor() != 0) {
2569  Double_t norm = hobj->GetSumOfWeights()/hobj->GetNormFactor();
2570  xxmin *= norm;
2571  xxmax *= norm;
2572  }
2573  hobj->SetMinimum(xxmin);
2574  hobj->SetMaximum(xxmax);
2575  hobj->SetBit(TH1::kIsZoomed);
2576  } else {
2577  bin1 = hobj->GetYaxis()->FindFixBin(xmin);
2578  bin2 = hobj->GetYaxis()->FindFixBin(xmax);
2579  hobj->GetYaxis()->SetRange(bin1,bin2);
2580  }
2581  }
2582  }
2583  Modified(kTRUE);
2584  }
2585  }
2586  if (!opaque) {
2587  gVirtualX->SetLineColor(-1);
2588  } else {
2589  if (zoombox) {
2590  zoombox->Delete();
2591  zoombox = 0;
2592  }
2593  }
2594  break;
2595  }
2596 }
2597 
2598 ////////////////////////////////////////////////////////////////////////////////
2599 /// Search if object named name is inside this pad or in pads inside this pad.
2600 ///
2601 /// In case name is in several sub-pads the first one is returned.
2602 
2603 TObject *TPad::FindObject(const char *name) const
2604 {
2605  if (!fPrimitives) return nullptr;
2606  TObject *found = fPrimitives->FindObject(name);
2607  if (found) return found;
2608  TObject *cur;
2609  TIter next(GetListOfPrimitives());
2610  while ((cur = next())) {
2611  if (cur->InheritsFrom(TPad::Class())) {
2612  found = ((TPad*)cur)->FindObject(name);
2613  if (found) return found;
2614  }
2615  }
2616  return nullptr;
2617 }
2618 
2619 ////////////////////////////////////////////////////////////////////////////////
2620 /// Search if obj is in pad or in pads inside this pad.
2621 ///
2622 /// In case obj is in several sub-pads the first one is returned.
2623 
2624 TObject *TPad::FindObject(const TObject *obj) const
2625 {
2626  if (!fPrimitives) return nullptr;
2627  TObject *found = fPrimitives->FindObject(obj);
2628  if (found) return found;
2629  TObject *cur;
2630  TIter next(GetListOfPrimitives());
2631  while ((cur = next())) {
2632  if (cur->InheritsFrom(TPad::Class())) {
2633  found = ((TPad*)cur)->FindObject(obj);
2634  if (found) return found;
2635  }
2636  }
2637  return nullptr;
2638 }
2639 
2640 ////////////////////////////////////////////////////////////////////////////////
2641 /// Get canvas identifier.
2642 
2643 Int_t TPad::GetCanvasID() const
2644 {
2645  return fCanvas ? fCanvas->GetCanvasID() : -1;
2646 }
2647 
2648 ////////////////////////////////////////////////////////////////////////////////
2649 /// Get canvas implementation pointer if any
2650 
2651 TCanvasImp *TPad::GetCanvasImp() const
2652 {
2653  return fCanvas ? fCanvas->GetCanvasImp() : nullptr;
2654 }
2655 
2656 ////////////////////////////////////////////////////////////////////////////////
2657 /// Get Event.
2658 
2659 Int_t TPad::GetEvent() const
2660 {
2661  return fCanvas ? fCanvas->GetEvent() : 0;
2662 }
2663 
2664 ////////////////////////////////////////////////////////////////////////////////
2665 /// Get X event.
2666 
2667 Int_t TPad::GetEventX() const
2668 {
2669  return fCanvas ? fCanvas->GetEventX() : 0;
2670 }
2671 
2672 ////////////////////////////////////////////////////////////////////////////////
2673 /// Get Y event.
2674 
2675 Int_t TPad::GetEventY() const
2676 {
2677  return fCanvas ? fCanvas->GetEventY() : 0;
2678 }
2679 
2680 ////////////////////////////////////////////////////////////////////////////////
2681 /// Get virtual canvas.
2682 
2683 TVirtualPad *TPad::GetVirtCanvas() const
2684 {
2685  return fCanvas ? (TVirtualPad*) fCanvas : nullptr;
2686 }
2687 
2688 ////////////////////////////////////////////////////////////////////////////////
2689 /// Get highlight color.
2690 
2691 Color_t TPad::GetHighLightColor() const
2692 {
2693  return fCanvas ? fCanvas->GetHighLightColor() : 0;
2694 }
2695 
2696 ////////////////////////////////////////////////////////////////////////////////
2697 /// Static function (see also TPad::SetMaxPickDistance)
2698 
2699 Int_t TPad::GetMaxPickDistance()
2700 {
2701  return fgMaxPickDistance;
2702 }
2703 
2704 ////////////////////////////////////////////////////////////////////////////////
2705 /// Get selected.
2706 
2707 TObject *TPad::GetSelected() const
2708 {
2709  if (fCanvas == this) return nullptr;
2710  return fCanvas ? fCanvas->GetSelected() : nullptr;
2711 }
2712 
2713 ////////////////////////////////////////////////////////////////////////////////
2714 /// Get selected pad.
2715 
2716 TVirtualPad *TPad::GetSelectedPad() const
2717 {
2718  if (fCanvas == this) return nullptr;
2719  return fCanvas ? fCanvas->GetSelectedPad() : nullptr;
2720 }
2721 
2722 ////////////////////////////////////////////////////////////////////////////////
2723 /// Get save pad.
2724 
2725 TVirtualPad *TPad::GetPadSave() const
2726 {
2727  if (fCanvas == this) return nullptr;
2728  return fCanvas ? fCanvas->GetPadSave() : nullptr;
2729 }
2730 
2731 ////////////////////////////////////////////////////////////////////////////////
2732 /// Get Wh.
2733 
2734 UInt_t TPad::GetWh() const
2735 {
2736  return fCanvas ? fCanvas->GetWh() : 0;
2737 }
2738 
2739 ////////////////////////////////////////////////////////////////////////////////
2740 /// Get Ww.
2741 
2742 UInt_t TPad::GetWw() const
2743 {
2744  return fCanvas ? fCanvas->GetWw() : 0;
2745 }
2746 
2747 ////////////////////////////////////////////////////////////////////////////////
2748 /// Hide tool tip depending on the event type. Typically tool tips
2749 /// are hidden when event is not a kMouseEnter and not a kMouseMotion
2750 /// event.
2751 
2752 void TPad::HideToolTip(Int_t event)
2753 {
2754  if (event != kMouseEnter && event != kMouseMotion && fTip)
2755  gPad->CloseToolTip(fTip);
2756 }
2757 
2758 ////////////////////////////////////////////////////////////////////////////////
2759 /// Is pad in batch mode ?
2760 
2761 Bool_t TPad::IsBatch() const
2762 {
2763  return fCanvas ? fCanvas->IsBatch() : kFALSE;
2764 }
2765 
2766 ////////////////////////////////////////////////////////////////////////////////
2767 /// Is pad retained ?
2768 
2769 Bool_t TPad::IsRetained() const
2770 {
2771  return fCanvas ? fCanvas->IsRetained() : kFALSE;
2772 }
2773 
2774 ////////////////////////////////////////////////////////////////////////////////
2775 /// Is pad moving in opaque mode ?
2776 
2777 Bool_t TPad::OpaqueMoving() const
2778 {
2779  return fCanvas ? fCanvas->OpaqueMoving() : kFALSE;
2780 }
2781 
2782 ////////////////////////////////////////////////////////////////////////////////
2783 /// Is pad resizing in opaque mode ?
2784 
2785 Bool_t TPad::OpaqueResizing() const
2786 {
2787  return fCanvas ? fCanvas->OpaqueResizing() : kFALSE;
2788 }
2789 
2790 ////////////////////////////////////////////////////////////////////////////////
2791 /// Set pad in batch mode.
2792 
2793 void TPad::SetBatch(Bool_t batch)
2794 {
2795  if (fCanvas) fCanvas->SetBatch(batch);
2796 }
2797 
2798 ////////////////////////////////////////////////////////////////////////////////
2799 /// Set canvas size.
2800 
2801 void TPad::SetCanvasSize(UInt_t ww, UInt_t wh)
2802 {
2803  if (fCanvas) fCanvas->SetCanvasSize(ww,wh);
2804 }
2805 
2806 ////////////////////////////////////////////////////////////////////////////////
2807 /// Set cursor type.
2808 
2809 void TPad::SetCursor(ECursor cursor)
2810 {
2811  if (fCanvas) fCanvas->SetCursor(cursor);
2812 }
2813 
2814 ////////////////////////////////////////////////////////////////////////////////
2815 /// Set double buffer mode ON or OFF.
2816 
2817 void TPad::SetDoubleBuffer(Int_t mode)
2818 {
2819  if (fCanvas) fCanvas->SetDoubleBuffer(mode);
2820 }
2821 
2822 ////////////////////////////////////////////////////////////////////////////////
2823 /// Set selected.
2824 
2825 void TPad::SetSelected(TObject *obj)
2826 {
2827  if (fCanvas) fCanvas->SetSelected(obj);
2828 }
2829 
2830 ////////////////////////////////////////////////////////////////////////////////
2831 /// Update pad.
2832 
2833 void TPad::Update()
2834 {
2835  if (fCanvas) fCanvas->Update();
2836 }
2837 
2838 ////////////////////////////////////////////////////////////////////////////////
2839 /// Get frame.
2840 
2841 TFrame *TPad::GetFrame()
2842 {
2843  if (!fPrimitives) fPrimitives = new TList;
2844  TFrame *frame = (TFrame*)GetListOfPrimitives()->FindObject(fFrame);
2845  if (!frame) frame = (TFrame*)GetListOfPrimitives()->FindObject("TFrame");
2846  fFrame = frame;
2847  if (!fFrame) {
2848  if (!frame) fFrame = new TFrame(0,0,1,1);
2849  Int_t framecolor = GetFrameFillColor();
2850  if (!framecolor) framecolor = GetFillColor();
2851  fFrame->SetFillColor(framecolor);
2852  fFrame->SetFillStyle(GetFrameFillStyle());
2853  fFrame->SetLineColor(GetFrameLineColor());
2854  fFrame->SetLineStyle(GetFrameLineStyle());
2855  fFrame->SetLineWidth(GetFrameLineWidth());
2856  fFrame->SetBorderSize(GetFrameBorderSize());
2857  fFrame->SetBorderMode(GetFrameBorderMode());
2858  }
2859  return fFrame;
2860 }
2861 
2862 ////////////////////////////////////////////////////////////////////////////////
2863 /// Get primitive.
2864 
2865 TObject *TPad::GetPrimitive(const char *name) const
2866 {
2867  if (!fPrimitives) return nullptr;
2868  TIter next(fPrimitives);
2869  TObject *found, *obj;
2870  while ((obj=next())) {
2871  if (!strcmp(name, obj->GetName())) return obj;
2872  if (obj->InheritsFrom(TPad::Class())) continue;
2873  found = obj->FindObject(name);
2874  if (found) return found;
2875  }
2876  return nullptr;
2877 }
2878 
2879 ////////////////////////////////////////////////////////////////////////////////
2880 /// Get a pointer to subpadnumber of this pad.
2881 
2882 TVirtualPad *TPad::GetPad(Int_t subpadnumber) const
2883 {
2884  if (!subpadnumber) {
2885  return (TVirtualPad*)this;
2886  }
2887 
2888  TObject *obj;
2889  if (!fPrimitives) return nullptr;
2890  TIter next(GetListOfPrimitives());
2891  while ((obj = next())) {
2892  if (obj->InheritsFrom(TVirtualPad::Class())) {
2893  TVirtualPad *pad = (TVirtualPad*)obj;
2894  if (pad->GetNumber() == subpadnumber) return pad;
2895  }
2896  }
2897  return nullptr;
2898 }
2899 
2900 ////////////////////////////////////////////////////////////////////////////////
2901 /// Return lower and upper bounds of the pad in NDC coordinates.
2902 
2903 void TPad::GetPadPar(Double_t &xlow, Double_t &ylow, Double_t &xup, Double_t &yup)
2904 {
2905  xlow = fXlowNDC;
2906  ylow = fYlowNDC;
2907  xup = fXlowNDC+fWNDC;
2908  yup = fYlowNDC+fHNDC;
2909 }
2910 
2911 ////////////////////////////////////////////////////////////////////////////////
2912 /// Return pad world coordinates range.
2913 
2914 void TPad::GetRange(Double_t &x1, Double_t &y1, Double_t &x2, Double_t &y2)
2915 {
2916  x1 = fX1;
2917  y1 = fY1;
2918  x2 = fX2;
2919  y2 = fY2;
2920 }
2921 
2922 ////////////////////////////////////////////////////////////////////////////////
2923 /// Return pad axis coordinates range.
2924 
2925 void TPad::GetRangeAxis(Double_t &xmin, Double_t &ymin, Double_t &xmax, Double_t &ymax)
2926 {
2927  xmin = fUxmin;
2928  ymin = fUymin;
2929  xmax = fUxmax;
2930  ymax = fUymax;
2931 }
2932 
2933 ////////////////////////////////////////////////////////////////////////////////
2934 /// Highlight pad.
2935 /// do not highlight when printing on Postscript
2936 
2937 void TPad::HighLight(Color_t color, Bool_t set)
2938 {
2939  if (gVirtualPS && gVirtualPS->TestBit(kPrintingPS)) return;
2940 
2941  if (color <= 0) return;
2942 
2943  AbsCoordinates(kTRUE);
2944 
2945  // We do not want to have active(executable) buttons, etc highlighted
2946  // in this manner, unless we want to edit'em
2947  if (GetMother() && GetMother()->IsEditable() && !InheritsFrom(TButton::Class())) {
2948  //When doing a DrawClone from the GUI you would do
2949  // - select an empty pad -
2950  // - right click on object -
2951  // - select DrawClone on menu -
2952  //
2953  // Without the SetSelectedPad(); in the HighLight function, the
2954  // above instruction lead to the clone to be drawn in the
2955  // same canvas as the original object. This is because the
2956  // 'right clicking' (via TCanvas::HandleInput) changes gPad
2957  // momentarily such that when DrawClone is called, it is
2958  // not the right value (for DrawClone). Should be FIXED.
2959  gROOT->SetSelectedPad(this);
2960  if (GetBorderMode()>0) {
2961  if (set) PaintBorder(-color, kFALSE);
2962  else PaintBorder(-GetFillColor(), kFALSE);
2963  }
2964  }
2965 
2966  AbsCoordinates(kFALSE);
2967 }
2968 
2969 ////////////////////////////////////////////////////////////////////////////////
2970 /// List all primitives in pad.
2971 
2972 void TPad::ls(Option_t *option) const
2973 {
2974  TROOT::IndentLevel();
2975  std::cout <<IsA()->GetName()<<" fXlowNDC=" <<fXlowNDC<<" fYlowNDC="<<fYlowNDC<<" fWNDC="<<GetWNDC()<<" fHNDC="<<GetHNDC()
2976  <<" Name= "<<GetName()<<" Title= "<<GetTitle()<<" Option="<<option<<std::endl;
2977  TROOT::IncreaseDirLevel();
2978  if (!fPrimitives) return;
2979  fPrimitives->ls(option);
2980  TROOT::DecreaseDirLevel();
2981 }
2982 
2983 ////////////////////////////////////////////////////////////////////////////////
2984 /// Increment (i==1) or set (i>1) the number of autocolor in the pad.
2985 
2986 Int_t TPad::IncrementPaletteColor(Int_t i, TString opt)
2987 {
2988  if (opt.Index("pfc")>=0 || opt.Index("plc")>=0 || opt.Index("pmc")>=0) {
2989  if (i==1) fNumPaletteColor++;
2990  else fNumPaletteColor = i;
2991  return fNumPaletteColor;
2992  } else {
2993  return 0;
2994  }
2995 }
2996 
2997 ////////////////////////////////////////////////////////////////////////////////
2998 /// Get the next autocolor in the pad.
2999 
3000 Int_t TPad::NextPaletteColor()
3001 {
3002  Int_t i = 0;
3003  Int_t ncolors = gStyle->GetNumberOfColors();
3004  if (fNumPaletteColor>1) {
3005  i = fNextPaletteColor*(ncolors/(fNumPaletteColor-1));
3006  if (i>=ncolors) i = ncolors-1;
3007  }
3008  fNextPaletteColor++;
3009  if (fNextPaletteColor > fNumPaletteColor-1) fNextPaletteColor = 0;
3010  return gStyle->GetColorPalette(i);
3011 }
3012 
3013 ////////////////////////////////////////////////////////////////////////////////
3014 /// Initialise the grid used to find empty space when adding a box (Legend) in a pad
3015 
3016 void TPad::FillCollideGrid(TObject *oi)
3017 {
3018  Int_t const cellSize = 10; // Sive of an individual grid cell in pixels.
3019 
3020  if (fCGnx == 0 && fCGny == 0) {
3021  fCGnx = gPad->GetWw()/cellSize;
3022  fCGny = gPad->GetWh()/cellSize;
3023  } else {
3024  Int_t CGnx = gPad->GetWw()/cellSize;
3025  Int_t CGny = gPad->GetWh()/cellSize;
3026  if (fCGnx != CGnx || fCGny != CGny) {
3027  fCGnx = CGnx;
3028  fCGny = CGny;
3029  delete [] fCollideGrid;
3030  fCollideGrid = nullptr;
3031  }
3032  }
3033 
3034  // Initialise the collide grid
3035  if (!fCollideGrid) {
3036  fCollideGrid = new Bool_t [fCGnx*fCGny];
3037  for (int i = 0; i<fCGnx; i++) {
3038  for (int j = 0; j<fCGny; j++) {
3039  fCollideGrid[i + j*fCGnx] = kTRUE;
3040  }
3041  }
3042  }
3043 
3044  // Fill the collide grid
3045  TList *l = GetListOfPrimitives();
3046  Int_t np = l->GetSize();
3047  TObject *o;
3048 
3049  for (int i=0; i<np; i++) {
3050  o = (TObject *) l->At(i);
3051  if (o!=oi) {
3052  if (o->InheritsFrom(TFrame::Class())) { FillCollideGridTFrame(o); continue;}
3053  if (o->InheritsFrom(TBox::Class())) { FillCollideGridTBox(o); continue;}
3054  if (o->InheritsFrom(TH1::Class())) { FillCollideGridTH1(o); continue;}
3055  if (o->InheritsFrom(TGraph::Class())) { FillCollideGridTGraph(o); continue;}
3056  if (o->InheritsFrom(TMultiGraph::Class())) {
3057  TList * grlist = ((TMultiGraph *)o)->GetListOfGraphs();
3058  TIter nextgraph(grlist);
3059  TObject * og;
3060  while ((og = nextgraph())) FillCollideGridTGraph(og);
3061  }
3062  if (o->InheritsFrom(THStack::Class())) {
3063  TList * hlist = ((THStack *)o)->GetHists();
3064  TIter nexthist(hlist);
3065  TObject * oh;
3066  while ((oh = nexthist())) {
3067  if (oh->InheritsFrom(TH1::Class())) FillCollideGridTH1(oh);
3068  }
3069  }
3070  }
3071  }
3072 }
3073 
3074 ////////////////////////////////////////////////////////////////////////////////
3075 /// Check if a box of size w and h collide some primitives in the pad at
3076 /// position i,j
3077 
3078 Bool_t TPad::Collide(Int_t i, Int_t j, Int_t w, Int_t h)
3079 {
3080  for (int r=i; r<w+i; r++) {
3081  for (int c=j; c<h+j; c++) {
3082  if (!fCollideGrid[r + c*fCGnx]) return kTRUE;
3083  }
3084  }
3085  return kFALSE;
3086 }
3087 
3088 ////////////////////////////////////////////////////////////////////////////////
3089 /// Place a box in NDC space
3090 ///
3091 /// \return `true` if the box could be placed, `false` if not.
3092 ///
3093 /// \param[in] w box width to be placed
3094 /// \param[in] h box height to be placed
3095 /// \param[out] xl x position of the bottom left corner of the placed box
3096 /// \param[out] yb y position of the bottom left corner of the placed box
3097 
3098 Bool_t TPad::PlaceBox(TObject *o, Double_t w, Double_t h, Double_t &xl, Double_t &yb)
3099 {
3100  FillCollideGrid(o);
3101 
3102  Int_t iw = (int)(fCGnx*w);
3103  Int_t ih = (int)(fCGny*h);
3104 
3105  Int_t nxmax = fCGnx-iw-1;
3106  Int_t nymax = fCGny-ih-1;
3107 
3108  for (Int_t i = 0; i<nxmax; i++) {
3109  for (Int_t j = 0; j<=nymax; j++) {
3110  if (Collide(i,j,iw,ih)) {
3111  continue;
3112  } else {
3113  xl = (Double_t)(i)/(Double_t)(fCGnx);
3114  yb = (Double_t)(j)/(Double_t)(fCGny);
3115  return kTRUE;
3116  }
3117  }
3118  }
3119  return kFALSE;
3120 }
3121 
3122 #define NotFree(i, j) fCollideGrid[TMath::Max(TMath::Min(i+j*fCGnx,fCGnx*fCGny),0)] = kFALSE;
3123 
3124 ////////////////////////////////////////////////////////////////////////////////
3125 /// Mark as "not free" the cells along a line.
3126 
3127 void TPad::LineNotFree(Int_t x1, Int_t x2, Int_t y1, Int_t y2)
3128 {
3129  NotFree(x1, y1);
3130  NotFree(x2, y2);
3131  Int_t i, j, xt, yt;
3132 
3133  // horizontal lines
3134  if (y1==y2) {
3135  for (i=x1+1; i<x2; i++) NotFree(i,y1);
3136  return;
3137  }
3138 
3139  // vertical lines
3140  if (x1==x2) {
3141  for (i=y1+1; i<y2; i++) NotFree(x1,i);
3142  return;
3143  }
3144 
3145  // other lines
3146  if (TMath::Abs(x2-x1)>TMath::Abs(y2-y1)) {
3147  if (x1>x2) {
3148  xt = x1; x1 = x2; x2 = xt;
3149  yt = y1; y1 = y2; y2 = yt;
3150  }
3151  for (i=x1+1; i<x2; i++) {
3152  j = (Int_t)((Double_t)(y2-y1)*(Double_t)((i-x1)/(Double_t)(x2-x1))+y1);
3153  NotFree(i,j);
3154  NotFree(i,(j+1));
3155  }
3156  } else {
3157  if (y1>y2) {
3158  yt = y1; y1 = y2; y2 = yt;
3159  xt = x1; x1 = x2; x2 = xt;
3160  }
3161  for (j=y1+1; j<y2; j++) {
3162  i = (Int_t)((Double_t)(x2-x1)*(Double_t)((j-y1)/(Double_t)(y2-y1))+x1);
3163  NotFree(i,j);
3164  NotFree((i+1),j);
3165  }
3166  }
3167 }
3168 
3169 ////////////////////////////////////////////////////////////////////////////////
3170 void TPad::FillCollideGridTBox(TObject *o)
3171 {
3172  TBox *b = (TBox *)o;
3173 
3174  Double_t xs = (fX2-fX1)/fCGnx;
3175  Double_t ys = (fY2-fY1)/fCGny;
3176 
3177  Int_t x1 = (Int_t)((b->GetX1()-fX1)/xs);
3178  Int_t x2 = (Int_t)((b->GetX2()-fX1)/xs);
3179  Int_t y1 = (Int_t)((b->GetY1()-fY1)/ys);
3180  Int_t y2 = (Int_t)((b->GetY2()-fY1)/ys);
3181  for (int i = x1; i<=x2; i++) {
3182  for (int j = y1; j<=y2; j++) NotFree(i, j);
3183  }
3184 }
3185 
3186 ////////////////////////////////////////////////////////////////////////////////
3187 void TPad::FillCollideGridTFrame(TObject *o)
3188 {
3189  TFrame *f = (TFrame *)o;
3190 
3191  Double_t xs = (fX2-fX1)/fCGnx;
3192  Double_t ys = (fY2-fY1)/fCGny;
3193 
3194  Int_t x1 = (Int_t)((f->GetX1()-fX1)/xs);
3195  Int_t x2 = (Int_t)((f->GetX2()-fX1)/xs);
3196  Int_t y1 = (Int_t)((f->GetY1()-fY1)/ys);
3197  Int_t y2 = (Int_t)((f->GetY2()-fY1)/ys);
3198  Int_t i;
3199 
3200  for (i = x1; i<=x2; i++) {
3201  NotFree(i, y1);
3202  NotFree(i, (y1-1));
3203  NotFree(i, (y1-2));
3204  }
3205  for (i = y1; i<=y2; i++) {
3206  NotFree(x1, i);
3207  NotFree((x1-1), i);
3208  NotFree((x1-2), i);
3209  }
3210 }
3211 
3212 ////////////////////////////////////////////////////////////////////////////////
3213 void TPad::FillCollideGridTGraph(TObject *o)
3214 {
3215  TGraph *g = (TGraph *)o;
3216 
3217  Double_t xs = (fX2-fX1)/fCGnx;
3218  Double_t ys = (fY2-fY1)/fCGny;
3219 
3220  Int_t n = g->GetN();
3221  Double_t x1, x2, y1, y2;
3222 
3223  for (Int_t i=1; i<n; i++) {
3224  g->GetPoint(i-1,x1,y1);
3225  g->GetPoint(i ,x2,y2);
3226  if (fLogx) {
3227  if (x1 > 0) x1 = TMath::Log10(x1);
3228  else x1 = fUxmin;
3229  if (x2 > 0) x2 = TMath::Log10(x2);
3230  else x2 = fUxmin;
3231  }
3232  if (fLogy) {
3233  if (y1 > 0) y1 = TMath::Log10(y1);
3234  else y1 = fUymin;
3235  if (y2 > 0) y2 = TMath::Log10(y2);
3236  else y2 = fUymin;
3237  }
3238  LineNotFree((int)((x1-fX1)/xs), (int)((x2-fX1)/xs),
3239  (int)((y1-fY1)/ys), (int)((y2-fY1)/ys));
3240  }
3241 }
3242 
3243 ////////////////////////////////////////////////////////////////////////////////
3244 void TPad::FillCollideGridTH1(TObject *o)
3245 {
3246  TH1 *h = (TH1 *)o;
3247 
3248  if (o->InheritsFrom(TH2::Class())) return;
3249  if (o->InheritsFrom(TH3::Class())) return;
3250 
3251  TString name = h->GetName();
3252  if (name.Index("hframe") >= 0) return;
3253 
3254  Double_t xs = (fX2-fX1)/fCGnx;
3255  Double_t ys = (fY2-fY1)/fCGny;
3256 
3257  bool haserrors = false;
3258  TString drawOption = h->GetDrawOption();
3259  drawOption.ToLower();
3260  drawOption.ReplaceAll("same","");
3261 
3262  if (drawOption.Index("hist") < 0) {
3263  if (drawOption.Index("e") >= 0) haserrors = true;
3264  }
3265 
3266  Int_t nx = h->GetNbinsX();
3267  Int_t x1, y1, y2;
3268  Int_t i, j;
3269  Double_t x1l, y1l, y2l;
3270 
3271  for (i = 1; i<nx; i++) {
3272  if (haserrors) {
3273  x1l = h->GetBinCenter(i);
3274  if (fLogx) {
3275  if (x1l > 0) x1l = TMath::Log10(x1l);
3276  else x1l = fUxmin;
3277  }
3278  x1 = (Int_t)((x1l-fX1)/xs);
3279  y1l = h->GetBinContent(i)-h->GetBinErrorLow(i);
3280  if (fLogy) {
3281  if (y1l > 0) y1l = TMath::Log10(y1l);
3282  else y1l = fUymin;
3283  }
3284  y1 = (Int_t)((y1l-fY1)/ys);
3285  y2l = h->GetBinContent(i)+h->GetBinErrorUp(i);
3286  if (fLogy) {
3287  if (y2l > 0) y2l = TMath::Log10(y2l);
3288  else y2l = fUymin;
3289  }
3290  y2 = (Int_t)((y2l-fY1)/ys);
3291  for (j=y1; j<=y2; j++) {
3292  NotFree(x1, j);
3293  }
3294  }
3295  x1l = h->GetBinLowEdge(i);
3296  if (fLogx) {
3297  if (x1l > 0) x1l = TMath::Log10(x1l);
3298  else x1l = fUxmin;
3299  }
3300  x1 = (Int_t)((x1l-fX1)/xs);
3301  y1l = h->GetBinContent(i);
3302  if (fLogy) {
3303  if (y1l > 0) y1l = TMath::Log10(y1l);
3304  else y1l = fUymin;
3305  }
3306  y1 = (Int_t)((y1l-fY1)/ys);
3307  NotFree(x1, y1);
3308  x1l = h->GetBinLowEdge(i)+h->GetBinWidth(i);
3309  if (fLogx) {
3310  if (x1l > 0) x1l = TMath::Log10(x1l);
3311  else x1l = fUxmin;
3312  }
3313  x1 = (int)((x1l-fX1)/xs);
3314  NotFree(x1, y1);
3315  }
3316 
3317  // Extra objects in the list of function
3318  TPaveStats *ps = (TPaveStats*)h->GetListOfFunctions()->FindObject("stats");
3319  if (ps) FillCollideGridTBox(ps);
3320 }
3321 
3322 ////////////////////////////////////////////////////////////////////////////////
3323 /// This method draws the collide grid on top of the canvas. This is used for
3324 /// debugging only. At some point it will be removed.
3325 
3326 void TPad::DrawCollideGrid()
3327 {
3328  auto box = new TBox();
3329  box->SetFillColorAlpha(kRed,0.5);
3330 
3331  Double_t xs = (fX2-fX1)/fCGnx;
3332  Double_t ys = (fY2-fY1)/fCGny;
3333 
3334  Double_t X1L, X2L, Y1L, Y2L;
3335  Double_t t = 0.15;
3336  Double_t Y1, Y2;
3337  Double_t X1 = fX1;
3338  Double_t X2 = X1+xs;
3339 
3340  for (int i = 0; i<fCGnx; i++) {
3341  Y1 = fY1;
3342  Y2 = Y1+ys;
3343  for (int j = 0; j<fCGny; j++) {
3344  if (gPad->GetLogx()) {
3345  X1L = TMath::Power(10,X1);
3346  X2L = TMath::Power(10,X2);
3347  } else {
3348  X1L = X1;
3349  X2L = X2;
3350  }
3351  if (gPad->GetLogy()) {
3352  Y1L = TMath::Power(10,Y1);
3353  Y2L = TMath::Power(10,Y2);
3354  } else {
3355  Y1L = Y1;
3356  Y2L = Y2;
3357  }
3358  if (!fCollideGrid[i + j*fCGnx]) {
3359  box->SetFillColorAlpha(kBlack,t);
3360  box->DrawBox(X1L, Y1L, X2L, Y2L);
3361  } else {
3362  box->SetFillColorAlpha(kRed,t);
3363  box->DrawBox(X1L, Y1L, X2L, Y2L);
3364  }
3365  Y1 = Y2;
3366  Y2 = Y1+ys;
3367  if (t==0.15) t = 0.1;
3368  else t = 0.15;
3369  }
3370  X1 = X2;
3371  X2 = X1+xs;
3372  }
3373 }
3374 
3375 
3376 ////////////////////////////////////////////////////////////////////////////////
3377 /// Convert x from pad to X.
3378 
3379 Double_t TPad::PadtoX(Double_t x) const
3380 {
3381  if (fLogx && x < 50) return Double_t(TMath::Exp(2.302585092994*x));
3382  return x;
3383 }
3384 
3385 ////////////////////////////////////////////////////////////////////////////////
3386 /// Convert y from pad to Y.
3387 
3388 Double_t TPad::PadtoY(Double_t y) const
3389 {
3390  if (fLogy && y < 50) return Double_t(TMath::Exp(2.302585092994*y));
3391  return y;
3392 }
3393 
3394 ////////////////////////////////////////////////////////////////////////////////
3395 /// Convert x from X to pad.
3396 
3397 Double_t TPad::XtoPad(Double_t x) const
3398 {
3399  if (fLogx) {
3400  if (x > 0) x = TMath::Log10(x);
3401  else x = fUxmin;
3402  }
3403  return x;
3404 }
3405 
3406 ////////////////////////////////////////////////////////////////////////////////
3407 /// Convert y from Y to pad.
3408 
3409 Double_t TPad::YtoPad(Double_t y) const
3410 {
3411  if (fLogy) {
3412  if (y > 0) y = TMath::Log10(y);
3413  else y = fUymin;
3414  }
3415  return y;
3416 }
3417 
3418 ////////////////////////////////////////////////////////////////////////////////
3419 /// Paint all primitives in pad.
3420 
3421 void TPad::Paint(Option_t * /*option*/)
3422 {
3423  if (!fPrimitives) fPrimitives = new TList;
3424  if (fViewer3D && fViewer3D->CanLoopOnPrimitives()) {
3425  fViewer3D->PadPaint(this);
3426  Modified(kFALSE);
3427  if (GetGLDevice()!=-1 && gVirtualPS) {
3428  TPad *padsav = (TPad*)gPad;
3429  gPad = this;
3430  gGLManager->PrintViewer(GetViewer3D());
3431  gPad = padsav;
3432  }
3433  return;
3434  }
3435 
3436  if (fCanvas) TColor::SetGrayscale(fCanvas->IsGrayscale());
3437 
3438  TPad *padsav = (TPad*)gPad;
3439 
3440  fPadPaint = 1;
3441  cd();
3442 
3443  PaintBorder(GetFillColor(), kTRUE);
3444  PaintDate();
3445 
3446  TObjOptLink *lnk = (TObjOptLink*)GetListOfPrimitives()->FirstLink();
3447  TObject *obj;
3448 
3449  Bool_t began3DScene = kFALSE;
3450  while (lnk) {
3451  obj = lnk->GetObject();
3452 
3453  // Create a pad 3D viewer if none exists and we encounter a 3D shape
3454  if (!fViewer3D && obj->InheritsFrom(TAtt3D::Class())) {
3455  GetViewer3D("pad");
3456  }
3457 
3458  // Open a 3D scene if required
3459  if (fViewer3D && !fViewer3D->BuildingScene()) {
3460  fViewer3D->BeginScene();
3461  began3DScene = kTRUE;
3462  }
3463 
3464  obj->Paint(lnk->GetOption());
3465  lnk = (TObjOptLink*)lnk->Next();
3466  }
3467 
3468  if (padsav) padsav->cd();
3469  fPadPaint = 0;
3470  Modified(kFALSE);
3471 
3472  // Close the 3D scene if we opened it. This must be done after modified
3473  // flag is cleared, as some viewers will invoke another paint by marking pad modified again
3474  if (began3DScene) {
3475  fViewer3D->EndScene();
3476  }
3477 }
3478 
3479 ////////////////////////////////////////////////////////////////////////////////
3480 /// Paint the pad border.
3481 /// Draw first a box as a normal filled box
3482 
3483 void TPad::PaintBorder(Color_t color, Bool_t tops)
3484 {
3485  if(color >= 0) {
3486  TAttLine::Modify(); //Change line attributes only if necessary
3487  TAttFill::Modify(); //Change fill area attributes only if necessary
3488 
3489  //With Cocoa we have a transparency. But we also have
3490  //pixmaps, and if you just paint a new content over the old one
3491  //with alpha < 1., you'll be able to see the old content.
3492  if (!gROOT->IsBatch() && gVirtualX->InheritsFrom("TGCocoa") && GetPainter())
3493  GetPainter()->ClearDrawable();
3494 
3495  PaintBox(fX1,fY1,fX2,fY2);
3496  }
3497  if (color < 0) color = -color;
3498  // then paint 3d frame (depending on bordermode)
3499  if (IsTransparent()) return;
3500  // Paint a 3D frame around the pad.
3501 
3502  if (fBorderMode == 0) return;
3503  Int_t bordersize = fBorderSize;
3504  if (bordersize <= 0) bordersize = 2;
3505 
3506  const Double_t realBsX = bordersize / (GetAbsWNDC() * GetWw()) * (fX2 - fX1);
3507  const Double_t realBsY = bordersize / (GetAbsHNDC() * GetWh()) * (fY2 - fY1);
3508 
3509  Short_t px1,py1,px2,py2;
3510  Double_t xl, xt, yl, yt;
3511 
3512  // GetDarkColor() and GetLightColor() use GetFillColor()
3513  Color_t oldcolor = GetFillColor();
3514  SetFillColor(color);
3515  TAttFill::Modify();
3516  Color_t light = 0, dark = 0;
3517  if (color != 0) {
3518  light = TColor::GetColorBright(color);
3519  dark = TColor::GetColorDark(color);
3520  }
3521 
3522  // Compute real left bottom & top right of the box in pixels
3523  px1 = XtoPixel(fX1); py1 = YtoPixel(fY1);
3524  px2 = XtoPixel(fX2); py2 = YtoPixel(fY2);
3525  if (px1 < px2) {xl = fX1; xt = fX2; }
3526  else {xl = fX2; xt = fX1;}
3527  if (py1 > py2) {yl = fY1; yt = fY2;}
3528  else {yl = fY2; yt = fY1;}
3529 
3530  Double_t frameXs[7] = {}, frameYs[7] = {};
3531 
3532  if (!IsBatch()) {
3533  // Draw top&left part of the box
3534  frameXs[0] = xl; frameYs[0] = yl;
3535  frameXs[1] = xl + realBsX; frameYs[1] = yl + realBsY;
3536  frameXs[2] = frameXs[1]; frameYs[2] = yt - realBsY;
3537  frameXs[3] = xt - realBsX; frameYs[3] = frameYs[2];
3538  frameXs[4] = xt; frameYs[4] = yt;
3539  frameXs[5] = xl; frameYs[5] = yt;
3540  frameXs[6] = xl; frameYs[6] = yl;
3541 
3542  if (fBorderMode == -1) GetPainter()->SetFillColor(dark);
3543  else GetPainter()->SetFillColor(light);
3544  GetPainter()->DrawFillArea(7, frameXs, frameYs);
3545 
3546  // Draw bottom&right part of the box
3547  frameXs[0] = xl; frameYs[0] = yl;
3548  frameXs[1] = xl + realBsX; frameYs[1] = yl + realBsY;
3549  frameXs[2] = xt - realBsX; frameYs[2] = frameYs[1];
3550  frameXs[3] = frameXs[2]; frameYs[3] = yt - realBsY;
3551  frameXs[4] = xt; frameYs[4] = yt;
3552  frameXs[5] = xt; frameYs[5] = yl;
3553  frameXs[6] = xl; frameYs[6] = yl;
3554 
3555  if (fBorderMode == -1) GetPainter()->SetFillColor(light);
3556  else GetPainter()->SetFillColor(dark);
3557  GetPainter()->DrawFillArea(7, frameXs, frameYs);
3558 
3559  // If this pad is a button, highlight it
3560  if (InheritsFrom(TButton::Class()) && fBorderMode == -1) {
3561  if (TestBit(kFraming)) { // bit set in TButton::SetFraming
3562  if (GetFillColor() != 2) GetPainter()->SetLineColor(2);
3563  else GetPainter()->SetLineColor(4);
3564  GetPainter()->DrawBox(xl + realBsX, yl + realBsY, xt - realBsX, yt - realBsY, TVirtualPadPainter::kHollow);
3565  }
3566  }
3567  GetPainter()->SetFillColor(-1);
3568  SetFillColor(oldcolor);
3569  }
3570 
3571  if (!tops) return;
3572 
3573  PaintBorderPS(xl, yl, xt, yt, fBorderMode, bordersize, dark, light);
3574 }
3575 
3576 ////////////////////////////////////////////////////////////////////////////////
3577 /// Paint a frame border with Postscript.
3578 
3579 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)
3580 {
3581  if (!gVirtualPS) return;
3582  gVirtualPS->DrawFrame(xl, yl, xt, yt, bmode,bsize,dark,light);
3583 }
3584 
3585 ////////////////////////////////////////////////////////////////////////////////
3586 /// Paint the current date and time if the option date is on.
3587 
3588 void TPad::PaintDate()
3589 {
3590  if (fCanvas == this && gStyle->GetOptDate()) {
3591  TDatime dt;
3592  const char *dates;
3593  char iso[16];
3594  if (gStyle->GetOptDate() < 10) {
3595  //by default use format like "Wed Sep 25 17:10:35 2002"
3596  dates = dt.AsString();
3597  } else if (gStyle->GetOptDate() < 20) {
3598  //use ISO format like 2002-09-25
3599  strlcpy(iso,dt.AsSQLString(),16);
3600  dates = iso;
3601  } else {
3602  //use ISO format like 2002-09-25 17:10:35
3603  dates = dt.AsSQLString();
3604  }
3605  TText tdate(gStyle->GetDateX(),gStyle->GetDateY(),dates);
3606  tdate.SetTextSize( gStyle->GetAttDate()->GetTextSize());
3607  tdate.SetTextFont( gStyle->GetAttDate()->GetTextFont());
3608  tdate.SetTextColor(gStyle->GetAttDate()->GetTextColor());
3609  tdate.SetTextAlign(gStyle->GetAttDate()->GetTextAlign());
3610  tdate.SetTextAngle(gStyle->GetAttDate()->GetTextAngle());
3611  tdate.SetNDC();
3612  tdate.Paint();
3613  }
3614 }
3615 
3616 ////////////////////////////////////////////////////////////////////////////////
3617 /// Paint histogram/graph frame.
3618 
3619 void TPad::PaintPadFrame(Double_t xmin, Double_t ymin, Double_t xmax, Double_t ymax)
3620 {
3621  if (!fPrimitives) fPrimitives = new TList;
3622  TList *glist = GetListOfPrimitives();
3623  TFrame *frame = GetFrame();
3624  frame->SetX1(xmin);
3625  frame->SetX2(xmax);
3626  frame->SetY1(ymin);
3627  frame->SetY2(ymax);
3628  if (!glist->FindObject(fFrame)) {
3629  glist->AddFirst(frame);
3630  fFrame->SetBit(kMustCleanup);
3631  }
3632  frame->Paint();
3633 }
3634 
3635 ////////////////////////////////////////////////////////////////////////////////
3636 /// Traverse pad hierarchy and (re)paint only modified pads.
3637 
3638 void TPad::PaintModified()
3639 {
3640  if (fViewer3D && fViewer3D->CanLoopOnPrimitives()) {
3641  if (IsModified()) {
3642  fViewer3D->PadPaint(this);
3643  Modified(kFALSE);
3644  }
3645  TList *pList = GetListOfPrimitives();
3646  TObjOptLink *lnk = 0;
3647  if (pList) lnk = (TObjOptLink*)pList->FirstLink();
3648  TObject *obj;
3649  while (lnk) {
3650  obj = lnk->GetObject();
3651  if (obj->InheritsFrom(TPad::Class()))
3652  ((TPad*)obj)->PaintModified();
3653  lnk = (TObjOptLink*)lnk->Next();
3654  }
3655  return;
3656  }
3657 
3658  if (fCanvas) TColor::SetGrayscale(fCanvas->IsGrayscale());
3659 
3660  TPad *padsav = (TPad*)gPad;
3661  TVirtualPS *saveps = gVirtualPS;
3662  if (gVirtualPS) {
3663  if (gVirtualPS->TestBit(kPrintingPS)) gVirtualPS = 0;
3664  }
3665  fPadPaint = 1;
3666  cd();
3667  if (IsModified() || IsTransparent()) {
3668  if ((fFillStyle < 3026) && (fFillStyle > 3000)) {
3669  if (!gPad->IsBatch()) GetPainter()->ClearDrawable();
3670  }
3671  PaintBorder(GetFillColor(), kTRUE);
3672  }
3673 
3674  PaintDate();
3675 
3676  TList *pList = GetListOfPrimitives();
3677  TObjOptLink *lnk = 0;
3678  if (pList) lnk = (TObjOptLink*)pList->FirstLink();
3679  TObject *obj;
3680 
3681  Bool_t began3DScene = kFALSE;
3682 
3683  while (lnk) {
3684  obj = lnk->GetObject();
3685  if (obj->InheritsFrom(TPad::Class())) {
3686  ((TPad*)obj)->PaintModified();
3687  } else if (IsModified() || IsTransparent()) {
3688 
3689  // Create a pad 3D viewer if none exists and we encounter a
3690  // 3D shape
3691  if (!fViewer3D && obj->InheritsFrom(TAtt3D::Class())) {
3692  GetViewer3D("pad");
3693  }
3694 
3695  // Open a 3D scene if required
3696  if (fViewer3D && !fViewer3D->BuildingScene()) {
3697  fViewer3D->BeginScene();
3698  began3DScene = kTRUE;
3699  }
3700 
3701  obj->Paint(lnk->GetOption());
3702  }
3703  lnk = (TObjOptLink*)lnk->Next();
3704  }
3705 
3706  if (padsav) padsav->cd();
3707  fPadPaint = 0;
3708  Modified(kFALSE);
3709 
3710  // This must be done after modified flag is cleared, as some
3711  // viewers will invoke another paint by marking pad modified again
3712  if (began3DScene) {
3713  fViewer3D->EndScene();
3714  }
3715 
3716  gVirtualPS = saveps;
3717 }
3718 
3719 ////////////////////////////////////////////////////////////////////////////////
3720 /// Paint box in CurrentPad World coordinates.
3721 ///
3722 /// - if option[0] = 's' the box is forced to be paint with style=0
3723 /// - if option[0] = 'l' the box contour is drawn
3724 
3725 void TPad::PaintBox(Double_t x1, Double_t y1, Double_t x2, Double_t y2, Option_t *option)
3726 {
3727  if (!gPad->IsBatch()) {
3728  Int_t style0 = GetPainter()->GetFillStyle();
3729  Int_t style = style0;
3730  if (option[0] == 's') {
3731  GetPainter()->SetFillStyle(0);
3732  style = 0;
3733  }
3734  if (style) {
3735  if (style > 3000 && style < 4000) {
3736  if (style < 3026) {
3737  // draw stipples with fFillColor foreground
3738  GetPainter()->DrawBox(x1, y1, x2, y2, TVirtualPadPainter::kFilled);
3739  }
3740 
3741  if (style >= 3100 && style < 4000) {
3742  Double_t xb[4], yb[4];
3743  xb[0] = x1; xb[1] = x1; xb[2] = x2; xb[3] = x2;
3744  yb[0] = y1; yb[1] = y2; yb[2] = y2; yb[3] = y1;
3745  PaintFillAreaHatches(4, xb, yb, style);
3746  return;
3747  }
3748  //special case for TAttFillCanvas
3749  if (GetPainter()->GetFillColor() == 10) {
3750  GetPainter()->SetFillColor(1);
3751  GetPainter()->DrawBox(x1, y1, x2, y2, TVirtualPadPainter::kFilled);
3752  GetPainter()->SetFillColor(10);
3753  }
3754  } else if (style >= 4000 && style <= 4100) {
3755  // For style >=4000 we make the window transparent.
3756  // From 4000 to 4100 the window is 100% transparent to 100% opaque
3757 
3758  //ignore this style option when this is the canvas itself
3759  if (this == fMother) {
3760  //It's clear, that virtual X checks a style (4000) and will render a hollow rect!
3761  const Style_t oldFillStyle = GetPainter()->GetFillStyle();
3762  if (gVirtualX->InheritsFrom("TGCocoa"))
3763  GetPainter()->SetFillStyle(1000);
3764  GetPainter()->DrawBox(x1, y1, x2, y2, TVirtualPadPainter::kFilled);
3765  if (gVirtualX->InheritsFrom("TGCocoa"))
3766  GetPainter()->SetFillStyle(oldFillStyle);
3767  } else {
3768  //draw background by blitting all bottom pads
3769  int px, py;
3770  XYtoAbsPixel(fX1, fY2, px, py);
3771 
3772  if (fMother) {
3773  fMother->CopyBackgroundPixmap(px, py);
3774  CopyBackgroundPixmaps(fMother, this, px, py);
3775  }
3776 
3777  GetPainter()->SetOpacity(style - 4000);
3778  }
3779  } else if (style >= 1000 && style <= 1999) {
3780  GetPainter()->DrawBox(x1, y1, x2, y2, TVirtualPadPainter::kFilled);
3781  } else {
3782  GetPainter()->DrawBox(x1, y1, x2, y2, TVirtualPadPainter::kHollow);
3783  }
3784  if (option[0] == 'l') GetPainter()->DrawBox(x1, y1, x2, y2, TVirtualPadPainter::kHollow);
3785  } else {
3786  GetPainter()->DrawBox(x1, y1, x2, y2, TVirtualPadPainter::kHollow);
3787  if (option[0] == 's') GetPainter()->SetFillStyle(style0);
3788  }
3789  }
3790 
3791  if (gVirtualPS) {
3792  Int_t style0 = gVirtualPS->GetFillStyle();
3793  if (option[0] == 's') {
3794  gVirtualPS->SetFillStyle(0);
3795  } else {
3796  if (style0 >= 3100 && style0 < 4000) {
3797  Double_t xb[4], yb[4];
3798  xb[0] = x1; xb[1] = x1; xb[2] = x2; xb[3] = x2;
3799  yb[0] = y1; yb[1] = y2; yb[2] = y2; yb[3] = y1;
3800  PaintFillAreaHatches(4, xb, yb, style0);
3801  return;
3802  }
3803  }
3804  gVirtualPS->DrawBox(x1, y1, x2, y2);
3805  if (option[0] == 'l') {
3806  gVirtualPS->SetFillStyle(0);
3807  gVirtualPS->DrawBox(x1, y1, x2, y2);
3808  }
3809  if (option[0] == 's' || option[0] == 'l') gVirtualPS->SetFillStyle(style0);
3810  }
3811 
3812  Modified();
3813 }
3814 
3815 ////////////////////////////////////////////////////////////////////////////////
3816 /// Copy pixmaps of pads laying below pad "stop" into pad "stop". This
3817 /// gives the effect of pad "stop" being transparent.
3818 
3819 void TPad::CopyBackgroundPixmaps(TPad *start, TPad *stop, Int_t x, Int_t y)
3820 {
3821  TObject *obj;
3822  if (!fPrimitives) fPrimitives = new TList;
3823  TIter next(start->GetListOfPrimitives());
3824  while ((obj = next())) {
3825  if (obj->InheritsFrom(TPad::Class())) {
3826  if (obj == stop) break;
3827  ((TPad*)obj)->CopyBackgroundPixmap(x, y);
3828  ((TPad*)obj)->CopyBackgroundPixmaps((TPad*)obj, stop, x, y);
3829  }
3830  }
3831 }
3832 
3833 ////////////////////////////////////////////////////////////////////////////////
3834 /// Copy pixmap of this pad as background of the current pad.
3835 
3836 void TPad::CopyBackgroundPixmap(Int_t x, Int_t y)
3837 {
3838  int px, py;
3839  XYtoAbsPixel(fX1, fY2, px, py);
3840  GetPainter()->CopyDrawable(GetPixmapID(), px-x, py-y);
3841 }
3842 
3843 ////////////////////////////////////////////////////////////////////////////////
3844 
3845 void TPad::PaintFillArea(Int_t, Float_t *, Float_t *, Option_t *)
3846 {
3847  Warning("TPad::PaintFillArea", "Float_t signature is obsolete. Use Double_t signature.");
3848 }
3849 
3850 ////////////////////////////////////////////////////////////////////////////////
3851 /// Paint fill area in CurrentPad World coordinates.
3852 
3853 void TPad::PaintFillArea(Int_t nn, Double_t *xx, Double_t *yy, Option_t *)
3854 {
3855  if (nn <3) return;
3856  Int_t n=0;
3857  Double_t xmin,xmax,ymin,ymax;
3858  if (TestBit(TGraph::kClipFrame)) {
3859  xmin = fUxmin; ymin = fUymin; xmax = fUxmax; ymax = fUymax;
3860  } else {
3861  xmin = fX1; ymin = fY1; xmax = fX2; ymax = fY2;
3862  }
3863 
3864  Int_t nc = 2*nn+1;
3865  std::vector<Double_t> x(nc, 0.);
3866  std::vector<Double_t> y(nc, 0.);
3867 
3868  n = ClipPolygon(nn, xx, yy, nc, &x.front(), &y.front(),xmin,ymin,xmax,ymax);
3869  if (!n)
3870  return;
3871 
3872  // Paint the fill area with hatches
3873  Int_t fillstyle = GetPainter()->GetFillStyle();
3874  if (gPad->IsBatch() && gVirtualPS) fillstyle = gVirtualPS->GetFillStyle();
3875  if (fillstyle >= 3100 && fillstyle < 4000) {
3876  PaintFillAreaHatches(nn, &x.front(), &y.front(), fillstyle);
3877  return;
3878  }
3879 
3880  if (!gPad->IsBatch())
3881  // invoke the graphics subsystem
3882  GetPainter()->DrawFillArea(n, &x.front(), &y.front());
3883 
3884  if (gVirtualPS)
3885  gVirtualPS->DrawPS(-n, &x.front(), &y.front());
3886 
3887  Modified();
3888 }
3889 
3890 ////////////////////////////////////////////////////////////////////////////////
3891 /// Paint fill area in CurrentPad NDC coordinates.
3892 
3893 void TPad::PaintFillAreaNDC(Int_t n, Double_t *x, Double_t *y, Option_t *option)
3894 {
3895  auto xw = new Double_t[n];
3896  auto yw = new Double_t[n];
3897  for (int i=0; i<n; i++) {
3898  xw[i] = fX1 + x[i]*(fX2 - fX1);
3899  yw[i] = fY1 + y[i]*(fY2 - fY1);
3900  }
3901  PaintFillArea(n, xw, yw, option);
3902  delete [] xw;
3903  delete [] yw;
3904 }
3905 
3906 ////////////////////////////////////////////////////////////////////////////////
3907 /// This function paints hatched fill area according to the FillStyle value
3908 /// The convention for the Hatch is the following:
3909 ///
3910 /// `FillStyle = 3ijk`
3911 ///
3912 /// - i (1-9) : specify the space between each hatch
3913 /// 1 = minimum 9 = maximum
3914 /// the final spacing is i*GetHatchesSpacing(). The hatches spacing
3915 /// is set by SetHatchesSpacing()
3916 /// - j (0-9) : specify angle between 0 and 90 degrees
3917 /// * 0 = 0
3918 /// * 1 = 10
3919 /// * 2 = 20
3920 /// * 3 = 30
3921 /// * 4 = 45
3922 /// * 5 = Not drawn
3923 /// * 6 = 60
3924 /// * 7 = 70
3925 /// * 8 = 80
3926 /// * 9 = 90
3927 /// - k (0-9) : specify angle between 90 and 180 degrees
3928 /// * 0 = 180
3929 /// * 1 = 170
3930 /// * 2 = 160
3931 /// * 3 = 150
3932 /// * 4 = 135
3933 /// * 5 = Not drawn
3934 /// * 6 = 120
3935 /// * 7 = 110
3936 /// * 8 = 100
3937 /// * 9 = 90
3938 
3939 void TPad::PaintFillAreaHatches(Int_t nn, Double_t *xx, Double_t *yy, Int_t FillStyle)
3940 {
3941  static Double_t ang1[10] = { 0., 10., 20., 30., 45.,5., 60., 70., 80., 89.99};
3942  static Double_t ang2[10] = {180.,170.,160.,150.,135.,5.,120.,110.,100., 89.99};
3943 
3944  Int_t fasi = FillStyle%1000;
3945  Int_t idSPA = (Int_t)(fasi/100);
3946  Int_t iAng2 = (Int_t)((fasi-100*idSPA)/10);
3947  Int_t iAng1 = fasi%10;
3948  Double_t dy = 0.003*(Double_t)(idSPA)*gStyle->GetHatchesSpacing();
3949  Int_t lw = gStyle->GetHatchesLineWidth();
3950  Short_t lws = 0;
3951  Int_t lss = 0;
3952  Int_t lcs = 0;
3953 
3954  // Save the current line attributes
3955  if (!gPad->IsBatch()) {
3956  lws = GetPainter()->GetLineWidth();
3957  lss = GetPainter()->GetLineStyle();
3958  lcs = GetPainter()->GetLineColor();
3959  } else {
3960  if (gVirtualPS) {
3961  lws = gVirtualPS->GetLineWidth();
3962  lss = gVirtualPS->GetLineStyle();
3963  lcs = gVirtualPS->GetLineColor();
3964  }
3965  }
3966 
3967  // Change the current line attributes to draw the hatches
3968  if (!gPad->IsBatch()) {
3969  GetPainter()->SetLineStyle(1);
3970  GetPainter()->SetLineWidth(Short_t(lw));
3971  GetPainter()->SetLineColor(GetPainter()->GetFillColor());
3972  }
3973  if (gVirtualPS) {
3974  gVirtualPS->SetLineStyle(1);
3975  gVirtualPS->SetLineWidth(Short_t(lw));
3976  gVirtualPS->SetLineColor(gVirtualPS->GetFillColor());
3977  }
3978 
3979  // Draw the hatches
3980  if (ang1[iAng1] != 5.) PaintHatches(dy, ang1[iAng1], nn, xx, yy);
3981  if (ang2[iAng2] != 5.) PaintHatches(dy, ang2[iAng2], nn, xx, yy);
3982 
3983  // Restore the line attributes
3984  if (!gPad->IsBatch()) {
3985  GetPainter()->SetLineStyle(lss);
3986  GetPainter()->SetLineWidth(lws);
3987  GetPainter()->SetLineColor(lcs);
3988  }
3989  if (gVirtualPS) {
3990  gVirtualPS->SetLineStyle(lss);
3991  gVirtualPS->SetLineWidth(lws);
3992  gVirtualPS->SetLineColor(lcs);
3993  }
3994 }
3995 
3996 ////////////////////////////////////////////////////////////////////////////////
3997 /// This routine draw hatches inclined with the
3998 /// angle "angle" and spaced of "dy" in normalized device
3999 /// coordinates in the surface defined by n,xx,yy.
4000 
4001 void TPad::PaintHatches(Double_t dy, Double_t angle,
4002  Int_t nn, Double_t *xx, Double_t *yy)
4003 {
4004  Int_t i, i1, i2, nbi, m, inv;
4005  Double_t ratiox, ratioy, ymin, ymax, yrot, ycur;
4006  const Double_t angr = TMath::Pi()*(180.-angle)/180.;
4007  const Double_t epsil = 0.0001;
4008  const Int_t maxnbi = 100;
4009  Double_t xli[maxnbi], xlh[2], ylh[2], xt1, xt2, yt1, yt2;
4010  Double_t ll, x, y, x1, x2, y1, y2, a, b, xi, xip, xin, yi, yip;
4011 
4012  Double_t rwxmin = gPad->GetX1();
4013  Double_t rwxmax = gPad->GetX2();
4014  Double_t rwymin = gPad->GetY1();
4015  Double_t rwymax = gPad->GetY2();
4016  ratiox = 1./(rwxmax-rwxmin);
4017  ratioy = 1./(rwymax-rwymin);
4018 
4019  Double_t sina = TMath::Sin(angr), sinb;
4020  Double_t cosa = TMath::Cos(angr), cosb;
4021  if (TMath::Abs(cosa) <= epsil) cosa=0.;
4022  if (TMath::Abs(sina) <= epsil) sina=0.;
4023  sinb = -sina;
4024  cosb = cosa;
4025 
4026  // Values needed to compute the hatches in TRUE normalized space (NDC)
4027  Int_t iw = gPad->GetWw();
4028  Int_t ih = gPad->GetWh();
4029  Double_t x1p,y1p,x2p,y2p;
4030  gPad->GetPadPar(x1p,y1p,x2p,y2p);
4031  iw = (Int_t)(iw*x2p)-(Int_t)(iw*x1p);
4032  ih = (Int_t)(ih*y2p)-(Int_t)(ih*y1p);
4033  Double_t wndc = TMath::Min(1.,(Double_t)iw/(Double_t)ih);
4034  Double_t hndc = TMath::Min(1.,(Double_t)ih/(Double_t)iw);
4035 
4036  // Search ymin and ymax
4037  ymin = 1.;
4038  ymax = 0.;
4039  for (i=1; i<=nn; i++) {
4040  x = wndc*ratiox*(xx[i-1]-rwxmin);
4041  y = hndc*ratioy*(yy[i-1]-rwymin);
4042  yrot = sina*x+cosa*y;
4043  if (yrot > ymax) ymax = yrot;
4044  if (yrot < ymin) ymin = yrot;
4045  }
4046  ymax = (Double_t)((Int_t)(ymax/dy))*dy;
4047 
4048  for (ycur=ymax; ycur>=ymin; ycur=ycur-dy) {
4049  nbi = 0;
4050  for (i=2; i<=nn+1; i++) {
4051  i2 = i;
4052  i1 = i-1;
4053  if (i == nn+1) i2=1;
4054  x1 = wndc*ratiox*(xx[i1-1]-rwxmin);
4055  y1 = hndc*ratioy*(yy[i1-1]-rwymin);
4056  x2 = wndc*ratiox*(xx[i2-1]-rwxmin);
4057  y2 = hndc*ratioy*(yy[i2-1]-rwymin);
4058  xt1 = cosa*x1-sina*y1;
4059  yt1 = sina*x1+cosa*y1;
4060  xt2 = cosa*x2-sina*y2;
4061  yt2 = sina*x2+cosa*y2;
4062 
4063  // Line segment parallel to oy
4064  if (xt1 == xt2) {
4065  if (yt1 < yt2) {
4066  yi = yt1;
4067  yip = yt2;
4068  } else {
4069  yi = yt2;
4070  yip = yt1;
4071  }
4072  if ((yi <= ycur) && (ycur < yip)) {
4073  nbi++;
4074  if (nbi >= maxnbi) return;
4075  xli[nbi-1] = xt1;
4076  }
4077  continue;
4078  }
4079 
4080  // Line segment parallel to ox
4081  if (yt1 == yt2) {
4082  if (yt1 == ycur) {
4083  nbi++;
4084  if (nbi >= maxnbi) return;
4085  xli[nbi-1] = xt1;
4086  nbi++;
4087  if (nbi >= maxnbi) return;
4088  xli[nbi-1] = xt2;
4089  }
4090  continue;
4091  }
4092 
4093  // Other line segment
4094  a = (yt1-yt2)/(xt1-xt2);
4095  b = (yt2*xt1-xt2*yt1)/(xt1-xt2);
4096  if (xt1 < xt2) {
4097  xi = xt1;
4098  xip = xt2;
4099  } else {
4100  xi = xt2;
4101  xip = xt1;
4102  }
4103  xin = (ycur-b)/a;
4104  if ((xi <= xin) && (xin < xip) &&
4105  (TMath::Min(yt1,yt2) <= ycur) &&
4106  (ycur < TMath::Max(yt1,yt2))) {
4107  nbi++;
4108  if (nbi >= maxnbi) return;
4109  xli[nbi-1] = xin;
4110  }
4111  }
4112 
4113  // Sorting of the x coordinates intersections
4114  inv = 0;
4115  m = nbi-1;
4116 L30:
4117  for (i=1; i<=m; i++) {
4118  if (xli[i] < xli[i-1]) {
4119  inv++;
4120  ll = xli[i-1];
4121  xli[i-1] = xli[i];
4122  xli[i] = ll;
4123  }
4124  }
4125  m--;
4126  if (inv == 0) goto L50;
4127  inv = 0;
4128  goto L30;
4129 
4130  // Draw the hatches
4131 L50:
4132  if (nbi%2 != 0) continue;
4133 
4134  for (i=1; i<=nbi; i=i+2) {
4135  // Rotate back the hatches
4136  xlh[0] = cosb*xli[i-1]-sinb*ycur;
4137  ylh[0] = sinb*xli[i-1]+cosb*ycur;
4138  xlh[1] = cosb*xli[i] -sinb*ycur;
4139  ylh[1] = sinb*xli[i] +cosb*ycur;
4140  // Convert hatches' positions from true NDC to WC
4141  xlh[0] = (xlh[0]/wndc)*(rwxmax-rwxmin)+rwxmin;
4142  ylh[0] = (ylh[0]/hndc)*(rwymax-rwymin)+rwymin;
4143  xlh[1] = (xlh[1]/wndc)*(rwxmax-rwxmin)+rwxmin;
4144  ylh[1] = (ylh[1]/hndc)*(rwymax-rwymin)+rwymin;
4145  gPad->PaintLine(xlh[0], ylh[0], xlh[1], ylh[1]);
4146  }
4147  }
4148 }
4149 
4150 ////////////////////////////////////////////////////////////////////////////////
4151 /// Paint line in CurrentPad World coordinates.
4152 
4153 void TPad::PaintLine(Double_t x1, Double_t y1, Double_t x2, Double_t y2)
4154 {
4155  Double_t x[2], y[2];
4156  x[0] = x1; x[1] = x2; y[0] = y1; y[1] = y2;
4157 
4158  //If line is totally clipped, return
4159  if (TestBit(TGraph::kClipFrame)) {
4160  if (Clip(x,y,fUxmin,fUymin,fUxmax,fUymax) == 2) return;
4161  } else {
4162  if (Clip(x,y,fX1,fY1,fX2,fY2) == 2) return;
4163  }
4164 
4165  if (!gPad->IsBatch())
4166  GetPainter()->DrawLine(x[0], y[0], x[1], y[1]);
4167 
4168  if (gVirtualPS) {
4169  gVirtualPS->DrawPS(2, x, y);
4170  }
4171 
4172  Modified();
4173 }
4174 
4175 ////////////////////////////////////////////////////////////////////////////////
4176 /// Paint line in normalized coordinates.
4177 
4178 void TPad::PaintLineNDC(Double_t u1, Double_t v1,Double_t u2, Double_t v2)
4179 {
4180  static Double_t xw[2], yw[2];
4181  if (!gPad->IsBatch())
4182  GetPainter()->DrawLineNDC(u1, v1, u2, v2);
4183 
4184  if (gVirtualPS) {
4185  xw[0] = fX1 + u1*(fX2 - fX1);
4186  xw[1] = fX1 + u2*(fX2 - fX1);
4187  yw[0] = fY1 + v1*(fY2 - fY1);
4188  yw[1] = fY1 + v2*(fY2 - fY1);
4189  gVirtualPS->DrawPS(2, xw, yw);
4190  }
4191 
4192  Modified();
4193 }
4194 
4195 ////////////////////////////////////////////////////////////////////////////////
4196 /// Paint 3-D line in the CurrentPad.
4197 
4198 void TPad::PaintLine3D(Float_t *p1, Float_t *p2)
4199 {
4200  if (!fView) return;
4201 
4202  // convert from 3-D to 2-D pad coordinate system
4203  Double_t xpad[6];
4204  Double_t temp[3];
4205  Int_t i;
4206  for (i=0;i<3;i++) temp[i] = p1[i];
4207  fView->WCtoNDC(temp, &xpad[0]);
4208  for (i=0;i<3;i++) temp[i] = p2[i];
4209  fView->WCtoNDC(temp, &xpad[3]);
4210  PaintLine(xpad[0],xpad[1],xpad[3],xpad[4]);
4211 }
4212 
4213 ////////////////////////////////////////////////////////////////////////////////
4214 /// Paint 3-D line in the CurrentPad.
4215 
4216 void TPad::PaintLine3D(Double_t *p1, Double_t *p2)
4217 {
4218  //take into account perspective view
4219  if (!fView) return;
4220  // convert from 3-D to 2-D pad coordinate system
4221  Double_t xpad[6];
4222  Double_t temp[3];
4223  Int_t i;
4224  for (i=0;i<3;i++) temp[i] = p1[i];
4225  fView->WCtoNDC(temp, &xpad[0]);
4226  for (i=0;i<3;i++) temp[i] = p2[i];
4227  fView->WCtoNDC(temp, &xpad[3]);
4228  PaintLine(xpad[0],xpad[1],xpad[3],xpad[4]);
4229 }
4230 
4231 ////////////////////////////////////////////////////////////////////////////////
4232 /// Paint polyline in CurrentPad World coordinates.
4233 
4234 void TPad::PaintPolyLine(Int_t n, Float_t *x, Float_t *y, Option_t *)
4235 {
4236  if (n < 2) return;
4237 
4238  Double_t xmin,xmax,ymin,ymax;
4239  if (TestBit(TGraph::kClipFrame)) {
4240  xmin = fUxmin; ymin = fUymin; xmax = fUxmax; ymax = fUymax;
4241  } else {
4242  xmin = fX1; ymin = fY1; xmax = fX2; ymax = fY2;
4243  }
4244  Int_t i, i1=-1,np=1;
4245  for (i=0; i<n-1; i++) {
4246  Double_t x1=x[i];
4247  Double_t y1=y[i];
4248  Double_t x2=x[i+1];
4249  Double_t y2=y[i+1];
4250  Int_t iclip = Clip(&x[i],&y[i],xmin,ymin,xmax,ymax);
4251  if (iclip == 2) {
4252  i1 = -1;
4253  continue;
4254  }
4255  np++;
4256  if (i1 < 0) i1 = i;
4257  if (iclip == 0 && i < n-2) continue;
4258  if (!gPad->IsBatch())
4259  GetPainter()->DrawPolyLine(np, &x[i1], &y[i1]);
4260  if (gVirtualPS) {
4261  gVirtualPS->DrawPS(np, &x[i1], &y[i1]);
4262  }
4263  if (iclip) {
4264  x[i] = x1;
4265  y[i] = y1;
4266  x[i+1] = x2;
4267  y[i+1] = y2;
4268  }
4269  i1 = -1;
4270  np = 1;
4271  }
4272 
4273  Modified();
4274 }
4275 
4276 ////////////////////////////////////////////////////////////////////////////////
4277 /// Paint polyline in CurrentPad World coordinates.
4278 ///
4279 /// If option[0] == 'C' no clipping
4280 
4281 void TPad::PaintPolyLine(Int_t n, Double_t *x, Double_t *y, Option_t *option)
4282 {
4283  if (n < 2) return;
4284 
4285  Double_t xmin,xmax,ymin,ymax;
4286  Bool_t mustClip = kTRUE;
4287  if (TestBit(TGraph::kClipFrame)) {
4288  xmin = fUxmin; ymin = fUymin; xmax = fUxmax; ymax = fUymax;
4289  } else {
4290  xmin = fX1; ymin = fY1; xmax = fX2; ymax = fY2;
4291  if (option && (option[0] == 'C')) mustClip = kFALSE;
4292  }
4293 
4294  Int_t i, i1=-1, np=1, iclip=0;
4295 
4296  for (i=0; i < n-1; i++) {
4297  Double_t x1=x[i];
4298  Double_t y1=y[i];
4299  Double_t x2=x[i+1];
4300  Double_t y2=y[i+1];
4301  if (mustClip) {
4302  iclip = Clip(&x[i],&y[i],xmin,ymin,xmax,ymax);
4303  if (iclip == 2) {
4304  i1 = -1;
4305  continue;
4306  }
4307  }
4308  np++;
4309  if (i1 < 0) i1 = i;
4310  if (iclip == 0 && i < n-2) continue;
4311  if (!gPad->IsBatch())
4312  GetPainter()->DrawPolyLine(np, &x[i1], &y[i1]);
4313  if (gVirtualPS) {
4314  gVirtualPS->DrawPS(np, &x[i1], &y[i1]);
4315  }
4316  if (iclip) {
4317  x[i] = x1;
4318  y[i] = y1;
4319  x[i+1] = x2;
4320  y[i+1] = y2;
4321  }
4322  i1 = -1;
4323  np = 1;
4324  }
4325 
4326  Modified();
4327 }
4328 
4329 ////////////////////////////////////////////////////////////////////////////////
4330 /// Paint polyline in CurrentPad NDC coordinates.
4331 
4332 void TPad::PaintPolyLineNDC(Int_t n, Double_t *x, Double_t *y, Option_t *)
4333 {
4334  if (n <=0) return;
4335 
4336  if (!gPad->IsBatch())
4337  GetPainter()->DrawPolyLineNDC(n, x, y);
4338 
4339  if (gVirtualPS) {
4340  Double_t *xw = new Double_t[n];
4341  Double_t *yw = new Double_t[n];
4342  for (Int_t i=0; i<n; i++) {
4343  xw[i] = fX1 + x[i]*(fX2 - fX1);
4344  yw[i] = fY1 + y[i]*(fY2 - fY1);
4345  }
4346  gVirtualPS->DrawPS(n, xw, yw);
4347  delete [] xw;
4348  delete [] yw;
4349  }
4350  Modified();
4351 }
4352 
4353 ////////////////////////////////////////////////////////////////////////////////
4354 /// Paint 3-D polyline in the CurrentPad.
4355 
4356 void TPad::PaintPolyLine3D(Int_t n, Double_t *p)
4357 {
4358  if (!fView) return;
4359 
4360  // Loop on each individual line
4361  for (Int_t i = 1; i < n; i++)
4362  PaintLine3D(&p[3*i-3], &p[3*i]);
4363 
4364  Modified();
4365 }
4366 
4367 ////////////////////////////////////////////////////////////////////////////////
4368 /// Paint polymarker in CurrentPad World coordinates.
4369 
4370 void TPad::PaintPolyMarker(Int_t nn, Float_t *x, Float_t *y, Option_t *)
4371 {
4372  Int_t n = TMath::Abs(nn);
4373  Double_t xmin,xmax,ymin,ymax;
4374  if (nn > 0 || TestBit(TGraph::kClipFrame)) {
4375  xmin = fUxmin; ymin = fUymin; xmax = fUxmax; ymax = fUymax;
4376  } else {
4377  xmin = fX1; ymin = fY1; xmax = fX2; ymax = fY2;
4378  }
4379  Int_t i,i1=-1,np=0;
4380  for (i=0; i<n; i++) {
4381  if (x[i] >= xmin && x[i] <= xmax && y[i] >= ymin && y[i] <= ymax) {
4382  np++;
4383  if (i1 < 0) i1 = i;
4384  if (i < n-1) continue;
4385  }
4386  if (np == 0) continue;
4387  if (!gPad->IsBatch())
4388  GetPainter()->DrawPolyMarker(np, &x[i1], &y[i1]);
4389  if (gVirtualPS) {
4390  gVirtualPS->DrawPolyMarker(np, &x[i1], &y[i1]);
4391  }
4392  i1 = -1;
4393  np = 0;
4394  }
4395  Modified();
4396 }
4397 
4398 ////////////////////////////////////////////////////////////////////////////////
4399 /// Paint polymarker in CurrentPad World coordinates.
4400 
4401 void TPad::PaintPolyMarker(Int_t nn, Double_t *x, Double_t *y, Option_t *)
4402 {
4403  Int_t n = TMath::Abs(nn);
4404  Double_t xmin,xmax,ymin,ymax;
4405  if (nn > 0 || TestBit(TGraph::kClipFrame)) {
4406  xmin = fUxmin; ymin = fUymin; xmax = fUxmax; ymax = fUymax;
4407  } else {
4408  xmin = fX1; ymin = fY1; xmax = fX2; ymax = fY2;
4409  }
4410  Int_t i,i1=-1,np=0;
4411  for (i=0; i<n; i++) {
4412  if (x[i] >= xmin && x[i] <= xmax && y[i] >= ymin && y[i] <= ymax) {
4413  np++;
4414  if (i1 < 0) i1 = i;
4415  if (i < n-1) continue;
4416  }
4417  if (np == 0) continue;
4418  if (!gPad->IsBatch())
4419  GetPainter()->DrawPolyMarker(np, &x[i1], &y[i1]);
4420  if (gVirtualPS) {
4421  gVirtualPS->DrawPolyMarker(np, &x[i1], &y[i1]);
4422  }
4423  i1 = -1;
4424  np = 0;
4425  }
4426  Modified();
4427 }
4428 
4429 ////////////////////////////////////////////////////////////////////////////////
4430 /// Paint text in CurrentPad World coordinates.
4431 
4432 void TPad::PaintText(Double_t x, Double_t y, const char *text)
4433 {
4434  Modified();
4435 
4436  if (!gPad->IsBatch())
4437  GetPainter()->DrawText(x, y, text, TVirtualPadPainter::kClear);
4438 
4439  if (gVirtualPS) gVirtualPS->Text(x, y, text);
4440 }
4441 
4442 ////////////////////////////////////////////////////////////////////////////////
4443 /// Paint text in CurrentPad World coordinates.
4444 
4445 void TPad::PaintText(Double_t x, Double_t y, const wchar_t *text)
4446 {
4447  Modified();
4448 
4449  if (!gPad->IsBatch())
4450  GetPainter()->DrawText(x, y, text, TVirtualPadPainter::kClear);
4451 
4452  if (gVirtualPS) gVirtualPS->Text(x, y, text);
4453 }
4454 
4455 ////////////////////////////////////////////////////////////////////////////////
4456 /// Paint text in CurrentPad NDC coordinates.
4457 
4458 void TPad::PaintTextNDC(Double_t u, Double_t v, const char *text)
4459 {
4460  Modified();
4461 
4462  if (!gPad->IsBatch())
4463  GetPainter()->DrawTextNDC(u, v, text, TVirtualPadPainter::kClear);
4464 
4465  if (gVirtualPS) {
4466  Double_t x = fX1 + u*(fX2 - fX1);
4467  Double_t y = fY1 + v*(fY2 - fY1);
4468  gVirtualPS->Text(x, y, text);
4469  }
4470 }
4471 
4472 ////////////////////////////////////////////////////////////////////////////////
4473 /// Paint text in CurrentPad NDC coordinates.
4474 
4475 void TPad::PaintTextNDC(Double_t u, Double_t v, const wchar_t *text)
4476 {
4477  Modified();
4478 
4479  if (!gPad->IsBatch())
4480  GetPainter()->DrawTextNDC(u, v, text, TVirtualPadPainter::kClear);
4481 
4482  if (gVirtualPS) {
4483  Double_t x = fX1 + u*(fX2 - fX1);
4484  Double_t y = fY1 + v*(fY2 - fY1);
4485  gVirtualPS->Text(x, y, text);
4486  }
4487 }
4488 
4489 ////////////////////////////////////////////////////////////////////////////////
4490 /// Search for an object at pixel position px,py.
4491 ///
4492 /// Check if point is in this pad.
4493 ///
4494 /// If yes, check if it is in one of the sub-pads
4495 ///
4496 /// If found in the pad, compute closest distance of approach
4497 /// to each primitive.
4498 ///
4499 /// If one distance of approach is found to be within the limit Distancemaximum
4500 /// the corresponding primitive is selected and the routine returns.
4501 
4502 TPad *TPad::Pick(Int_t px, Int_t py, TObjLink *&pickobj)
4503 {
4504  //the two following statements are necessary under NT (multithreaded)
4505  //when a TCanvas object is being created and a thread calling TPad::Pick
4506  //before the TPad constructor has completed in the other thread
4507  if (gPad == 0) return 0; //Andy Haas
4508  if (GetListOfPrimitives() == 0) return 0; //Andy Haas
4509 
4510  Int_t dist;
4511  // Search if point is in pad itself
4512  Double_t x = AbsPixeltoX(px);
4513  Double_t y = AbsPixeltoY(py);
4514  if (this != gPad->GetCanvas()) {
4515  if (!((x >= fX1 && x <= fX2) && (y >= fY1 && y <= fY2))) return 0;
4516  }
4517 
4518  // search for a primitive in this pad or its sub-pads
4519  static TObjOptLink dummyLink(0,""); //place holder for when no link available
4520  TPad *padsav = (TPad*)gPad;
4521  gPad = this; // since no drawing will be done, don't use cd() for efficiency reasons
4522  TPad *pick = 0;
4523  TPad *picked = this;
4524  pickobj = 0;
4525  if (DistancetoPrimitive(px,py) < fgMaxPickDistance) {
4526  dummyLink.SetObject(this);
4527  pickobj = &dummyLink;
4528  }
4529 
4530  // Loop backwards over the list of primitives. The first non-pad primitive
4531  // found is the selected one. However, we have to keep going down the
4532  // list to see if there is maybe a pad overlaying the primitive. In that
4533  // case look into the pad for a possible primitive. Once a pad has been
4534  // found we can terminate the loop.
4535  Bool_t gotPrim = kFALSE; // true if found a non pad primitive
4536  TObjLink *lnk = GetListOfPrimitives()->LastLink();
4537 
4538  //We can have 3d stuff in pad. If canvas prefers to draw
4539  //such stuff with OpenGL, the selection of 3d objects is
4540  //a gl viewer business so, in first cycle we do not
4541  //call DistancetoPrimitive for TAtt3D descendants.
4542  //In case of gl we first try to select 2d object first.
4543 
4544  while (lnk) {
4545  TObject *obj = lnk->GetObject();
4546 
4547  //If canvas prefers GL, all 3d objects must be drawn/selected by
4548  //gl viewer
4549  if (obj->InheritsFrom(TAtt3D::Class()) && fEmbeddedGL) {
4550  lnk = lnk->Prev();
4551  continue;
4552  }
4553 
4554  fPadPointer = obj;
4555  if (obj->InheritsFrom(TPad::Class())) {
4556  pick = ((TPad*)obj)->Pick(px, py, pickobj);
4557  if (pick) {
4558  picked = pick;
4559  break;
4560  }
4561  } else if (!gROOT->GetEditorMode()) {
4562  if (!gotPrim) {
4563  if (!obj->TestBit(kCannotPick)) {
4564  dist = obj->DistancetoPrimitive(px, py);
4565  if (dist < fgMaxPickDistance) {
4566  pickobj = lnk;
4567  gotPrim = kTRUE;
4568  if (dist == 0) break;
4569  }
4570  }
4571  }
4572  }
4573 
4574  lnk = lnk->Prev();
4575  }
4576 
4577  //if no primitive found, check if we have a TView
4578  //if yes, return the view except if you are in the lower or upper X range
4579  //of the pad.
4580  //In case canvas prefers gl, fView existence
4581  //automatically means viewer3d existence. (?)
4582 
4583  if (fView && !gotPrim) {
4584  Double_t dx = 0.05*(fUxmax-fUxmin);
4585  if ((x > fUxmin + dx) && (x < fUxmax-dx)) {
4586 
4587  if (fEmbeddedGL) {
4588  //No 2d stuff was selected, but we have gl-viewer. Let it select an object in
4589  //scene (or select itself). In any case it'll internally call
4590  //gPad->SetSelected(ptr) as, for example, hist painter does.
4591  py -= Int_t((1 - GetHNDC() - GetYlowNDC()) * GetWh());
4592  px -= Int_t(GetXlowNDC() * GetWw());
4593  fViewer3D->DistancetoPrimitive(px, py);
4594  }
4595  else
4596  dummyLink.SetObject(fView);
4597  }
4598  }
4599 
4600  if (picked->InheritsFrom(TButton::Class())) {
4601  TButton *button = (TButton*)picked;
4602  if (!button->IsEditable()) pickobj = 0;
4603  }
4604 
4605  if (TestBit(kCannotPick)) {
4606 
4607  if (picked == this) {
4608  // cannot pick pad itself!
4609  picked = 0;
4610  }
4611 
4612  }
4613 
4614  gPad = padsav;
4615  return picked;
4616 }
4617 
4618 ////////////////////////////////////////////////////////////////////////////////
4619 /// Pop pad to the top of the stack.
4620 
4621 void TPad::Pop()
4622 {
4623  if (!fMother) return;
4624  if (!fMother->TestBit(kNotDeleted)) return;
4625  if (!fPrimitives) fPrimitives = new TList;
4626  if (this == fMother->GetListOfPrimitives()->Last()) return;
4627 
4628  TListIter next(fMother->GetListOfPrimitives());
4629  TObject *obj;
4630  while ((obj = next()))
4631  if (obj == this) {
4632  char *opt = StrDup(next.GetOption());
4633  fMother->GetListOfPrimitives()->Remove(this);
4634  fMother->GetListOfPrimitives()->AddLast(this, opt);
4635  delete [] opt;
4636  return;
4637  }
4638 }
4639 
4640 ////////////////////////////////////////////////////////////////////////////////
4641 /// Save Pad contents in a file in one of various formats.
4642 ///
4643 /// - if filename is "", the file produced is padname.ps
4644 /// - if filename starts with a dot, the padname is added in front
4645 /// - if filename contains .eps, an Encapsulated Postscript file is produced
4646 /// - if filename contains .gif, a GIF file is produced
4647 /// - if filename contains .gif+NN, an animated GIF file is produced
4648 /// See comments in TASImage::WriteImage for meaning of NN and other
4649 /// .gif suffix variants
4650 /// - if filename contains .C or .cxx, a C++ macro file is produced
4651 /// - if filename contains .root, a Root file is produced
4652 /// - if filename contains .xml, a XML file is produced
4653 /// - if filename contains .json, a JSON file is produced
4654 ///
4655 /// See comments in TPad::SaveAs or the TPad::Print function below
4656 
4657 void TPad::Print(const char *filename) const
4658 {
4659  ((TPad*)this)->SaveAs(filename);
4660 }
4661 
4662 ////////////////////////////////////////////////////////////////////////////////
4663 /// Auxiliary function. Returns kTRUE if list contains an object inherited
4664 /// from TImage
4665 
4666 static Bool_t ContainsTImage(TList *li)
4667 {
4668  TIter next(li);
4669  TObject *obj;
4670 
4671  while ((obj = next())) {
4672  if (obj->InheritsFrom(TImage::Class())) {
4673  return kTRUE;
4674  } else if (obj->InheritsFrom(TPad::Class())) {
4675  if (ContainsTImage(((TPad*)obj)->GetListOfPrimitives())) {
4676  return kTRUE;
4677  }
4678  }
4679  }
4680  return kFALSE;
4681 }
4682 
4683 ////////////////////////////////////////////////////////////////////////////////
4684 /// Save Canvas contents in a file in one of various formats.
4685 ///
4686 /// option can be:
4687 /// - 0 as "ps"
4688 /// - "ps" Postscript file is produced (see special cases below)
4689 /// - "Portrait" Postscript file is produced (Portrait)
4690 /// - "Landscape" Postscript file is produced (Landscape)
4691 /// - "Title:" The character string after "Title:" becomes a table
4692 /// of content entry (for PDF files).
4693 /// - "eps" an Encapsulated Postscript file is produced
4694 /// - "Preview" an Encapsulated Postscript file with preview is produced.
4695 /// - "EmbedFonts" a PDF file with embedded fonts is generated.
4696 /// - "pdf" a PDF file is produced
4697 /// - "svg" a SVG file is produced
4698 /// - "tex" a TeX file is produced
4699 /// - "gif" a GIF file is produced
4700 /// - "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
4701 /// - "xpm" a XPM file is produced
4702 /// - "png" a PNG file is produced
4703 /// - "jpg" a JPEG file is produced. NOTE: JPEG's lossy compression will make all sharp edges fuzzy.
4704 /// - "tiff" a TIFF file is produced
4705 /// - "cxx" a C++ macro file is produced
4706 /// - "xml" a XML file
4707 /// - "json" a JSON file
4708 /// - "root" a ROOT binary file
4709 ///
4710 /// filename = 0 - filename is defined by the GetName and its
4711 /// extension is defined with the option
4712 ///
4713 /// When Postscript output is selected (ps, eps), the canvas is saved
4714 /// to filename.ps or filename.eps. The aspect ratio of the canvas is preserved
4715 /// on the Postscript file. When the "ps" option is selected, the Postscript
4716 /// page will be landscape format if the canvas is in landscape format, otherwise
4717 /// portrait format is selected.
4718 ///
4719 /// The physical size of the Postscript page is the one selected in the
4720 /// current style. This size can be modified via TStyle::SetPaperSize.
4721 ///
4722 /// Examples:
4723 /// ~~~ {.cpp}
4724 /// gStyle->SetPaperSize(TStyle::kA4); //default
4725 /// gStyle->SetPaperSize(TStyle::kUSLetter);
4726 /// ~~~
4727 /// where TStyle::kA4 and TStyle::kUSLetter are defined in the enum
4728 /// EPaperSize in TStyle.h
4729 ///
4730 /// An alternative is to call:
4731 /// ~~~ {.cpp}
4732 /// gStyle->SetPaperSize(20,26); same as kA4
4733 /// or gStyle->SetPaperSize(20,24); same as kUSLetter
4734 /// ~~~
4735 /// The above numbers take into account some margins and are in centimeters.
4736 ///
4737 /// ### The "Preview" option
4738 ///
4739 /// The "Preview" option allows to generate a preview (in the TIFF format) within
4740 /// the Encapsulated Postscript file. This preview can be used by programs like
4741 /// MSWord to visualize the picture on screen. The "Preview" option relies on the
4742 /// "epstool" command (http://www.cs.wisc.edu/~ghost/gsview/epstool.htm).
4743 ///
4744 /// Example:
4745 /// ~~~ {.cpp}
4746 /// canvas->Print("example.eps","Preview");
4747 /// ~~~
4748 ///
4749 /// ### The "EmbedFonts" option
4750 ///
4751 /// The "EmbedFonts" option allows to embed the fonts used in a PDF file inside
4752 /// that file. This option relies on the "gs" command (https://ghostscript.com).
4753 ///
4754 /// Example:
4755 /// ~~~ {.cpp}
4756 /// canvas->Print("example.pdf","EmbedFonts");
4757 /// ~~~
4758 ///
4759 /// ### Writing several canvases to the same Postscript or PDF file:
4760 ///
4761 /// - if the Postscript or PDF file name finishes with "(", the file is not closed
4762 /// - if the Postscript or PDF file name finishes with ")" and the file has been opened
4763 /// with "(", the file is closed.
4764 ///
4765 /// Example:
4766 /// ~~~ {.cpp}
4767 /// {
4768 /// TCanvas c1("c1");
4769 /// h1.Draw();
4770 /// c1.Print("c1.ps("); //write canvas and keep the ps file open
4771 /// h2.Draw();
4772 /// c1.Print("c1.ps"); canvas is added to "c1.ps"
4773 /// h3.Draw();
4774 /// c1.Print("c1.ps)"); canvas is added to "c1.ps" and ps file is closed
4775 /// }
4776 /// ~~~
4777 /// In the previous example replacing "ps" by "pdf" will create a multi-pages PDF file.
4778 ///
4779 /// Note that the following sequence writes the canvas to "c1.ps" and closes the ps file.:
4780 /// ~~~ {.cpp}
4781 /// TCanvas c1("c1");
4782 /// h1.Draw();
4783 /// c1.Print("c1.ps");
4784 /// ~~~
4785 /// The TCanvas::Print("file.ps(") mechanism is very useful, but it can be
4786 /// a little inconvenient to have the action of opening/closing a file
4787 /// being atomic with printing a page. Particularly if pages are being
4788 /// generated in some loop one needs to detect the special cases of first
4789 /// and last page and then munge the argument to Print() accordingly.
4790 ///
4791 /// The "[" and "]" can be used instead of "(" and ")".
4792 ///
4793 /// Example:
4794 /// ~~~ {.cpp}
4795 /// c1.Print("file.ps["); // No actual print, just open file.ps
4796 /// for (int i=0; i<10; ++i) {
4797 /// // fill canvas for context i
4798 /// // ...
4799 ///
4800 /// c1.Print("file.ps"); // actually print canvas to file
4801 /// }// end loop
4802 /// c1.Print("file.ps]"); // No actual print, just close.
4803 /// ~~~
4804 /// As before, the same macro is valid for PDF files.
4805 ///
4806 /// It is possible to print a canvas into an animated GIF file by specifying the
4807 /// file name as "myfile.gif+" or "myfile.gif+NN", where NN*10ms is delay
4808 /// between the subimages' display. If NN is omitted the delay between
4809 /// subimages is zero. Each picture is added in the animation thanks to a loop
4810 /// similar to the following one:
4811 /// ~~~ {.cpp}
4812 /// for (int i=0; i<10; ++i) {
4813 /// // fill canvas for context i
4814 /// // ...
4815 ///
4816 /// c1.Print("file.gif+5"); // print canvas to GIF file with 50ms delays
4817 /// }// end loop
4818 /// ~~~
4819 /// The delay between each frame must be specified in each Print() statement.
4820 /// If the file "myfile.gif" already exists, the new frame are appended at
4821 /// the end of the file. To avoid this, delete it first with gSystem->Unlink(myfile.gif);
4822 /// If you want the gif file to repeat or loop forever, check TASImage::WriteImage documentation
4823 
4824 void TPad::Print(const char *filenam, Option_t *option)
4825 {
4826  TString psname, fs1 = filenam;
4827 
4828  // "[" and "]" are special characters for ExpandPathName. When they are at the end
4829  // of the file name (see help) they must be removed before doing ExpandPathName.
4830  if (fs1.EndsWith("[")) {
4831  fs1.Replace((fs1.Length()-1),1," ");
4832  gSystem->ExpandPathName(fs1);
4833  fs1.Replace((fs1.Length()-1),1,"[");
4834  } else if (fs1.EndsWith("]")) {
4835  fs1.Replace((fs1.Length()-1),1," ");
4836  gSystem->ExpandPathName(fs1);
4837  fs1.Replace((fs1.Length()-1),1,"]");
4838  } else {
4839  gSystem->ExpandPathName(fs1);
4840  }
4841 
4842  // Set the default option as "Postscript" (Should be a data member of TPad)
4843  const char *opt_default = "ps";
4844 
4845  TString opt = !option ? opt_default : option;
4846  Bool_t image = kFALSE;
4847 
4848  if (!fs1.Length()) {
4849  psname = GetName();
4850  psname += opt;
4851  } else {
4852  psname = fs1;
4853  }
4854 
4855  // lines below protected against case like c1->SaveAs( "../ps/cs.ps" );
4856  if (psname.BeginsWith('.') && (psname.Contains('/') == 0)) {
4857  psname = GetName();
4858  psname.Append(fs1);
4859  psname.Prepend("/");
4860  psname.Prepend(gEnv->GetValue("Canvas.PrintDirectory","."));
4861  }
4862  if (!gPad->IsBatch() && fCanvas)
4863  GetPainter()->SelectDrawable(GetCanvasID());
4864 
4865  // Save pad/canvas in alternative formats
4866  TImage::EImageFileTypes gtype = TImage::kUnknown;
4867  if (strstr(opt, "gif+")) {
4868  gtype = TImage::kAnimGif;
4869  image = kTRUE;
4870  } else if (strstr(opt, "gif")) {
4871  gtype = TImage::kGif;
4872  image = kTRUE;
4873  } else if (strstr(opt, "png")) {
4874  gtype = TImage::kPng;
4875  image = kTRUE;
4876  } else if (strstr(opt, "jpg")) {
4877  gtype = TImage::kJpeg;
4878  image = kTRUE;
4879  } else if (strstr(opt, "tiff")) {
4880  gtype = TImage::kTiff;
4881  image = kTRUE;
4882  } else if (strstr(opt, "xpm")) {
4883  gtype = TImage::kXpm;
4884  image = kTRUE;
4885  } else if (strstr(opt, "bmp")) {
4886  gtype = TImage::kBmp;
4887  image = kTRUE;
4888  }
4889 
4890  Int_t wid = 0;
4891  if (!GetCanvas()) return;
4892  if (!gROOT->IsBatch() && image) {
4893  if ((gtype == TImage::kGif) && !ContainsTImage(fPrimitives)) {
4894  wid = (this == GetCanvas()) ? GetCanvas()->GetCanvasID() : GetPixmapID();
4895  Color_t hc = gPad->GetCanvas()->GetHighLightColor();
4896  gPad->GetCanvas()->SetHighLightColor(-1);
4897  gPad->Modified();
4898  gPad->Update();
4899  GetPainter()->SelectDrawable(wid);
4900  GetPainter()->SaveImage(this, psname.Data(), gtype);
4901  if (!gSystem->AccessPathName(psname.Data())) {
4902  Info("Print", "GIF file %s has been created", psname.Data());
4903  }
4904  gPad->GetCanvas()->SetHighLightColor(hc);
4905  return;
4906  }
4907  if (gtype != TImage::kUnknown) {
4908  Color_t hc = gPad->GetCanvas()->GetHighLightColor();
4909  gPad->GetCanvas()->SetHighLightColor(-1);
4910  gPad->Modified();
4911  gPad->Update();
4912  gVirtualX->Update(1);
4913  gSystem->Sleep(30); // synchronize
4914  GetPainter()->SaveImage(this, psname, gtype);
4915  if (!gSystem->AccessPathName(psname)) {
4916  Info("Print", "file %s has been created", psname.Data());
4917  }
4918  gPad->GetCanvas()->SetHighLightColor(hc);
4919  } else {
4920  Warning("Print", "Unsupported image format %s", psname.Data());
4921  }
4922  return;
4923  }
4924 
4925  //==============Save pad/canvas as a C++ script==============================
4926  if (strstr(opt,"cxx")) {
4927  GetCanvas()->SaveSource(psname, "");
4928  return;
4929  }
4930 
4931  //==============Save pad/canvas as a root file===============================
4932  if (strstr(opt,"root")) {
4933  if (gDirectory) gDirectory->SaveObjectAs(this,psname.Data(),"");
4934  return;
4935  }
4936 
4937  //==============Save pad/canvas as a XML file================================
4938  if (strstr(opt,"xml")) {
4939  // Plugin XML driver
4940  if (gDirectory) gDirectory->SaveObjectAs(this,psname.Data(),"");
4941  return;
4942  }
4943 
4944  //==============Save pad/canvas as a JSON file================================
4945  if (strstr(opt,"json")) {
4946  if (gDirectory) gDirectory->SaveObjectAs(this,psname.Data(),"");
4947  return;
4948  }
4949 
4950  //==============Save pad/canvas as a SVG file================================
4951  if (strstr(opt,"svg")) {
4952  gVirtualPS = (TVirtualPS*)gROOT->GetListOfSpecials()->FindObject(psname);
4953 
4954  Bool_t noScreen = kFALSE;
4955  if (!GetCanvas()->IsBatch() && GetCanvas()->GetCanvasID() == -1) {
4956  noScreen = kTRUE;
4957  GetCanvas()->SetBatch(kTRUE);
4958  }
4959 
4960  TPad *padsav = (TPad*)gPad;
4961  cd();
4962 
4963  if (!gVirtualPS) {
4964  // Plugin Postscript/SVG driver
4965  TPluginHandler *h;
4966  if ((h = gROOT->GetPluginManager()->FindHandler("TVirtualPS", "svg"))) {
4967  if (h->LoadPlugin() == -1)
4968  return;
4969  h->ExecPlugin(0);
4970  }
4971  }
4972 
4973  // Create a new SVG file
4974  if (gVirtualPS) {
4975  gVirtualPS->SetName(psname);
4976  gVirtualPS->Open(psname);
4977  gVirtualPS->SetBit(kPrintingPS);
4978  gVirtualPS->NewPage();
4979  }
4980  Paint();
4981  if (noScreen) GetCanvas()->SetBatch(kFALSE);
4982 
4983  if (!gSystem->AccessPathName(psname)) Info("Print", "SVG file %s has been created", psname.Data());
4984 
4985  delete gVirtualPS;
4986  gVirtualPS = 0;
4987  padsav->cd();
4988 
4989  return;
4990  }
4991 
4992  //==============Save pad/canvas as a TeX file================================
4993  if (strstr(opt,"tex")) {
4994  gVirtualPS = (TVirtualPS*)gROOT->GetListOfSpecials()->FindObject(psname);
4995 
4996  Bool_t noScreen = kFALSE;
4997  if (!GetCanvas()->IsBatch() && GetCanvas()->GetCanvasID() == -1) {
4998  noScreen = kTRUE;
4999  GetCanvas()->SetBatch(kTRUE);
5000  }
5001 
5002  TPad *padsav = (TPad*)gPad;
5003  cd();
5004 
5005  if (!gVirtualPS) {
5006  // Plugin Postscript/SVG driver
5007  TPluginHandler *h;
5008  if ((h = gROOT->GetPluginManager()->FindHandler("TVirtualPS", "tex"))) {
5009  if (h->LoadPlugin() == -1)
5010  return;
5011  h->ExecPlugin(0);
5012  }
5013  }
5014 
5015  // Create a new TeX file
5016  if (gVirtualPS) {
5017  gVirtualPS->SetName(psname);
5018  gVirtualPS->Open(psname);
5019  gVirtualPS->SetBit(kPrintingPS);
5020  gVirtualPS->NewPage();
5021  }
5022  Paint();
5023  if (noScreen) GetCanvas()->SetBatch(kFALSE);
5024 
5025  if (!gSystem->AccessPathName(psname)) Info("Print", "TeX file %s has been created", psname.Data());
5026 
5027  delete gVirtualPS;
5028  gVirtualPS = 0;
5029  padsav->cd();
5030 
5031  return;
5032  }
5033 
5034  //==============Save pad/canvas as a Postscript file=========================
5035 
5036  // in case we read directly from a Root file and the canvas
5037  // is not on the screen, set batch mode
5038 
5039  Bool_t mustOpen = kTRUE;
5040  Bool_t mustClose = kTRUE;
5041  Bool_t copen=kFALSE, cclose=kFALSE, copenb=kFALSE, ccloseb=kFALSE;
5042  if (!image) {
5043  // The parenthesis mechanism is only valid for PS and PDF files.
5044  copen = psname.EndsWith("("); if (copen) psname[psname.Length()-1] = 0;
5045  cclose = psname.EndsWith(")"); if (cclose) psname[psname.Length()-1] = 0;
5046  copenb = psname.EndsWith("["); if (copenb) psname[psname.Length()-1] = 0;
5047  ccloseb = psname.EndsWith("]"); if (ccloseb) psname[psname.Length()-1] = 0;
5048  }
5049  gVirtualPS = (TVirtualPS*)gROOT->GetListOfSpecials()->FindObject(psname);
5050  if (gVirtualPS) {mustOpen = kFALSE; mustClose = kFALSE;}
5051  if (copen || copenb) mustClose = kFALSE;
5052  if (cclose || ccloseb) mustClose = kTRUE;
5053 
5054  Bool_t noScreen = kFALSE;
5055  if (!GetCanvas()->IsBatch() && GetCanvas()->GetCanvasID() == -1) {
5056  noScreen = kTRUE;
5057  GetCanvas()->SetBatch(kTRUE);
5058  }
5059  Int_t pstype = 111;
5060  Double_t xcanvas = GetCanvas()->XtoPixel(GetCanvas()->GetX2());
5061  Double_t ycanvas = GetCanvas()->YtoPixel(GetCanvas()->GetY1());
5062  Double_t ratio = ycanvas/xcanvas;
5063  if (ratio < 1) pstype = 112;
5064  if (strstr(opt,"Portrait")) pstype = 111;
5065  if (strstr(opt,"Landscape")) pstype = 112;
5066  if (strstr(opt,"eps")) pstype = 113;
5067  if (strstr(opt,"Preview")) pstype = 113;
5068  TPad *padsav = (TPad*)gPad;
5069  cd();
5070  TVirtualPS *psave = gVirtualPS;
5071 
5072  if (!gVirtualPS || mustOpen) {
5073  // Plugin Postscript driver
5074  TPluginHandler *h;
5075  if (strstr(opt,"pdf") || strstr(opt,"Title:") || strstr(opt,"EmbedFonts")) {
5076  if ((h = gROOT->GetPluginManager()->FindHandler("TVirtualPS", "pdf"))) {
5077  if (h->LoadPlugin() == -1) return;
5078  h->ExecPlugin(0);
5079  }
5080  } else if (image) {
5081  // Plugin TImageDump driver
5082  if ((h = gROOT->GetPluginManager()->FindHandler("TVirtualPS", "image"))) {
5083  if (h->LoadPlugin() == -1) return;
5084  h->ExecPlugin(0);
5085  }
5086  } else {
5087  if ((h = gROOT->GetPluginManager()->FindHandler("TVirtualPS", "ps"))) {
5088  if (h->LoadPlugin() == -1) return;
5089  h->ExecPlugin(0);
5090  }
5091  }
5092 
5093  // Create a new Postscript, PDF or image file
5094  if (gVirtualPS) gVirtualPS->SetName(psname);
5095  const Ssiz_t titlePos = opt.Index("Title:");
5096  if (titlePos != kNPOS) {
5097  if (gVirtualPS) gVirtualPS->SetTitle(opt.Data()+titlePos+6);
5098  opt.Replace(titlePos,opt.Length(),"pdf");
5099  }
5100  if (gVirtualPS) gVirtualPS->Open(psname,pstype);
5101  if (gVirtualPS) gVirtualPS->SetBit(kPrintingPS);
5102  if (!copenb) {
5103  if (!strstr(opt,"pdf") || image) {
5104  if (gVirtualPS) gVirtualPS->NewPage();
5105  }
5106  Paint();
5107  }
5108  if (noScreen) GetCanvas()->SetBatch(kFALSE);
5109 
5110  if (mustClose) {
5111  gROOT->GetListOfSpecials()->Remove(gVirtualPS);
5112  delete gVirtualPS;
5113  gVirtualPS = psave;
5114  } else {
5115  gROOT->GetListOfSpecials()->Add(gVirtualPS);
5116  gVirtualPS = 0;
5117  }
5118 
5119  if (!gSystem->AccessPathName(psname)) {
5120  if (!copen) Info("Print", "%s file %s has been created", opt.Data(), psname.Data());
5121  else Info("Print", "%s file %s has been created using the current canvas", opt.Data(), psname.Data());
5122  }
5123  } else {
5124  // Append to existing Postscript, PDF or GIF file
5125  if (!ccloseb) {
5126  gVirtualPS->NewPage();
5127  Paint();
5128  }
5129  const Ssiz_t titlePos = opt.Index("Title:");
5130  if (titlePos != kNPOS) {
5131  gVirtualPS->SetTitle(opt.Data()+titlePos+6);
5132  opt.Replace(titlePos,opt.Length(),"pdf");
5133  } else {
5134  gVirtualPS->SetTitle("PDF");
5135  }
5136  if (mustClose) {
5137  if (cclose) Info("Print", "Current canvas added to %s file %s and file closed", opt.Data(), psname.Data());
5138  else Info("Print", "%s file %s has been closed", opt.Data(), psname.Data());
5139  gROOT->GetListOfSpecials()->Remove(gVirtualPS);
5140  delete gVirtualPS;
5141  gVirtualPS = 0;
5142  } else {
5143  Info("Print", "Current canvas added to %s file %s", opt.Data(), psname.Data());
5144  gVirtualPS = 0;
5145  }
5146  }
5147 
5148  if (strstr(opt,"Preview")) gSystem->Exec(Form("epstool --quiet -t6p %s %s",psname.Data(),psname.Data()));
5149  if (strstr(opt,"EmbedFonts")) {
5150  gSystem->Exec(Form("gs -quiet -dSAFER -dNOPLATFONTS -dNOPAUSE -dBATCH -sDEVICE=pdfwrite -dUseCIEColor -dCompatibilityLevel=1.4 -dPDFSETTINGS=/printer -dCompatibilityLevel=1.4 -dMaxSubsetPct=100 -dSubsetFonts=true -dEmbedAllFonts=true -sOutputFile=pdf_temp.pdf -f %s",
5151  psname.Data()));
5152  gSystem->Rename("pdf_temp.pdf", psname.Data());
5153  }
5154 
5155  padsav->cd();
5156 }
5157 
5158 ////////////////////////////////////////////////////////////////////////////////
5159 /// Set world coordinate system for the pad.
5160 /// Emits signal "RangeChanged()", in the slot get the range
5161 /// via GetRange().
5162 
5163 void TPad::Range(Double_t x1, Double_t y1, Double_t x2, Double_t y2)
5164 {
5165  if ((x1 >= x2) || (y1 >= y2)) {
5166  Error("Range", "illegal world coordinates range: x1=%f, y1=%f, x2=%f, y2=%f",x1,y1,x2,y2);
5167  return;
5168  }
5169 
5170  fUxmin = x1;
5171  fUxmax = x2;
5172  fUymin = y1;
5173  fUymax = y2;
5174 
5175  if (fX1 == x1 && fY1 == y1 && fX2 == x2 && fY2 == y2) return;
5176 
5177  fX1 = x1;
5178  fY1 = y1;
5179  fX2 = x2;
5180  fY2 = y2;
5181 
5182  // compute pad conversion coefficients
5183  ResizePad();
5184 
5185  if (gPad == this)
5186  GetPainter()->InvalidateCS();
5187 
5188  // emit signal
5189  RangeChanged();
5190 }
5191 
5192 ////////////////////////////////////////////////////////////////////////////////
5193 /// Set axis coordinate system for the pad.
5194 /// The axis coordinate system is a subset of the world coordinate system
5195 /// xmin,ymin is the origin of the current coordinate system,
5196 /// xmax is the end of the X axis, ymax is the end of the Y axis.
5197 /// By default a margin of 10 per cent is left on all sides of the pad
5198 /// Emits signal "RangeAxisChanged()", in the slot get the axis range
5199 /// via GetRangeAxis().
5200 
5201 void TPad::RangeAxis(Double_t xmin, Double_t ymin, Double_t xmax, Double_t ymax)
5202 {
5203  if ((xmin >= xmax) || (ymin >= ymax)) {
5204  Error("RangeAxis", "illegal axis coordinates range: xmin=%f, ymin=%f, xmax=%f, ymax=%f",
5205  xmin, ymin, xmax, ymax);
5206  return;
5207  }
5208 
5209  fUxmin = xmin;
5210  fUymin = ymin;
5211  fUxmax = xmax;
5212  fUymax = ymax;
5213 
5214  // emit signal
5215  RangeAxisChanged();
5216 }
5217 
5218 ////////////////////////////////////////////////////////////////////////////////
5219 /// Recursively remove object from a pad and its sub-pads.
5220 
5221 void TPad::RecursiveRemove(TObject *obj)
5222 {
5223  if (obj == fCanvas->GetSelected()) fCanvas->SetSelected(0);
5224  if (obj == fCanvas->GetClickSelected()) fCanvas->SetClickSelected(0);
5225  if (obj == fView) fView = nullptr;
5226  if (!fPrimitives) return;
5227  Int_t nold = fPrimitives->GetSize();
5228  fPrimitives->RecursiveRemove(obj);
5229  if (nold != fPrimitives->GetSize()) fModified = kTRUE;
5230 }
5231 
5232 ////////////////////////////////////////////////////////////////////////////////
5233 /// Redraw the frame axis
5234 /// Redrawing axis may be necessary in case of superimposed histograms
5235 /// when one or more histograms have a fill color
5236 /// Instead of calling this function, it may be more convenient
5237 /// to call directly h1->Draw("sameaxis") where h1 is the pointer
5238 /// to the first histogram drawn in the pad.
5239 ///
5240 /// By default, if the pad has the options gridx or/and gridy activated,
5241 /// the grid is not drawn by this function.
5242 /// if option="g" is specified, this will force the drawing of the grid
5243 /// on top of the picture
5244 
5245 void TPad::RedrawAxis(Option_t *option)
5246 {
5247  // get first histogram in the list of primitives
5248  TString opt = option;
5249  opt.ToLower();
5250 
5251  TPad *padsav = (TPad*)gPad;
5252  cd();
5253 
5254  if (!fPrimitives) fPrimitives = new TList;
5255  TIter next(fPrimitives);
5256  TObject *obj;
5257  while ((obj = next())) {
5258  if (obj->InheritsFrom(TH1::Class())) {
5259  TH1 *hobj = (TH1*)obj;
5260  if (opt.Contains("g")) hobj->DrawCopy("sameaxig");
5261  else hobj->DrawCopy("sameaxis");
5262  return;
5263  }
5264  if (obj->InheritsFrom(TMultiGraph::Class())) {
5265  TMultiGraph *mg = (TMultiGraph*)obj;
5266  if (mg) {
5267  TH1F *h1f = mg->GetHistogram();
5268  if (h1f) h1f->DrawCopy("sameaxis");
5269  }
5270  return;
5271  }
5272  if (obj->InheritsFrom(TGraph::Class())) {
5273  TGraph *g = (TGraph*)obj;
5274  if (g) g->GetHistogram()->DrawCopy("sameaxis");
5275  return;
5276  }
5277  if (obj->InheritsFrom(THStack::Class())) {
5278  THStack *hs = (THStack*)obj;
5279  if (hs) {
5280  TH1 *h1 = hs->GetHistogram();
5281  if (h1) h1->DrawCopy("sameaxis");
5282  }
5283  return;
5284  }
5285  }
5286 
5287  if (padsav) padsav->cd();
5288 }
5289 
5290 ////////////////////////////////////////////////////////////////////////////////
5291 /// Compute pad conversion coefficients.
5292 ///
5293 /// ### Conversion from x to px
5294 ///
5295 /// \f[\frac{x-xmin}{xrange} = \frac{px-pxlow}{pxrange}\f]
5296 /// with:
5297 /// \f[ xrange = xmax-xmin \f]
5298 /// \f[ pxrange = pxmax-pxmin \f]
5299 ///
5300 /// \f[
5301 /// \Rightarrow px = \frac{pxrange(x-xmin)}{xrange} + pxlow = fXtoPixelk + fXtoPixel \times x
5302 /// \f]
5303 ///
5304 /// \f[
5305 /// \Rightarrow fXtoPixelk = pxlow - pxrange \frac{xmin}{xrange}
5306 /// \f]
5307 /// \f[
5308 /// fXtoPixel = \frac{pxrange}{xrange}
5309 /// \f]
5310 /// where:
5311 /// \f[
5312 /// pxlow = fAbsXlowNDC \times fCw
5313 /// \f]
5314 /// \f[
5315 /// pxrange = fAbsWNDC \times fCw
5316 /// \f]
5317 ///
5318 /// ### Conversion from y to py
5319 ///
5320 /// \f[\frac{y-ymin}{yrange} = \frac{py-pylow}{pyrange}\f]
5321 /// with:
5322 /// \f[ yrange = ymax-ymin \f]
5323 /// \f[ pyrange = pymax-pymin \f]
5324 ///
5325 /// \f[
5326 /// \Rightarrow py = \frac{pyrange(y-xmin)}{yrange} + pylow = fYtoPixelk + fYtoPixel \times y
5327 /// \f]
5328 ///
5329 /// \f[
5330 /// \Rightarrow fYtoPixelk = pylow - pyrange \frac{ymin}{yrange}
5331 /// \f]
5332 /// \f[
5333 /// fYtoPixel = \frac{pyrange}{yrange}
5334 /// \f]
5335 /// where:
5336 /// \f[
5337 /// pylow = fAbsYlowNDC \times fCh
5338 /// \f]
5339 /// \f[
5340 /// pyrange = fAbsHNDC \times fCh
5341 /// \f]
5342 ///
5343 /// ### Conversion from px to x
5344 ///
5345 /// \f[
5346 /// \Rightarrow x = \frac{xrange(px-pxlow)}{pxrange}+ xmin = fPixeltoXk + fPixeltoX \times px
5347 /// \f]
5348 ///
5349 /// \f[
5350 /// \Rightarrow fPixeltoXk = xmin - pxlow \times\frac{xrange}{pxrange}
5351 /// \f]
5352 /// \f[
5353 /// fPixeltoX = \frac{xrange}{pxrange}
5354 /// \f]
5355 ///
5356 /// ### Conversion from py to y
5357 ///
5358 /// \f[
5359 /// \Rightarrow y = \frac{yrange(py-pylow)}{pyrange}+ ymin = fPixeltoYk + fPixeltoY \times py
5360 /// \f]
5361 ///
5362 /// \f[
5363 /// \Rightarrow fPixeltoYk = ymin - pylow \times\frac{yrange}{pyrange}
5364 /// \f]
5365 /// \f[
5366 /// fPixeltoY = \frac{yrange}{pyrange}
5367 /// \f]
5368 ///
5369 /// ### Computation of the coefficients in case of LOG scales
5370 ///
5371 /// #### Conversion from pixel coordinates to world coordinates
5372 ///
5373 /// \f[
5374 /// u = \frac{Log(x) - Log(xmin)}{Log(xmax) - Log(xmin)} = \frac{Log(x/xmin)}{Log(xmax/xmin)} = \frac{px - pxlow}{pxrange}
5375 /// \f]
5376 ///
5377 /// \f[ \Rightarrow Log(\frac{x}{xmin}) = u \times Log(\frac{xmax}{xmin}) \f]
5378 /// \f[ x = xmin \times e^{(u \times Log(\frac{xmax}{xmin})} \f]
5379 /// Let:
5380 /// \f[ alfa = \frac{Log(\frac{xmax}{xmin})}{fAbsWNDC} \f]
5381 ///
5382 /// \f[ x = xmin \times e^{(-alfa \times pxlow)} + e^{(alfa \times px)} \f]
5383 /// \f[ x = fPixeltoXk \times e^{(fPixeltoX \times px)} \f]
5384 /// \f[ ==> fPixeltoXk = xmin \times e^{(-alfa*pxlow)} \f]
5385 /// \f[ fPixeltoX = alfa \f]
5386 ///
5387 /// \f[
5388 /// v = \frac{Log(y) - Log(ymin)}{Log(ymax) - Log(ymin)} = \frac{Log(y/ymin)}{Log(ymax/ymin)} = \frac{py - pylow}{pyrange}
5389 /// \f]
5390 /// Let:
5391 /// \f[ beta = Log(\frac{ymax}{ymin}) \f]
5392 /// \f[ Log(\frac{y}{ymin}) = beta \times pylow - beta \times py \f]
5393 /// \f[ \frac{y}{ymin} = e^{(beta \times pylow - beta \times py)} \f]
5394 /// \f[ y = ymin \times e^{(beta \times pylow)} \times e^{(-beta \times py)}\f]
5395 /// \f[ \Rightarrow y = fPixeltoYk \times e^{(fPixeltoY \times py)} \f]
5396 /// \f[ fPixeltoYk = ymin \times e^{(beta \times pylow)} \f]
5397 /// \f[ fPixeltoY = -beta \f]
5398 ///
5399 /// #### Conversion from World coordinates to pixel coordinates
5400 ///
5401 /// \f[ px = pxlow + u*pxrange \f]
5402 /// \f[ = pxlow + Log(x/xmin)/alfa \f]
5403 /// \f[ = pxlow -Log(xmin)/alfa + Log(x)/alfa \f]
5404 /// \f[ = fXtoPixelk + fXtoPixel*Log(x) \f]
5405 /// \f[ \Rightarrow fXtoPixelk = pxlow -Log(xmin)/alfa \f]
5406 /// \f[ \Rightarrow fXtoPixel = 1/alfa \f]
5407 ///
5408 /// \f[ py = pylow - Log(y/ymin)/beta \f]
5409 /// \f[ = fYtoPixelk + fYtoPixel*Log(y) \f]
5410 /// \f[ \Rightarrow fYtoPixelk = pylow - Log(ymin)/beta \f]
5411 /// \f[ fYtoPixel = 1/beta \f]
5412 
5413 void TPad::ResizePad(Option_t *option)
5414 {
5415 
5416  if (!gPad) {
5417  Error("ResizePad", "Cannot resize pad. No current pad available.");
5418  return;
5419  }
5420 
5421  // Recompute subpad positions in case pad has been moved/resized
5422  TPad *parent = fMother;
5423  if (this == gPad->GetCanvas()) {
5424  fAbsXlowNDC = fXlowNDC;
5425  fAbsYlowNDC = fYlowNDC;
5426  fAbsWNDC = fWNDC;
5427  fAbsHNDC = fHNDC;
5428  }
5429  else {
5430  fAbsXlowNDC = fXlowNDC*parent->GetAbsWNDC() + parent->GetAbsXlowNDC();
5431  fAbsYlowNDC = fYlowNDC*parent->GetAbsHNDC() + parent->GetAbsYlowNDC();
5432  fAbsWNDC = fWNDC*parent->GetAbsWNDC();
5433  fAbsHNDC = fHNDC*parent->GetAbsHNDC();
5434  }
5435 
5436  Double_t ww = (Double_t)gPad->GetWw();
5437  Double_t wh = (Double_t)gPad->GetWh();
5438  Double_t pxlow = fAbsXlowNDC*ww;
5439  Double_t pylow = (1-fAbsYlowNDC)*wh;
5440  Double_t pxrange = fAbsWNDC*ww;
5441  Double_t pyrange = -fAbsHNDC*wh;
5442 
5443  // Linear X axis
5444  Double_t rounding = 0.00005;
5445  Double_t xrange = fX2 - fX1;
5446  fXtoAbsPixelk = rounding + pxlow - pxrange*fX1/xrange; //origin at left
5447  fXtoPixelk = rounding + -pxrange*fX1/xrange;
5448  fXtoPixel = pxrange/xrange;
5449  fAbsPixeltoXk = fX1 - pxlow*xrange/pxrange;
5450  fPixeltoXk = fX1;
5451  fPixeltoX = xrange/pxrange;
5452  // Linear Y axis
5453  Double_t yrange = fY2 - fY1;
5454  fYtoAbsPixelk = rounding + pylow - pyrange*fY1/yrange; //origin at top
5455  fYtoPixelk = rounding + -pyrange - pyrange*fY1/yrange;
5456  fYtoPixel = pyrange/yrange;
5457  fAbsPixeltoYk = fY1 - pylow*yrange/pyrange;
5458  fPixeltoYk = fY1;
5459  fPixeltoY = yrange/pyrange;
5460 
5461  // Coefficients to convert from pad NDC coordinates to pixel coordinates
5462 
5463  fUtoAbsPixelk = rounding + pxlow;
5464  fUtoPixelk = rounding;
5465  fUtoPixel = pxrange;
5466  fVtoAbsPixelk = rounding + pylow;
5467  fVtoPixelk = -pyrange;
5468  fVtoPixel = pyrange;
5469 
5470  // Coefficients to convert from canvas pixels to pad world coordinates
5471 
5472  // Resize all sub-pads
5473  TObject *obj;
5474  if (!fPrimitives) fPrimitives = new TList;
5475  TIter next(GetListOfPrimitives());
5476  while ((obj = next())) {
5477  if (obj->InheritsFrom(TPad::Class()))
5478  ((TPad*)obj)->ResizePad(option);
5479  }
5480 
5481  // Reset all current sizes
5482  if (gPad->IsBatch())
5483  fPixmapID = 0;
5484  else {
5485  GetPainter()->SetLineWidth(-1);
5486  GetPainter()->SetTextSize(-1);
5487 
5488  // create or re-create off-screen pixmap
5489  if (fPixmapID) {
5490  int w = TMath::Abs(XtoPixel(fX2) - XtoPixel(fX1));
5491  int h = TMath::Abs(YtoPixel(fY2) - YtoPixel(fY1));
5492  //protection in case of wrong pad parameters.
5493  //without this protection, the OpenPixmap or ResizePixmap crashes with
5494  //the message "Error in <RootX11ErrorHandler>: BadValue (integer parameter out of range for operation)"
5495  //resulting in a frozen xterm
5496  if ( !(TMath::Finite(fX1)) || !(TMath::Finite(fX2))
5497  || !(TMath::Finite(fY1)) || !(TMath::Finite(fY2))
5498  || (TMath::IsNaN(fX1)) || (TMath::IsNaN(fX2))
5499  || (TMath::IsNaN(fY1)) || (TMath::IsNaN(fY2)))
5500  Warning("ResizePad", "Inf/NaN propagated to the pad. Check drawn objects.");
5501  if (w <= 0 || w > 10000) {
5502  Warning("ResizePad", "%s width changed from %d to %d\n",GetName(),w,10);
5503  w = 10;
5504  }
5505  if (h <= 0 || h > 10000) {
5506  Warning("ResizePad", "%s height changed from %d to %d\n",GetName(),h,10);
5507  h = 10;
5508  }
5509  if (fPixmapID == -1) { // this case is handled via the ctor
5510  fPixmapID = GetPainter()->CreateDrawable(w, h);
5511  } else {
5512  if (gVirtualX->ResizePixmap(fPixmapID, w, h)) {
5513  Resized();
5514  Modified(kTRUE);
5515  }
5516  }
5517  }
5518  }
5519  if (fView) {
5520  TPad *padsav = (TPad*)gPad;
5521  if (padsav == this) {
5522  fView->ResizePad();
5523  } else {
5524  cd();
5525  fView->ResizePad();
5526  padsav->cd();
5527  }
5528  }
5529 }
5530 
5531 ////////////////////////////////////////////////////////////////////////////////
5532 /// Save Pad contents in a file in one of various formats.
5533 ///
5534 /// - if filename is "", the file produced is padname.ps
5535 /// - if filename starts with a dot, the padname is added in front
5536 /// - if filename contains .eps, an Encapsulated Postscript file is produced
5537 /// - if filename contains .pdf, a PDF file is produced
5538 /// - if filename contains .svg, a SVG file is produced
5539 /// - if filename contains .tex, a TeX file is produced
5540 /// - if filename contains .gif, a GIF file is produced
5541 /// - 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
5542 /// - if filename contains .xpm, a XPM file is produced
5543 /// - if filename contains .png, a PNG file is produced
5544 /// - if filename contains .jpg, a JPEG file is produced NOTE: JPEG's lossy compression will make all sharp edges fuzzy.
5545 /// - if filename contains .tiff, a TIFF file is produced
5546 /// - if filename contains .C or .cxx, a C++ macro file is produced
5547 /// - if filename contains .root, a Root file is produced
5548 /// - if filename contains .xml, a XML file is produced
5549 ///
5550 /// See comments in TPad::Print for the Postscript formats
5551 
5552 void TPad::SaveAs(const char *filename, Option_t * /*option*/) const
5553 {
5554  TString psname;
5555  Int_t lenfil = filename ? strlen(filename) : 0;
5556 
5557  if (!lenfil) { psname = GetName(); psname.Append(".ps"); }
5558  else psname = filename;
5559 
5560  // lines below protected against case like c1->SaveAs( "../ps/cs.ps" );
5561  if (psname.BeginsWith('.') && (psname.Contains('/') == 0)) {
5562  psname = GetName();
5563  psname.Append(filename);
5564  psname.Prepend("/");
5565  psname.Prepend(gEnv->GetValue("Canvas.PrintDirectory","."));
5566  }
5567 
5568  if (psname.EndsWith(".gif"))
5569  ((TPad*)this)->Print(psname,"gif");
5570  else if (psname.Contains(".gif+"))
5571  ((TPad*)this)->Print(psname,"gif+");
5572  else if (psname.EndsWith(".C") || psname.EndsWith(".cxx") || psname.EndsWith(".cpp"))
5573  ((TPad*)this)->Print(psname,"cxx");
5574  else if (psname.EndsWith(".root"))
5575  ((TPad*)this)->Print(psname,"root");
5576  else if (psname.EndsWith(".xml"))
5577  ((TPad*)this)->Print(psname,"xml");
5578  else if (psname.EndsWith(".json"))
5579  ((TPad*)this)->Print(psname,"json");
5580  else if (psname.EndsWith(".eps"))
5581  ((TPad*)this)->Print(psname,"eps");
5582  else if (psname.EndsWith(".pdf"))
5583  ((TPad*)this)->Print(psname,"pdf");
5584  else if (psname.EndsWith(".pdf["))
5585  ((TPad*)this)->Print(psname,"pdf");
5586  else if (psname.EndsWith(".pdf]"))
5587  ((TPad*)this)->Print(psname,"pdf");
5588  else if (psname.EndsWith(".pdf("))
5589  ((TPad*)this)->Print(psname,"pdf");
5590  else if (psname.EndsWith(".pdf)"))
5591  ((TPad*)this)->Print(psname,"pdf");
5592  else if (psname.EndsWith(".svg"))
5593  ((TPad*)this)->Print(psname,"svg");
5594  else if (psname.EndsWith(".tex"))
5595  ((TPad*)this)->Print(psname,"tex");
5596  else if (psname.EndsWith(".xpm"))
5597  ((TPad*)this)->Print(psname,"xpm");
5598  else if (psname.EndsWith(".png"))
5599  ((TPad*)this)->Print(psname,"png");
5600  else if (psname.EndsWith(".jpg"))
5601  ((TPad*)this)->Print(psname,"jpg");
5602  else if (psname.EndsWith(".jpeg"))
5603  ((TPad*)this)->Print(psname,"jpg");
5604  else if (psname.EndsWith(".bmp"))
5605  ((TPad*)this)->Print(psname,"bmp");
5606  else if (psname.EndsWith(".tiff"))
5607  ((TPad*)this)->Print(psname,"tiff");
5608  else
5609  ((TPad*)this)->Print(psname,"ps");
5610 }
5611 
5612 ////////////////////////////////////////////////////////////////////////////////
5613 /// Save primitives in this pad on the C++ source file out.
5614 
5615 void TPad::SavePrimitive(std::ostream &out, Option_t * /*= ""*/)
5616 {
5617  TPad *padsav = (TPad*)gPad;
5618  gPad = this;
5619  char quote='"';
5620  char lcname[10];
5621  const char *cname = GetName();
5622  Int_t nch = strlen(cname);
5623  if (nch < 10) {
5624  strlcpy(lcname,cname,10);
5625  for (Int_t k=1;k<=nch;k++) {if (lcname[nch-k] == ' ') lcname[nch-k] = 0;}
5626  if (lcname[0] == 0) {
5627  if (this == gPad->GetCanvas()) {strlcpy(lcname,"c1",10); nch = 2;}
5628  else {strlcpy(lcname,"pad",10); nch = 3;}
5629  }
5630  cname = lcname;
5631  }
5632 
5633  // Write pad parameters
5634  if (this != gPad->GetCanvas()) {
5635  out <<" "<<std::endl;
5636  out <<"// ------------>Primitives in pad: "<<GetName()<<std::endl;
5637 
5638  out<<" TPad *"<<cname<<" = new TPad("<<quote<<GetName()<<quote<<", "<<quote<<GetTitle()
5639  <<quote
5640  <<","<<fXlowNDC
5641  <<","<<fYlowNDC
5642  <<","<<fXlowNDC+fWNDC
5643  <<","<<fYlowNDC+fHNDC
5644  <<");"<<std::endl;
5645  out<<" "<<cname<<"->Draw();"<<std::endl;
5646  out<<" "<<cname<<"->cd();"<<std::endl;
5647  }
5648  out<<" "<<cname<<"->Range("<<fX1<<","<<fY1<<","<<fX2<<","<<fY2<<");"<<std::endl;
5649  TView *view = GetView();
5650  Double_t rmin[3], rmax[3];
5651  if (view) {
5652  view->GetRange(rmin, rmax);
5653  static Int_t viewNumber = 0;
5654  out<<" TView *view"<<++viewNumber<<" = TView::CreateView(1);"<<std::endl;
5655  out<<" view"<<viewNumber<<"->SetRange("<<rmin[0]<<","<<rmin[1]<<","<<rmin[2]<<","
5656  <<rmax[0]<<","<<rmax[1]<<","<<rmax[2]<<");"<<std::endl;
5657  }
5658  if (GetFillColor() != 19) {
5659  if (GetFillColor() > 228) {
5660  TColor::SaveColor(out, GetFillColor());
5661  out<<" "<<cname<<"->SetFillColor(ci);" << std::endl;
5662  } else
5663  out<<" "<<cname<<"->SetFillColor("<<GetFillColor()<<");"<<std::endl;
5664  }
5665  if (GetFillStyle() != 1001) {
5666  out<<" "<<cname<<"->SetFillStyle("<<GetFillStyle()<<");"<<std::endl;
5667  }
5668  if (GetBorderMode() != 1) {
5669  out<<" "<<cname<<"->SetBorderMode("<<GetBorderMode()<<");"<<std::endl;
5670  }
5671  if (GetBorderSize() != 4) {
5672  out<<" "<<cname<<"->SetBorderSize("<<GetBorderSize()<<");"<<std::endl;
5673  }
5674  if (GetLogx()) {
5675  out<<" "<<cname<<"->SetLogx();"<<std::endl;
5676  }
5677  if (GetLogy()) {
5678  out<<" "<<cname<<"->SetLogy();"<<std::endl;
5679  }
5680  if (GetLogz()) {
5681  out<<" "<<cname<<"->SetLogz();"<<std::endl;
5682  }
5683  if (GetGridx()) {
5684  out<<" "<<cname<<"->SetGridx();"<<std::endl;
5685  }
5686  if (GetGridy()) {
5687  out<<" "<<cname<<"->SetGridy();"<<std::endl;
5688  }
5689  if (GetTickx()) {
5690  out<<" "<<cname<<"->SetTickx("<<GetTickx()<<");"<<std::endl;
5691  }
5692  if (GetTicky()) {
5693  out<<" "<<cname<<"->SetTicky("<<GetTicky()<<");"<<std::endl;
5694  }
5695  if (GetTheta() != 30) {
5696  out<<" "<<cname<<"->SetTheta("<<GetTheta()<<");"<<std::endl;
5697  }
5698  if (GetPhi() != 30) {
5699  out<<" "<<cname<<"->SetPhi("<<GetPhi()<<");"<<std::endl;
5700  }
5701  if (TMath::Abs(fLeftMargin-0.1) > 0.01) {
5702  out<<" "<<cname<<"->SetLeftMargin("<<GetLeftMargin()<<");"<<std::endl;
5703  }
5704  if (TMath::Abs(fRightMargin-0.1) > 0.01) {
5705  out<<" "<<cname<<"->SetRightMargin("<<GetRightMargin()<<");"<<std::endl;
5706  }
5707  if (TMath::Abs(fTopMargin-0.1) > 0.01) {
5708  out<<" "<<cname<<"->SetTopMargin("<<GetTopMargin()<<");"<<std::endl;
5709  }
5710  if (TMath::Abs(fBottomMargin-0.1) > 0.01) {
5711  out<<" "<<cname<<"->SetBottomMargin("<<GetBottomMargin()<<");"<<std::endl;
5712  }
5713 
5714  if (GetFrameFillColor() != GetFillColor()) {
5715  if (GetFrameFillColor() > 228) {
5716  TColor::SaveColor(out, GetFrameFillColor());
5717  out<<" "<<cname<<"->SetFrameFillColor(ci);" << std::endl;
5718  } else
5719  out<<" "<<cname<<"->SetFrameFillColor("<<GetFrameFillColor()<<");"<<std::endl;
5720  }
5721  if (GetFrameFillStyle() != 1001) {
5722  out<<" "<<cname<<"->SetFrameFillStyle("<<GetFrameFillStyle()<<");"<<std::endl;
5723  }
5724  if (GetFrameLineStyle() != 1) {
5725  out<<" "<<cname<<"->SetFrameLineStyle("<<GetFrameLineStyle()<<");"<<std::endl;
5726  }
5727  if (GetFrameLineColor() != 1) {
5728  if (GetFrameLineColor() > 228) {
5729  TColor::SaveColor(out, GetFrameLineColor());
5730  out<<" "<<cname<<"->SetFrameLineColor(ci);" << std::endl;
5731  } else
5732  out<<" "<<cname<<"->SetFrameLineColor("<<GetFrameLineColor()<<");"<<std::endl;
5733  }
5734  if (GetFrameLineWidth() != 1) {
5735  out<<" "<<cname<<"->SetFrameLineWidth("<<GetFrameLineWidth()<<");"<<std::endl;
5736  }
5737  if (GetFrameBorderMode() != 1) {
5738  out<<" "<<cname<<"->SetFrameBorderMode("<<GetFrameBorderMode()<<");"<<std::endl;
5739  }
5740  if (GetFrameBorderSize() != 1) {
5741  out<<" "<<cname<<"->SetFrameBorderSize("<<GetFrameBorderSize()<<");"<<std::endl;
5742  }
5743 
5744  TFrame *frame = fFrame;
5745  if (!frame) frame = (TFrame*)GetPrimitive("TFrame");
5746  if (frame) {
5747  if (frame->GetFillColor() != GetFillColor()) {
5748  if (frame->GetFillColor() > 228) {
5749  TColor::SaveColor(out, frame->GetFillColor());
5750  out<<" "<<cname<<"->SetFrameFillColor(ci);" << std::endl;
5751  } else
5752  out<<" "<<cname<<"->SetFrameFillColor("<<frame->GetFillColor()<<");"<<std::endl;
5753  }
5754  if (frame->GetFillStyle() != 1001) {
5755  out<<" "<<cname<<"->SetFrameFillStyle("<<frame->GetFillStyle()<<");"<<std::endl;
5756  }
5757  if (frame->GetLineStyle() != 1) {
5758  out<<" "<<cname<<"->SetFrameLineStyle("<<frame->GetLineStyle()<<");"<<std::endl;
5759  }
5760  if (frame->GetLineColor() != 1) {
5761  if (frame->GetLineColor() > 228) {
5762  TColor::SaveColor(out, frame->GetLineColor());
5763  out<<" "<<cname<<"->SetFrameLineColor(ci);" << std::endl;
5764  } else
5765  out<<" "<<cname<<"->SetFrameLineColor("<<frame->GetLineColor()<<");"<<std::endl;
5766  }
5767  if (frame->GetLineWidth() != 1) {
5768  out<<" "<<cname<<"->SetFrameLineWidth("<<frame->GetLineWidth()<<");"<<std::endl;
5769  }
5770  if (frame->GetBorderMode() != 1) {
5771  out<<" "<<cname<<"->SetFrameBorderMode("<<frame->GetBorderMode()<<");"<<std::endl;
5772  }
5773  if (frame->GetBorderSize() != 1) {
5774  out<<" "<<cname<<"->SetFrameBorderSize("<<frame->GetBorderSize()<<");"<<std::endl;
5775  }
5776  }
5777 
5778  TIter next(GetListOfPrimitives());
5779  TObject *obj;
5780  Int_t grnum = 0;
5781 
5782  while ((obj = next())) {
5783  if (obj->InheritsFrom(TGraph::Class()))
5784  if (!strcmp(obj->GetName(),"Graph")) ((TGraph*)obj)->SetName(Form("Graph%d",grnum++));
5785  obj->SavePrimitive(out, (Option_t *)next.GetOption());
5786  }
5787  out<<" "<<cname<<"->Modified();"<<std::endl;
5788  out<<" "<<GetMother()->GetName()<<"->cd();"<<std::endl;
5789  if (padsav) padsav->cd();
5790 }
5791 
5792 ////////////////////////////////////////////////////////////////////////////////
5793 /// Fix pad aspect ratio to current value if fixed is true.
5794 
5795 void TPad::SetFixedAspectRatio(Bool_t fixed)
5796 {
5797  if (fixed) {
5798  if (!fFixedAspectRatio) {
5799  if (fHNDC != 0.)
5800  fAspectRatio = fWNDC / fHNDC;
5801  else {
5802  Error("SetAspectRatio", "cannot fix aspect ratio, height of pad is 0");
5803  return;
5804  }
5805  fFixedAspectRatio = kTRUE;
5806  }
5807  } else {
5808  fFixedAspectRatio = kFALSE;
5809  fAspectRatio = 0;
5810  }
5811 }
5812 
5813 ////////////////////////////////////////////////////////////////////////////////
5814 /// Set pad editable yes/no
5815 /// If a pad is not editable:
5816 /// - one cannot modify the pad and its objects via the mouse.
5817 /// - one cannot add new objects to the pad
5818 
5819 void TPad::SetEditable(Bool_t mode)
5820 {
5821  fEditable = mode;
5822 
5823  TObject *obj;
5824  if (!fPrimitives) fPrimitives = new TList;
5825  TIter next(GetListOfPrimitives());
5826  while ((obj = next())) {
5827  if (obj->InheritsFrom(TPad::Class())) {
5828  TPad *pad = (TPad*)obj;
5829  pad->SetEditable(mode);
5830  }
5831  }
5832 }
5833 
5834 ////////////////////////////////////////////////////////////////////////////////
5835 /// Override TAttFill::FillStyle for TPad because we want to handle style=0
5836 /// as style 4000.
5837 
5838 void TPad::SetFillStyle(Style_t fstyle)
5839 {
5840  if (fstyle == 0) fstyle = 4000;
5841  TAttFill::SetFillStyle(fstyle);
5842 }
5843 
5844 ////////////////////////////////////////////////////////////////////////////////
5845 /// Set Lin/Log scale for X
5846 /// - value = 0 X scale will be linear
5847 /// - value = 1 X scale will be logarithmic (base 10)
5848 /// - value > 1 reserved for possible support of base e or other
5849 
5850 void TPad::SetLogx(Int_t value)
5851 {
5852  fLogx = value;
5853  delete fView; fView = nullptr;
5854  Modified();
5855  RangeAxisChanged();
5856 }
5857 
5858 ////////////////////////////////////////////////////////////////////////////////
5859 /// Set Lin/Log scale for Y
5860 /// - value = 0 Y scale will be linear
5861 /// - value = 1 Y scale will be logarithmic (base 10)
5862 /// - value > 1 reserved for possible support of base e or other
5863 
5864 void TPad::SetLogy(Int_t value)
5865 {
5866  fLogy = value;
5867  delete fView; fView = nullptr;
5868  Modified();
5869  RangeAxisChanged();
5870 }
5871 
5872 ////////////////////////////////////////////////////////////////////////////////
5873 /// Set Lin/Log scale for Z
5874 
5875 void TPad::SetLogz(Int_t value)
5876 {
5877  fLogz = value;
5878  delete fView; fView = nullptr;
5879  Modified();
5880  RangeAxisChanged();
5881 }
5882 
5883 ////////////////////////////////////////////////////////////////////////////////
5884 /// Set canvas range for pad and resize the pad. If the aspect ratio
5885 /// was fixed before the call it will be un-fixed.
5886 
5887 void TPad::SetPad(Double_t xlow, Double_t ylow, Double_t xup, Double_t yup)
5888 {
5889  // Reorder points to make sure xlow,ylow is bottom left point and
5890  // xup,yup is top right point.
5891  if (xup < xlow) {
5892  Double_t x = xlow;
5893  xlow = xup;
5894  xup = x;
5895  }
5896  if (yup < ylow) {
5897  Double_t y = ylow;
5898  ylow = yup;
5899  yup = y;
5900  }
5901 
5902  fXlowNDC = xlow;
5903  fYlowNDC = ylow;
5904  fXUpNDC = xup;
5905  fYUpNDC = yup;
5906  fWNDC = xup - xlow;
5907  fHNDC = yup - ylow;
5908 
5909  SetFixedAspectRatio(kFALSE);
5910 
5911  ResizePad();
5912 }
5913 
5914 ////////////////////////////////////////////////////////////////////////////////
5915 /// Set all pad parameters.
5916 
5917 void TPad::SetPad(const char *name, const char *title,
5918  Double_t xlow, Double_t ylow, Double_t xup, Double_t yup,
5919  Color_t color, Short_t bordersize, Short_t bordermode)
5920 {
5921  fName = name;
5922  fTitle = title;
5923  SetFillStyle(1001);
5924  SetBottomMargin(gStyle->GetPadBottomMargin());
5925  SetTopMargin(gStyle->GetPadTopMargin());
5926  SetLeftMargin(gStyle->GetPadLeftMargin());
5927  SetRightMargin(gStyle->GetPadRightMargin());
5928  if (color >= 0) SetFillColor(color);
5929  else SetFillColor(gStyle->GetPadColor());
5930  if (bordersize < 0) fBorderSize = gStyle->GetPadBorderSize();
5931  else fBorderSize = bordersize;
5932  if (bordermode < -1) fBorderMode = gStyle->GetPadBorderMode();
5933  else fBorderMode = bordermode;
5934 
5935  SetPad(xlow, ylow, xup, yup);
5936 }
5937 
5938 ////////////////////////////////////////////////////////////////////////////////
5939 /// Set the current TView. Delete previous view if view=0
5940 
5941 void TPad::SetView(TView *view)
5942 {
5943  if (!view) delete fView;
5944  fView = view;
5945 }
5946 
5947 ////////////////////////////////////////////////////////////////////////////////
5948 /// Set postscript fill area attributes.
5949 
5950 void TPad::SetAttFillPS(Color_t color, Style_t style)
5951 {
5952  if (gVirtualPS) {
5953  gVirtualPS->SetFillColor(color);
5954  gVirtualPS->SetFillStyle(style);
5955  }
5956 }
5957 
5958 ////////////////////////////////////////////////////////////////////////////////
5959 /// Set postscript line attributes.
5960 
5961 void TPad::SetAttLinePS(Color_t color, Style_t style, Width_t lwidth)
5962 {
5963  if (gVirtualPS) {
5964  gVirtualPS->SetLineColor(color);
5965  gVirtualPS->SetLineStyle(style);
5966  gVirtualPS->SetLineWidth(lwidth);
5967  }
5968 }
5969 
5970 ////////////////////////////////////////////////////////////////////////////////
5971 /// Set postscript marker attributes.
5972 
5973 void TPad::SetAttMarkerPS(Color_t color, Style_t style, Size_t msize)
5974 {
5975  if (gVirtualPS) {
5976  gVirtualPS->SetMarkerColor(color);
5977  gVirtualPS->SetMarkerStyle(style);
5978  gVirtualPS->SetMarkerSize(msize);
5979  }
5980 }
5981 
5982 ////////////////////////////////////////////////////////////////////////////////
5983 /// Set postscript text attributes.
5984 
5985 void TPad::SetAttTextPS(Int_t align, Float_t angle, Color_t color, Style_t font, Float_t tsize)
5986 {
5987  if (gVirtualPS) {
5988  gVirtualPS->SetTextAlign(align);
5989  gVirtualPS->SetTextAngle(angle);
5990  gVirtualPS->SetTextColor(color);
5991  gVirtualPS->SetTextFont(font);
5992  if (font%10 > 2) {
5993  Float_t wh = (Float_t)gPad->XtoPixel(gPad->GetX2());
5994  Float_t hh = (Float_t)gPad->YtoPixel(gPad->GetY1());
5995  Float_t dy;
5996  if (wh < hh) {
5997  dy = AbsPixeltoX(Int_t(tsize)) - AbsPixeltoX(0);
5998  tsize = dy/(fX2-fX1);
5999  } else {
6000  dy = AbsPixeltoY(0) - AbsPixeltoY(Int_t(tsize));
6001  tsize = dy/(fY2-fY1);
6002  }
6003  }
6004  gVirtualPS->SetTextSize(tsize);
6005  }
6006 }
6007 
6008 ////////////////////////////////////////////////////////////////////////////////
6009 /// Draw Arrows to indicated equal distances of Objects with given BBoxes.
6010 /// Used by ShowGuidelines
6011 
6012 void TPad::DrawDist(Rectangle_t aBBox, Rectangle_t bBBox, char mode)
6013 {
6014  Int_t lineColor = TColor::GetColor(239, 202, 0);
6015  Int_t x1,x2,y1,y2;
6016  x1 = x2 = y1 = y2 = 0;
6017  if (mode == 'x') {
6018  if (aBBox.fX<bBBox.fX) {
6019  x1 = aBBox.fX+aBBox.fWidth;
6020  x2 = bBBox.fX;
6021  }
6022  else {
6023  x1 = bBBox.fX+bBBox.fWidth;
6024  x2 = aBBox.fX;
6025  }
6026 
6027  if ((aBBox.fY > bBBox.fY) && (aBBox.fY + aBBox.fHeight < bBBox.fY + bBBox.fHeight))
6028  y1 = y2 = aBBox.fY + TMath::Nint(0.5*(Double_t)(aBBox.fHeight))+1;
6029  else if ((bBBox.fY > aBBox.fY) && (bBBox.fY + bBBox.fHeight < aBBox.fY + aBBox.fHeight))
6030  y1 = y2 = bBBox.fY + TMath::Nint(0.5*(Double_t)(bBBox.fHeight))+1;
6031  else if (aBBox.fY>bBBox.fY) y1 = y2 = aBBox.fY-TMath::Nint(0.5*(Double_t)(aBBox.fY-(bBBox.fY+bBBox.fHeight)));
6032  else y1 = y2 = bBBox.fY-TMath::Nint(0.5*(Double_t)(bBBox.fY-(aBBox.fY+aBBox.fHeight)));
6033  }
6034  else if (mode == 'y') {
6035  if (aBBox.fY<bBBox.fY) {
6036  y1 = aBBox.fY+aBBox.fHeight;
6037  y2 = bBBox.fY;
6038  }
6039  else {
6040  y1 = bBBox.fY+bBBox.fHeight;
6041  y2 = aBBox.fY;
6042  }
6043  if ((aBBox.fX > bBBox.fX) && (aBBox.fX + aBBox.fWidth < bBBox.fX + bBBox.fWidth))
6044  x1 = x2 = aBBox.fX + TMath::Nint(0.5*(Double_t)(aBBox.fWidth))+1;
6045  else if ((bBBox.fX > aBBox.fX) && (bBBox.fX + bBBox.fWidth < aBBox.fX + aBBox.fWidth))
6046  x1 = x2 = bBBox.fX + TMath::Nint(0.5*(Double_t)(bBBox.fWidth))+1;
6047  else if (aBBox.fX>bBBox.fX) x1 = x2 = aBBox.fX+TMath::Nint(0.5*(Double_t)(bBBox.fX+bBBox.fWidth-aBBox.fX));
6048  else x1 = x2 = bBBox.fX+TMath::Nint(0.5*(Double_t)(aBBox.fX+aBBox.fWidth-bBBox.fX));
6049  }
6050 
6051  TArrow *A = new TArrow(gPad->PixeltoX(x1), gPad->PixeltoY(y1-gPad->VtoPixel(0)), gPad->PixeltoX(x2), gPad->PixeltoY(y2-gPad->VtoPixel(0)), 0.01, "<|>");
6052  A->SetBit(kCanDelete);
6053  A->SetFillColor(lineColor);
6054  A->SetLineWidth(1);
6055  A->SetLineColor(lineColor);
6056  A->Draw();
6057 
6058  return;
6059 }
6060 
6061 ////////////////////////////////////////////////////////////////////////////////
6062 /// struct used by ShowGuidelines to store the distance Field between objects
6063 /// in the canvas.
6064 
6065 struct dField {
6066  TAttBBox2D *fa;
6067  TAttBBox2D *fb;
6068  Int_t fdist;
6069  char fdir;
6070 
6071 
6072  dField()
6073  : fa(0), fb(0), fdist(0), fdir(' ')
6074  {}
6075 
6076  dField(TAttBBox2D *a, TAttBBox2D *b, Int_t dist, char direction)
6077  : fa(a), fb(b), fdist(dist), fdir(direction)
6078  {}
6079 };
6080 
6081 ////////////////////////////////////////////////////////////////////////////////
6082 /// Shows lines to indicate if a TAttBBox2D object is aligned to
6083 /// the center or to another object, shows distance arrows if two
6084 /// objects on screen have the same distance to another object
6085 /// Call from primitive in Execute Event, in ButtonMotion after
6086 /// the new coordinates have been set, to 'stick'
6087 /// once when button is up to delete lines
6088 ///
6089 /// modes: t (Top), b (bottom), l (left), r (right), i (inside)
6090 /// in resize modes (t,b,l,r) only size arrows are sticky
6091 ///
6092 /// in mode, the function gets the point on the element that is clicked to
6093 /// move (i) or resize (all others). The expected values are:
6094 /// \image html gpad_pad5.png
6095 
6096 void TPad::ShowGuidelines(TObject *object, const Int_t event, const char mode, const bool cling )
6097 {
6098  // When the object is moved with arrow or when the ShowGuideLines flag
6099  // is off we do show guide lines.
6100  if ((event == kArrowKeyRelease) || (event == kArrowKeyPress) ||
6101  !gEnv->GetValue("Canvas.ShowGuideLines", 0)) return;
6102 
6103  std::vector<dField> curDist;
6104  std::vector<dField> otherDist;
6105  Int_t pMX, pMY;
6106  Double_t MX, MY;
6107  Int_t threshold;
6108  TList *prims;
6109  UInt_t n;
6110  Rectangle_t aBBox, bBBox;
6111  aBBox = bBBox = Rectangle_t();
6112  TLine *L;
6113  TArrow *A;
6114  Int_t dSizeArrow = 12; // distance of arrows indicating same size from BBox in px
6115  Bool_t movedX, movedY; // make sure the current object is moved just once
6116  movedX = movedY = false;
6117  Bool_t resize = false; // indicates resize mode
6118  Bool_t log = gPad->GetLogx() || gPad->GetLogy();
6119  if (mode != 'i') resize = true;
6120 
6121  TPad *is_pad = dynamic_cast<TPad *>( object );
6122  TVirtualPad *padSave = 0;
6123  padSave = gPad;
6124  if (is_pad) is_pad->GetMother()->cd();
6125 
6126  static TPad * tmpGuideLinePad;
6127 
6128  //delete all existing Guidelines and create new invisible pad
6129  if (tmpGuideLinePad) {
6130  if (object == tmpGuideLinePad) { // in case of funny button click combination.
6131  tmpGuideLinePad->Delete();
6132  tmpGuideLinePad = 0;
6133  return;
6134  }
6135  tmpGuideLinePad->Delete();
6136  tmpGuideLinePad = 0;
6137  }
6138 
6139  // Get Primitives
6140  prims = gPad->GetListOfPrimitives();
6141  n = TMath::Min(15,prims->GetSize());
6142  Int_t lineColor = TColor::GetColor(239, 202, 0);
6143 
6144  TAttBBox2D *cur = dynamic_cast<TAttBBox2D *>( object );
6145  if (cur) {
6146  //create invisible TPad above gPad
6147  if (!tmpGuideLinePad){
6148  tmpGuideLinePad = new TPad("tmpGuideLinePad", "tmpGuideLinePad", 0, 0, 1, 1);
6149  Double_t x1, y1, x2, y2;
6150  gPad->GetRange(x1, y1, x2, y2);
6151  tmpGuideLinePad->Range(x1, y1, x2, y2);
6152  tmpGuideLinePad->SetFillStyle(0);
6153  tmpGuideLinePad->SetFillColor(0);
6154  tmpGuideLinePad->Draw();
6155  tmpGuideLinePad->cd();
6156  gPad->GetRange(x1, y1, x2, y2);
6157  }
6158  if (cling && !log) threshold = 7;
6159  else threshold = 1;
6160 
6161  Rectangle_t BBox = cur->GetBBox();
6162  TPoint center = cur->GetBBoxCenter();
6163 
6164  otherDist.clear();
6165  curDist.clear();
6166 
6167  switch (event) {
6168 
6169  case kButton1Down:
6170  case kButton1Motion:
6171  MX = gPad->GetX1() + 0.5 * (gPad->GetX2()-gPad->GetX1());
6172  MY = gPad->GetY1() + 0.5 * (gPad->GetY2()-gPad->GetY1());
6173  pMX = gPad->XtoPixel(MX);
6174  pMY = gPad->YtoPixel(MY);
6175  // Middlelines
6176  if (TMath::Abs(pMX-center.GetX())<threshold) {
6177  if (cling && (!resize)) {
6178  cur->SetBBoxCenterX(pMX);
6179  center = cur->GetBBoxCenter();
6180  BBox = cur->GetBBox();
6181  center = cur->GetBBoxCenter();
6182  }
6183  L = new TLine(MX, gPad->GetY1(), MX, gPad->GetY2());
6184  L->SetBit(kCanDelete);
6185  L->SetLineColor(lineColor);
6186  L->Draw();
6187  }
6188  if (TMath::Abs(pMY-center.GetY())<threshold) {
6189  if (cling && (!resize)) {
6190  cur->SetBBoxCenterY(pMY);
6191  center = cur->GetBBoxCenter();
6192  BBox = cur->GetBBox();
6193  center = cur->GetBBoxCenter();
6194  }
6195  L = new TLine(gPad->GetX1(), MY, gPad->GetX2(), MY);
6196  L->SetBit(kCanDelete);
6197  L->SetLineColor(lineColor);
6198  L->Draw();
6199  }
6200  // Alignment to other objects
6201  for (UInt_t i = 0; i<n; i++) {
6202  TAttBBox2D *other = dynamic_cast<TAttBBox2D *>( prims->At(i) );
6203  if (other) {
6204  if (other != cur) {
6205  TPoint centerOther = other->GetBBoxCenter();
6206  if (TMath::Abs(center.GetX()-centerOther.GetX())<threshold) {
6207  if (cling && (!resize)) {
6208  cur->SetBBoxCenterX(centerOther.GetX());
6209  BBox = cur->GetBBox();
6210  center = cur->GetBBoxCenter();
6211  }
6212  L = new TLine(gPad->PixeltoX(centerOther.GetX()), gPad->PixeltoY(center.GetY()-gPad->VtoPixel(0)),
6213  gPad->PixeltoX(centerOther.GetX()), gPad->PixeltoY(centerOther.GetY()-gPad->VtoPixel(0)));
6214  L->SetLineColor(lineColor);
6215  L->Draw();
6216  L->SetBit(kCanDelete);
6217  }
6218  if (TMath::Abs(center.GetY()-centerOther.GetY())<threshold) {
6219  if (cling && (!resize)) {
6220  cur->SetBBoxCenterY(centerOther.GetY());
6221  BBox = cur->GetBBox();
6222  center = cur->GetBBoxCenter();
6223  }
6224  L = new TLine(gPad->PixeltoX(center.GetX()), gPad->PixeltoY(centerOther.GetY()-gPad->VtoPixel(0)),
6225  gPad->PixeltoX(centerOther.GetX()), gPad->PixeltoY(centerOther.GetY()-gPad->VtoPixel(0)));
6226  L->SetBit(kCanDelete);
6227  L->SetLineColor(lineColor);
6228  L->Draw();
6229  }
6230  }
6231  }
6232  }
6233  // Get Distances between objects
6234  for (UInt_t i = 0; i<n; i++) {
6235  TAttBBox2D *a = dynamic_cast<TAttBBox2D *>( prims->At(i) );
6236  if (a) {
6237  aBBox = a->GetBBox();
6238  for (UInt_t j = i+1; j<n; j++) {
6239  TAttBBox2D *b = dynamic_cast<TAttBBox2D *>( prims->At(j) );
6240  if (b) {
6241  bBBox = b->GetBBox();
6242 
6243  //only when bounding boxes overlap in x or y direction
6244  if (((aBBox.fX<bBBox.fX)&&(bBBox.fX-aBBox.fX<=aBBox.fWidth))||((aBBox.fX>bBBox.fX)&&(aBBox.fX-bBBox.fX<=bBBox.fWidth))){ //BBoxes overlap in x direction
6245  if ((aBBox.fY+aBBox.fHeight<bBBox.fY)||(bBBox.fY+bBBox.fHeight<aBBox.fY)) {//No overlap in Y-direction required
6246  dField abDist = dField();
6247  if (aBBox.fY>bBBox.fY) abDist = dField(a, b, TMath::Abs(aBBox.fY-(bBBox.fY+bBBox.fHeight)), 'y');
6248  else abDist = dField(a, b, TMath::Abs(bBBox.fY-(aBBox.fY+aBBox.fHeight)), 'y');
6249  if ((b != cur)&&(a != cur)) otherDist.push_back(abDist);
6250  else curDist.push_back(abDist);
6251  }
6252  } else if (((aBBox.fY<bBBox.fY)&&(bBBox.fY-aBBox.fY<=aBBox.fHeight))||((aBBox.fY>bBBox.fY)&&(aBBox.fY-bBBox.fY<=bBBox.fHeight))) { //BBoxes overlap in y direction
6253  if ((aBBox.fX+aBBox.fWidth<bBBox.fX)||(bBBox.fX+bBBox.fWidth<aBBox.fX)) {//No overlap in x-direction required
6254  dField abDist = dField();
6255  if (aBBox.fX>bBBox.fX) abDist = dField(a, b, TMath::Abs(aBBox.fX-(bBBox.fX+bBBox.fWidth)), 'x');
6256  else abDist = dField(a, b, TMath::Abs(bBBox.fX-(aBBox.fX+aBBox.fWidth)), 'x');
6257  if ((b != cur)&&(a != cur)) otherDist.push_back(abDist);
6258  else curDist.push_back(abDist);
6259  }
6260  }
6261  }
6262  }
6263  }
6264  }
6265  // Show equal distances
6266  for (UInt_t i = 0; i<curDist.size(); i++) {
6267  for (UInt_t j = 0; j<otherDist.size(); j++) {
6268  if ((curDist[i].fdir == otherDist[j].fdir)&&(otherDist[j].fdir=='x')&&(TMath::Abs(curDist[i].fdist-otherDist[j].fdist)<threshold)) {
6269  if (cling && (!movedX) && (!resize)) {
6270  if ((cur->GetBBoxCenter().fX < curDist[i].fb->GetBBoxCenter().fX)||(cur->GetBBoxCenter().fX < curDist[i].fa->GetBBoxCenter().fX))
6271  cur->SetBBoxCenterX(cur->GetBBoxCenter().fX - otherDist[j].fdist + curDist[i].fdist);
6272  else cur->SetBBoxCenterX(cur->GetBBoxCenter().fX + otherDist[j].fdist - curDist[i].fdist);
6273  movedX = true;
6274  }
6275  DrawDist(curDist[i].fa->GetBBox(), curDist[i].fb->GetBBox(), 'x');
6276  DrawDist(otherDist[j].fa->GetBBox(), otherDist[j].fb->GetBBox(), 'x');
6277  }
6278  if ((curDist[i].fdir == otherDist[j].fdir)&&(otherDist[j].fdir=='y')&&(TMath::Abs(curDist[i].fdist-otherDist[j].fdist)<threshold)) {
6279  if (cling && (!movedY) && (!resize)) {
6280  if ((cur->GetBBoxCenter().fY < curDist[i].fb->GetBBoxCenter().fY)||(cur->GetBBoxCenter().fY < curDist[i].fa->GetBBoxCenter().fY))
6281  cur->SetBBoxCenterY(cur->GetBBoxCenter().fY - otherDist[j].fdist + curDist[i].fdist);
6282  else cur->SetBBoxCenterY(cur->GetBBoxCenter().fY + otherDist[j].fdist - curDist[i].fdist);
6283  movedY = true;
6284  }
6285  DrawDist(curDist[i].fa->GetBBox(), curDist[i].fb->GetBBox(), 'y');
6286  DrawDist(otherDist[j].fa->GetBBox(), otherDist[j].fb->GetBBox(), 'y');
6287  }
6288  }
6289  for (UInt_t j = i; j<curDist.size(); j++) {
6290  if (i!=j) {
6291  if ((curDist[i].fdir == curDist[j].fdir)&&(curDist[j].fdir=='x')&&(TMath::Abs(curDist[i].fdist-curDist[j].fdist)<threshold)) {
6292  if (cling && (!movedX) && (!resize)) {
6293  if ((cur->GetBBoxCenter().fX < curDist[i].fb->GetBBoxCenter().fX)||(cur->GetBBoxCenter().fX < curDist[i].fa->GetBBoxCenter().fX))
6294  cur->SetBBoxCenterX(cur->GetBBoxCenter().fX - floor(0.5*(curDist[j].fdist - curDist[i].fdist)));
6295  else cur->SetBBoxCenterX(cur->GetBBoxCenter().fX + floor(0.5*(curDist[j].fdist - curDist[i].fdist)));
6296  }
6297  DrawDist(curDist[i].fa->GetBBox(), curDist[i].fb->GetBBox(), 'x');
6298  DrawDist(curDist[j].fa->GetBBox(), curDist[j].fb->GetBBox(), 'x');
6299  }
6300 
6301  if ((curDist[i].fdir == curDist[j].fdir)&&(curDist[j].fdir=='y')&&(TMath::Abs(curDist[i].fdist-curDist[j].fdist)<threshold)) {
6302  if (cling && (!movedY) && (!resize)) {
6303  if ((cur->GetBBoxCenter().fY < curDist[i].fb->GetBBoxCenter().fY)||(cur->GetBBoxCenter().fY < curDist[i].fa->GetBBoxCenter().fY))
6304  cur->SetBBoxCenterY(cur->GetBBoxCenter().fY - floor(0.5*(curDist[j].fdist - curDist[i].fdist)));
6305  else cur->SetBBoxCenterY(cur->GetBBoxCenter().fY + floor(0.5*(curDist[j].fdist - curDist[i].fdist)));
6306  }
6307  DrawDist(curDist[i].fa->GetBBox(), curDist[i].fb->GetBBox(), 'y');
6308  DrawDist(curDist[j].fa->GetBBox(), curDist[j].fb->GetBBox(), 'y');
6309  }
6310  }
6311  }
6312  }
6313  if (resize) {
6314  // Show equal Sizes
6315  for (UInt_t i = 0; i<n; i++) {
6316  TAttBBox2D *a = dynamic_cast<TAttBBox2D *>( prims->At(i) );
6317  if (a && (cur != a)) {
6318  aBBox = a->GetBBox();
6319 
6320  if ((TMath::Abs(aBBox.fWidth - BBox.fWidth)<threshold) && (mode != 't') && (mode != 'b')) {
6321  if (cling) {
6322  if (mode == 'l') cur->SetBBoxX1(BBox.fX + BBox.fWidth - aBBox.fWidth);
6323  if (mode == 'r') cur->SetBBoxX2(BBox.fX + aBBox.fWidth);
6324  if ((mode == '1')||(mode == '4')) cur->SetBBoxX1(BBox.fX + BBox.fWidth - aBBox.fWidth);
6325  if ((mode == '2')||(mode == '3')) cur->SetBBoxX2(BBox.fX + aBBox.fWidth);
6326  BBox = cur->GetBBox();
6327  }
6328 
6329  A = new TArrow(gPad->PixeltoX(aBBox.fX), gPad->PixeltoY(aBBox.fY-dSizeArrow-gPad->VtoPixel(0)),
6330  gPad->PixeltoX(aBBox.fX+aBBox.fWidth), gPad->PixeltoY(aBBox.fY-dSizeArrow-gPad->VtoPixel(0)), 0.01, "<|>");
6331  A->SetBit(kCanDelete);
6332  A->SetLineColor(lineColor);
6333  A->SetFillColor(lineColor);
6334  A->Draw();
6335 
6336  A = new TArrow(gPad->PixeltoX(BBox.fX), gPad->PixeltoY(BBox.fY-dSizeArrow-gPad->VtoPixel(0)),
6337  gPad->PixeltoX(BBox.fX+BBox.fWidth), gPad->PixeltoY(BBox.fY-dSizeArrow-gPad->VtoPixel(0)), 0.01, "<|>");
6338  A->SetBit(kCanDelete);
6339  A->SetLineColor(lineColor);
6340  A->SetFillColor(lineColor);
6341  A->Draw();
6342  }
6343  if ((TMath::Abs(aBBox.fHeight - BBox.fHeight)<threshold) && (mode != 'r') && (mode != 'l')) {
6344  if (cling) {
6345  if (mode == 't') cur->SetBBoxY1(BBox.fY + BBox.fHeight - aBBox.fHeight);
6346  if (mode == 'b') cur->SetBBoxY2(BBox.fY + aBBox.fHeight);
6347  if ((mode == '1')||(mode == '2')) cur->SetBBoxY1(BBox.fY + BBox.fHeight - aBBox.fHeight);
6348  if ((mode == '3')||(mode == '4')) cur->SetBBoxY2(BBox.fY + aBBox.fHeight);
6349  BBox = cur->GetBBox();
6350  }
6351  A = new TArrow(gPad->PixeltoX(aBBox.fX-dSizeArrow), gPad->PixeltoY(aBBox.fY-gPad->VtoPixel(0)),
6352  gPad->PixeltoX(aBBox.fX-dSizeArrow), gPad->PixeltoY(aBBox.fY+aBBox.fHeight-gPad->VtoPixel(0)), 0.01, "<|>");
6353  A->SetBit(kCanDelete);
6354  A->SetLineColor(lineColor);
6355  A->SetFillColor(lineColor);
6356  A->Draw();
6357 
6358  A = new TArrow(gPad->PixeltoX(BBox.fX-dSizeArrow), gPad->PixeltoY(BBox.fY-gPad->VtoPixel(0)),
6359  gPad->PixeltoX(BBox.fX-dSizeArrow), gPad->PixeltoY(BBox.fY+BBox.fHeight-gPad->VtoPixel(0)), 0.01, "<|>");
6360  A->SetBit(kCanDelete);
6361  A->SetLineColor(lineColor);
6362  A->SetFillColor(lineColor);
6363  A->Draw();
6364  }
6365  }
6366  }
6367  }
6368 
6369  break;
6370 
6371  case kButton1Up:
6372  if (tmpGuideLinePad) {
6373  // All the arrows and lines in that pad are also deleted because
6374  // they all have the bit kCanDelete on.
6375  tmpGuideLinePad->Delete();
6376  tmpGuideLinePad = 0;
6377  }
6378  break;
6379  }
6380  }
6381 
6382  gPad->Modified(kTRUE);
6383  padSave->cd();
6384 }
6385 
6386 ////////////////////////////////////////////////////////////////////////////////
6387 /// Return kTRUE if the crosshair has been activated (via SetCrosshair).
6388 
6389 Bool_t TPad::HasCrosshair() const
6390 {
6391  return (Bool_t)GetCrosshair();
6392 }
6393 
6394 ////////////////////////////////////////////////////////////////////////////////
6395 /// Return the crosshair type (from the mother canvas)
6396 /// crosshair type = 0 means no crosshair.
6397 
6398 Int_t TPad::GetCrosshair() const
6399 {
6400  if (this == (TPad*)fCanvas)
6401  return fCrosshair;
6402  return fCanvas ? fCanvas->GetCrosshair() : 0;
6403 }
6404 
6405 ////////////////////////////////////////////////////////////////////////////////
6406 /// Set crosshair active/inactive.
6407 /// - If crhair != 0, a crosshair will be drawn in the pad and its sub-pads.
6408 /// - If the canvas crhair = 1 , the crosshair spans the full canvas.
6409 /// - If the canvas crhair > 1 , the crosshair spans only the pad.
6410 
6411 void TPad::SetCrosshair(Int_t crhair)
6412 {
6413  fCrosshair = crhair;
6414  fCrosshairPos = 0;
6415 
6416  if (this != (TPad*)fCanvas) fCanvas->SetCrosshair(crhair);
6417 }
6418 
6419 ////////////////////////////////////////////////////////////////////////////////
6420 /// static function to set the maximum Pick Distance fgMaxPickDistance
6421 /// This parameter is used in TPad::Pick to select an object if
6422 /// its DistancetoPrimitive returns a value < fgMaxPickDistance
6423 /// The default value is 5 pixels. Setting a smaller value will make
6424 /// picking more precise but also more difficult
6425 
6426 void TPad::SetMaxPickDistance(Int_t maxPick)
6427 {
6428  fgMaxPickDistance = maxPick;
6429 }
6430 
6431 ////////////////////////////////////////////////////////////////////////////////
6432 /// Set tool tip text associated with this pad. The delay is in
6433 /// milliseconds (minimum 250). To remove tool tip call method with
6434 /// text = 0.
6435 
6436 void TPad::SetToolTipText(const char *text, Long_t delayms)
6437 {
6438  if (fTip) {
6439  DeleteToolTip(fTip);
6440  fTip = nullptr;
6441  }
6442 
6443  if (text && strlen(text))
6444  fTip = CreateToolTip((TBox*)nullptr, text, delayms);
6445 }
6446 
6447 ////////////////////////////////////////////////////////////////////////////////
6448 /// Set pad vertical (default) or horizontal
6449 
6450 void TPad::SetVertical(Bool_t vert)
6451 {
6452  if (vert) ResetBit(kHori);
6453  else SetBit(kHori);
6454 }
6455 
6456 ////////////////////////////////////////////////////////////////////////////////
6457 /// Stream a class object.
6458 
6459 void TPad::Streamer(TBuffer &b)
6460 {
6461  UInt_t R__s, R__c;
6462  Int_t nch, nobjects;
6463  Float_t single;
6464  TObject *obj;
6465  if (b.IsReading()) {
6466  Version_t v = b.ReadVersion(&R__s, &R__c);
6467  if (v > 5) {
6468  if (!gPad) gPad = new TCanvas(GetName());
6469  TPad *padsave = (TPad*)gPad;
6470  fMother = (TPad*)gPad;
6471  if (fMother) fCanvas = fMother->GetCanvas();
6472  gPad = this;
6473  fPixmapID = -1; // -1 means pixmap will be created by ResizePad()
6474  gReadLevel++;
6475  gROOT->SetReadingObject(kTRUE);
6476 
6477  b.ReadClassBuffer(TPad::Class(), this, v, R__s, R__c);
6478 
6479  //Set the kCanDelete bit in all objects in the pad such that when the pad
6480  //is deleted all objects in the pad are deleted too.
6481  TIter next(fPrimitives);
6482  while ((obj = next())) {
6483  obj->SetBit(kCanDelete);
6484  }
6485 
6486  fModified = kTRUE;
6487  fPadPointer = nullptr;
6488  gReadLevel--;
6489  if (gReadLevel == 0 && IsA() == TPad::Class()) ResizePad();
6490  gROOT->SetReadingObject(kFALSE);
6491  gPad = padsave;
6492  return;
6493  }
6494 
6495  //====process old versions before automatic schema evolution
6496  if (v < 5) { //old TPad in single precision
6497  if (v < 3) { //old TPad derived from TWbox
6498  b.ReadVersion(); // TVirtualPad::Streamer(b)
6499  b.ReadVersion(); // TWbox::Streamer(b)
6500  b.ReadVersion(); // TBox::Streamer(b)
6501  TObject::Streamer(b);
6502  TAttLine::Streamer(b);
6503  TAttFill::Streamer(b);
6504  b >> single; fX1 = single;
6505  b >> single; fY1 = single;
6506  b >> single; fX2 = single;
6507  b >> single; fY2 = single;
6508  b >> fBorderSize;
6509  b >> fBorderMode;
6510  TAttPad::Streamer(b);
6511  } else { //new TPad
6512  TVirtualPad::Streamer(b);
6513  TAttPad::Streamer(b);
6514  b >> single; fX1 = single;
6515  b >> single; fY1 = single;
6516  b >> single; fX2 = single;
6517  b >> single; fY2 = single;
6518  b >> fBorderSize;
6519  b >> fBorderMode;
6520  }
6521  b >> fLogx;
6522  b >> fLogy;
6523  b >> fLogz;
6524  b >> single; fXtoAbsPixelk = single;
6525  b >> single; fXtoPixelk = single;
6526  b >> single; fXtoPixel = single;
6527  b >> single; fYtoAbsPixelk = single;
6528  b >> single; fYtoPixelk = single;
6529  b >> single; fYtoPixel = single;
6530  b >> single; fUtoAbsPixelk = single;
6531  b >> single; fUtoPixelk = single;
6532  b >> single; fUtoPixel = single;
6533  b >> single; fVtoAbsPixelk = single;
6534  b >> single; fVtoPixelk = single;
6535  b >> single; fVtoPixel = single;
6536  b >> single; fAbsPixeltoXk = single;
6537  b >> single; fPixeltoXk = single;
6538  b >> single; fPixeltoX = single;
6539  b >> single; fAbsPixeltoYk = single;
6540  b >> single; fPixeltoYk = single;
6541  b >> single; fPixeltoY = single;
6542  b >> single; fXlowNDC = single;
6543  b >> single; fYlowNDC = single;
6544  b >> single; fWNDC = single;
6545  b >> single; fHNDC = single;
6546  b >> single; fAbsXlowNDC = single;
6547  b >> single; fAbsYlowNDC = single;
6548  b >> single; fAbsWNDC = single;
6549  b >> single; fAbsHNDC = single;
6550  b >> single; fUxmin = single;
6551  b >> single; fUymin = single;
6552  b >> single; fUxmax = single;
6553  b >> single; fUymax = single;
6554  } else {
6555  TVirtualPad::Streamer(b);
6556  TAttPad::Streamer(b);
6557  b >> fX1;
6558  b >> fY1;
6559  b >> fX2;
6560  b >> fY2;
6561  b >> fBorderSize;
6562  b >> fBorderMode;
6563  b >> fLogx;
6564  b >> fLogy;
6565  b >> fLogz;
6566  b >> fXtoAbsPixelk;
6567  b >> fXtoPixelk;
6568  b >> fXtoPixel;
6569  b >> fYtoAbsPixelk;
6570  b >> fYtoPixelk;
6571  b >> fYtoPixel;
6572  b >> fUtoAbsPixelk;
6573  b >> fUtoPixelk;
6574  b >> fUtoPixel;
6575  b >> fVtoAbsPixelk;
6576  b >> fVtoPixelk;
6577  b >> fVtoPixel;
6578  b >> fAbsPixeltoXk;
6579  b >> fPixeltoXk;
6580  b >> fPixeltoX;
6581  b >> fAbsPixeltoYk;
6582  b >> fPixeltoYk;
6583  b >> fPixeltoY;
6584  b >> fXlowNDC;
6585  b >> fYlowNDC;
6586  b >> fWNDC;
6587  b >> fHNDC;
6588  b >> fAbsXlowNDC;
6589  b >> fAbsYlowNDC;
6590  b >> fAbsWNDC;
6591  b >> fAbsHNDC;
6592  b >> fUxmin;
6593  b >> fUymin;
6594  b >> fUxmax;
6595  b >> fUymax;
6596  }
6597 
6598  if (!gPad) gPad = new TCanvas(GetName());
6599  if (gReadLevel == 0) fMother = (TPad*)gROOT->GetSelectedPad();
6600  else fMother = (TPad*)gPad;
6601  if (!fMother) fMother = (TPad*)gPad;
6602  if (fMother) fCanvas = fMother->GetCanvas();
6603  gPad = fMother;
6604  fPixmapID = -1; // -1 means pixmap will be created by ResizePad()
6605  //-------------------------
6606  // read objects and their drawing options
6607  // b >> fPrimitives;
6608  gReadLevel++;
6609  gROOT->SetReadingObject(kTRUE);
6610  fPrimitives = new TList;
6611  b >> nobjects;
6612  if (nobjects > 0) {
6613  TPad *padsav = (TPad*)gPad;
6614  gPad = this;
6615  char drawoption[64];
6616  for (Int_t i = 0; i < nobjects; i++) {
6617  b >> obj;
6618  b >> nch;
6619  b.ReadFastArray(drawoption,nch);
6620  fPrimitives->AddLast(obj, drawoption);
6621  gPad = this; // gPad may be modified in b >> obj if obj is a pad
6622  }
6623  gPad = padsav;
6624  }
6625  gReadLevel--;
6626  gROOT->SetReadingObject(kFALSE);
6627  //////////////////////////////////////////////////////////////////////////
6628 
6629  if (v > 3) {
6630  b >> fExecs;
6631  }
6632  fName.Streamer(b);
6633  fTitle.Streamer(b);
6634  b >> fPadPaint;
6635  fModified = kTRUE;
6636  b >> fGridx;
6637  b >> fGridy;
6638  b >> fFrame;
6639  b >> fView;
6640  if (v < 5) {
6641  b >> single; fTheta = single;
6642  b >> single; fPhi = single;
6643  } else {
6644  b >> fTheta;
6645  b >> fPhi;
6646  }
6647  fPadPointer = nullptr;
6648  b >> fNumber;
6649  b >> fAbsCoord;
6650  if (v > 1) {
6651  b >> fTickx;
6652  b >> fTicky;
6653  } else {
6654  fTickx = fTicky = 0;
6655  }
6656  if (gReadLevel == 0 && IsA() == TPad::Class()) ResizePad();
6657  b.CheckByteCount(R__s, R__c, TPad::IsA());
6658  //====end of old versions
6659 
6660  } else {
6661  b.WriteClassBuffer(TPad::Class(),this);
6662  }
6663 }
6664 
6665 ////////////////////////////////////////////////////////////////////////////////
6666 /// Force a copy of current style for all objects in pad.
6667 
6668 void TPad::UseCurrentStyle()
6669 {
6670  if (gStyle->IsReading()) {
6671  SetFillColor(gStyle->GetPadColor());
6672  SetBottomMargin(gStyle->GetPadBottomMargin());
6673  SetTopMargin(gStyle->GetPadTopMargin());
6674  SetLeftMargin(gStyle->GetPadLeftMargin());
6675  SetRightMargin(gStyle->GetPadRightMargin());
6676  fBorderSize = gStyle->GetPadBorderSize();
6677  fBorderMode = gStyle->GetPadBorderMode();
6678  fGridx = gStyle->GetPadGridX();
6679  fGridy = gStyle->GetPadGridY();
6680  fTickx = gStyle->GetPadTickX();
6681  fTicky = gStyle->GetPadTickY();
6682  fLogx = gStyle->GetOptLogx();
6683  fLogy = gStyle->GetOptLogy();
6684  fLogz = gStyle->GetOptLogz();
6685  } else {
6686  gStyle->SetPadColor(GetFillColor());
6687  gStyle->SetPadBottomMargin(GetBottomMargin());
6688  gStyle->SetPadTopMargin(GetTopMargin());
6689  gStyle->SetPadLeftMargin(GetLeftMargin());
6690  gStyle->SetPadRightMargin(GetRightMargin());
6691  gStyle->SetPadBorderSize(GetBorderSize());
6692  gStyle->SetPadBorderMode(GetBorderMode());
6693  gStyle->SetPadGridX(fGridx);
6694  gStyle->SetPadGridY(fGridy);
6695  gStyle->SetPadTickX(fTickx);
6696  gStyle->SetPadTickY(fTicky);
6697  gStyle->SetOptLogx (fLogx);
6698  gStyle->SetOptLogy (fLogy);
6699  gStyle->SetOptLogz (fLogz);
6700  }
6701 
6702  if (!fPrimitives) fPrimitives = new TList;
6703  TIter next(GetListOfPrimitives());
6704  TObject *obj;
6705 
6706  while ((obj = next())) {
6707  obj->UseCurrentStyle();
6708  }
6709 
6710  TPaveText *title = (TPaveText*)FindObject("title");
6711  if (title) {
6712  if (gStyle->IsReading()) {
6713  title->SetFillColor(gStyle->GetTitleFillColor());
6714  title->SetTextFont(gStyle->GetTitleFont(""));
6715  title->SetTextColor(gStyle->GetTitleTextColor());
6716  title->SetBorderSize(gStyle->GetTitleBorderSize());
6717  if (!gStyle->GetOptTitle()) delete title;
6718  } else {
6719  gStyle->SetTitleFillColor(title->GetFillColor());
6720  gStyle->SetTitleFont(title->GetTextFont());
6721  gStyle->SetTitleTextColor(title->GetTextColor());
6722  gStyle->SetTitleBorderSize(title->GetBorderSize());
6723  }
6724  }
6725  if (fFrame) fFrame->UseCurrentStyle();
6726 
6727  if (gStyle->IsReading()) Modified();
6728 }
6729 
6730 ////////////////////////////////////////////////////////////////////////////////
6731 /// Loop and sleep until a primitive with name=pname is found in the pad.
6732 ///
6733 /// If emode is given, the editor is automatically set to emode, ie
6734 /// it is not required to have the editor control bar.
6735 ///
6736 /// The possible values for emode are:
6737 /// - emode = "" (default). User will select the mode via the editor bar
6738 /// - emode = "Arc", "Line", "Arrow", "Button", "Diamond", "Ellipse",
6739 /// - emode = "Pad","pave", "PaveLabel","PaveText", "PavesText",
6740 /// - emode = "PolyLine", "CurlyLine", "CurlyArc", "Text", "Marker", "CutG"
6741 ///
6742 /// If emode is specified and it is not valid, "PolyLine" is assumed. If emode
6743 /// is not specified or ="", an attempt is to use pname[1...]
6744 ///
6745 /// for example if pname="TArc", emode="Arc" will be assumed.
6746 /// When this function is called within a macro, the macro execution
6747 /// is suspended until a primitive corresponding to the arguments
6748 /// is found in the pad.
6749 ///
6750 /// If CRTL/C is typed in the pad, the function returns 0.
6751 ///
6752 /// While this function is executing, one can use the mouse, interact
6753 /// with the graphics pads, use the Inspector, Browser, TreeViewer, etc.
6754 ///
6755 /// Examples:
6756 /// ~~~ {.cpp}
6757 /// c1.WaitPrimitive(); // Return the first created primitive
6758 /// // whatever it is.
6759 /// // If a double-click with the mouse is executed
6760 /// // in the pad or any key pressed, the function
6761 /// // returns 0.
6762 /// c1.WaitPrimitive("ggg"); // Set the editor in mode "PolyLine/Graph"
6763 /// // Create a polyline, then using the context
6764 /// // menu item "SetName", change the name
6765 /// // of the created TGraph to "ggg"
6766 /// c1.WaitPrimitive("TArc");// Set the editor in mode "Arc". Returns
6767 /// // as soon as a TArc object is created.
6768 /// c1.WaitPrimitive("lat","Text"); // Set the editor in Text/Latex mode.
6769 /// // Create a text object, then Set its name to "lat"
6770 /// ~~~
6771 /// The following macro waits for 10 primitives of any type to be created.
6772 ///
6773 /// ~~~ {.cpp}
6774 ///{
6775 /// TCanvas c1("c1");
6776 /// TObject *obj;
6777 /// for (Int_t i=0;i<10;i++) {
6778 /// obj = gPad->WaitPrimitive();
6779 /// if (!obj) break;
6780 /// printf("Loop i=%d, found objIsA=%s, name=%s\n",
6781 /// i,obj->ClassName(),obj->GetName());
6782 /// }
6783 ///}
6784 /// ~~~
6785 ///
6786 /// If ROOT runs in batch mode a call to this method does nothing.
6787 
6788 TObject *TPad::WaitPrimitive(const char *pname, const char *emode)
6789 {
6790  if (!gPad) return 0;
6791 
6792  if (strlen(emode)) gROOT->SetEditorMode(emode);
6793  if (gROOT->GetEditorMode() == 0 && strlen(pname) > 2) gROOT->SetEditorMode(&pname[1]);
6794 
6795  if (!fPrimitives) fPrimitives = new TList;
6796  gSystem->ProcessEvents();
6797  TObject *oldlast = gPad->GetListOfPrimitives()->Last();
6798  TObject *obj = 0;
6799  Bool_t testlast = kFALSE;
6800  Bool_t hasname = strlen(pname) > 0;
6801  if (!pname[0] && !emode[0]) testlast = kTRUE;
6802  if (testlast) gROOT->SetEditorMode();
6803  while (!gSystem->ProcessEvents() && gROOT->GetSelectedPad()) {
6804  if (gROOT->GetEditorMode() == 0) {
6805  if (hasname) {
6806  obj = FindObject(pname);
6807  if (obj) return obj;
6808  }
6809  if (testlast) {
6810  obj = gPad->GetListOfPrimitives()->Last();
6811  if (obj != oldlast) return obj;
6812  Int_t event = GetEvent();
6813  if (event == kButton1Double || event == kKeyPress) {
6814  //the following statement is required against other loop executions
6815  //before returning
6816  fCanvas->HandleInput((EEventType)-1,0,0);
6817  return 0;
6818  }
6819  }
6820  }
6821  gSystem->Sleep(10);
6822  }
6823 
6824  return 0;
6825 }
6826 
6827 ////////////////////////////////////////////////////////////////////////////////
6828 /// Create a tool tip and return its pointer.
6829 
6830 TObject *TPad::CreateToolTip(const TBox *box, const char *text, Long_t delayms)
6831 {
6832  if (gPad->IsBatch()) return 0;
6833  return (TObject*)gROOT->ProcessLineFast(Form("new TGToolTip((TBox*)0x%lx,\"%s\",%d)",
6834  (Long_t)box,text,(Int_t)delayms));
6835 }
6836 
6837 ////////////////////////////////////////////////////////////////////////////////
6838 /// Delete tool tip object.
6839 
6840 void TPad::DeleteToolTip(TObject *tip)
6841 {
6842  // delete tip;
6843  if (!tip) return;
6844  gROOT->ProcessLineFast(Form("delete (TGToolTip*)0x%lx", (Long_t)tip));
6845 }
6846 
6847 ////////////////////////////////////////////////////////////////////////////////
6848 /// Reset tool tip, i.e. within time specified in CreateToolTip the
6849 /// tool tip will pop up.
6850 
6851 void TPad::ResetToolTip(TObject *tip)
6852 {
6853  if (!tip) return;
6854  // tip->Reset(this);
6855  gROOT->ProcessLineFast(Form("((TGToolTip*)0x%lx)->Reset((TPad*)0x%lx)",
6856  (Long_t)tip,(Long_t)this));
6857 }
6858 
6859 ////////////////////////////////////////////////////////////////////////////////
6860 /// Hide tool tip.
6861 
6862 void TPad::CloseToolTip(TObject *tip)
6863 {
6864  if (!tip) return;
6865  // tip->Hide();
6866  gROOT->ProcessLineFast(Form("((TGToolTip*)0x%lx)->Hide()",(Long_t)tip));
6867 }
6868 
6869 ////////////////////////////////////////////////////////////////////////////////
6870 /// Deprecated: use TPad::GetViewer3D() instead
6871 
6872 void TPad::x3d(Option_t *type)
6873 {
6874  ::Info("TPad::x3d()", "This function is deprecated. Use %s->GetViewer3D(\"x3d\") instead",this->GetName());
6875 
6876  // Default on GetViewer3D is pad - for x3d it was x3d...
6877  if (!type || !type[0]) {
6878  type = "x3d";
6879  }
6880  GetViewer3D(type);
6881 }
6882 
6883 ////////////////////////////////////////////////////////////////////////////////
6884 /// Create/obtain handle to 3D viewer. Valid types are:
6885 /// - 'pad' - pad drawing via TViewer3DPad
6886 /// any others registered with plugin manager supporting TVirtualViewer3D
6887 /// If an invalid/null type is requested then the current viewer is returned
6888 /// (if any), otherwise a default 'pad' type is returned
6889 
6890 TVirtualViewer3D *TPad::GetViewer3D(Option_t *type)
6891 {
6892  Bool_t validType = kFALSE;
6893 
6894  if ( (!type || !type[0] || (strstr(type, "gl") && !strstr(type, "ogl"))) && !fCanvas->UseGL())
6895  type = "pad";
6896 
6897  if (type && type[0]) {
6898 
6899  if (gPluginMgr->FindHandler("TVirtualViewer3D", type))
6900  validType = kTRUE;
6901 
6902  }
6903 
6904  // Invalid/null type requested?
6905  if (!validType) {
6906  // Return current viewer if there is one
6907  if (fViewer3D) {
6908  return fViewer3D;
6909  }
6910  // otherwise default to the pad
6911  else {
6912  type = "pad";
6913  }
6914  }
6915 
6916  // Ensure we can create the new viewer before removing any existing one
6917  TVirtualViewer3D *newViewer = 0;
6918 
6919  Bool_t createdExternal = kFALSE;
6920 
6921  // External viewers need to be created via plugin manager via interface...
6922  if (!strstr(type,"pad")) {
6923  newViewer = TVirtualViewer3D::Viewer3D(this,type);
6924 
6925  if (!newViewer) {
6926  Warning("TPad::CreateViewer3D", "Cannot create 3D viewer of type: %s", type);
6927 
6928  // Return the existing viewer
6929  return fViewer3D;
6930  }
6931 
6932  if (strstr(type, "gl") && !strstr(type, "ogl"))
6933  fEmbeddedGL = kTRUE, fCopyGLDevice = kTRUE, Modified();
6934  else
6935  createdExternal = kTRUE;
6936 
6937  } else
6938  newViewer = new TViewer3DPad(*this);
6939 
6940  // If we had a previous viewer destroy it now
6941  // In this case we do take responsibility for destroying viewer
6942  // c.f. ReleaseViewer3D
6943  delete fViewer3D;
6944 
6945  // Set and return new viewer
6946  fViewer3D = newViewer;
6947 
6948  // Ensure any new external viewer is painted
6949  // For internal TViewer3DPad type we assume this is being
6950  // create on demand due to a paint - so this is not required
6951  if (createdExternal) {
6952  Modified();
6953  Update();
6954  }
6955 
6956  return fViewer3D;
6957 }
6958 
6959 ////////////////////////////////////////////////////////////////////////////////
6960 /// Release current (external) viewer
6961 
6962 void TPad::ReleaseViewer3D(Option_t * /*type*/ )
6963 {
6964  fViewer3D = nullptr;
6965 
6966  // We would like to ensure the pad is repainted
6967  // when external viewer is closed down. However
6968  // a modify/paint call here will repaint the pad
6969  // before the external viewer window actually closes.
6970  // So the pad would have to be redraw twice over.
6971  // Currently we just have to live with the pad staying blank
6972  // any click in pad will refresh.
6973 }
6974 
6975 ////////////////////////////////////////////////////////////////////////////////
6976 /// Get GL device.
6977 
6978 Int_t TPad::GetGLDevice()
6979 {
6980  return fGLDevice;
6981 }
6982 
6983 ////////////////////////////////////////////////////////////////////////////////
6984 /// Emit RecordPave() signal.
6985 
6986 void TPad::RecordPave(const TObject *obj)
6987 {
6988  Emit("RecordPave(const TObject*)", (Long_t)obj);
6989 }
6990 
6991 ////////////////////////////////////////////////////////////////////////////////
6992 /// Emit RecordLatex() signal.
6993 
6994 void TPad::RecordLatex(const TObject *obj)
6995 {
6996  Emit("RecordLatex(const TObject*)", (Long_t)obj);
6997 }
6998 
6999 ////////////////////////////////////////////////////////////////////////////////
7000 /// Get pad painter from TCanvas.
7001 
7002 TVirtualPadPainter *TPad::GetPainter()
7003 {
7004  if (!fCanvas) return nullptr;
7005  return fCanvas->GetCanvasPainter();
7006 }
7007 
7008 ////////////////////////////////////////////////////////////////////////////////
7009 /// Return the bounding Box of the Pad
7010 
7011 Rectangle_t TPad::GetBBox()
7012 {
7013  Rectangle_t BBox;
7014  BBox.fX = gPad->XtoPixel(fXlowNDC*(gPad->GetX2()-gPad->GetX1()) + gPad->GetX1());
7015  BBox.fY = gPad->YtoPixel((fYlowNDC+fHNDC)*(gPad->GetY2()-gPad->GetY1()) + gPad->GetY1());
7016  BBox.fWidth = gPad->XtoPixel((fXlowNDC+fWNDC)*(gPad->GetX2()-gPad->GetX1()) + gPad->GetX1()) - gPad->XtoPixel(fXlowNDC*(gPad->GetX2()-gPad->GetX1()) + gPad->GetX1());
7017  BBox.fHeight = gPad->YtoPixel((fYlowNDC)*(gPad->GetY2()-gPad->GetY1()) + gPad->GetY1()) - gPad->YtoPixel((fYlowNDC+fHNDC)*(gPad->GetY2()-gPad->GetY1()) + gPad->GetY1());
7018  return (BBox);
7019 }
7020 
7021 
7022 ////////////////////////////////////////////////////////////////////////////////
7023 /// Return the center of the Pad as TPoint in pixels
7024 
7025 TPoint TPad::GetBBoxCenter()
7026 {
7027  TPoint p;
7028  Double_t x = ((fXlowNDC+0.5*fWNDC)*(gPad->GetX2()-gPad->GetX1())) + gPad->GetX1();
7029  Double_t y = ((fYlowNDC+0.5*fHNDC)*(gPad->GetY2()-gPad->GetY1())) + gPad->GetY1();
7030 
7031  p.SetX(gPad->XtoPixel(x));
7032  p.SetY(gPad->YtoPixel(y));
7033  return(p);
7034 }
7035 
7036 ////////////////////////////////////////////////////////////////////////////////
7037 /// Set center of the Pad
7038 
7039 void TPad::SetBBoxCenter(const TPoint &p)
7040 {
7041  fXlowNDC = (gPad->PixeltoX(p.GetX()) - gPad->GetX1())/(gPad->GetX2()-gPad->GetX1())-0.5*fWNDC;
7042  fYlowNDC = (gPad->PixeltoY(p.GetY()-gPad->VtoPixel(0)) - gPad->GetY1())/(gPad->GetY2()-gPad->GetY1())-0.5*fHNDC;
7043  ResizePad();
7044 }
7045 
7046 ////////////////////////////////////////////////////////////////////////////////
7047 /// Set X coordinate of the center of the Pad
7048 
7049 void TPad::SetBBoxCenterX(const Int_t x)
7050 {
7051  fXlowNDC = (gPad->PixeltoX(x) - gPad->GetX1())/(gPad->GetX2()-gPad->GetX1())-0.5*fWNDC;
7052  ResizePad();
7053 }
7054 
7055 ////////////////////////////////////////////////////////////////////////////////
7056 /// Set Y coordinate of the center of the Pad
7057 
7058 void TPad::SetBBoxCenterY(const Int_t y)
7059 {
7060  fYlowNDC = (gPad->PixeltoY(y-gPad->VtoPixel(0)) - gPad->GetY1())/(gPad->GetY2()-gPad->GetY1())-0.5*fHNDC;
7061  ResizePad();
7062 }
7063 
7064 ////////////////////////////////////////////////////////////////////////////////
7065 /// Set lefthandside of BoundingBox to a value
7066 /// (resize in x direction on left)
7067 
7068 void TPad::SetBBoxX1(const Int_t x)
7069 {
7070  fXlowNDC = (gPad->PixeltoX(x) - gPad->GetX1())/(gPad->GetX2()-gPad->GetX1());
7071  fWNDC = fXUpNDC - fXlowNDC;
7072  ResizePad();
7073 }
7074 
7075 ////////////////////////////////////////////////////////////////////////////////
7076 /// Set right hand side of BoundingBox to a value
7077 /// (resize in x direction on right)
7078 
7079 void TPad::SetBBoxX2(const Int_t x)
7080 {
7081  fWNDC = (gPad->PixeltoX(x) - gPad->GetX1())/(gPad->GetX2()-gPad->GetX1())-fXlowNDC;
7082  ResizePad();
7083 }
7084 
7085 ////////////////////////////////////////////////////////////////////////////////
7086 /// Set top of BoundingBox to a value (resize in y direction on top)
7087 
7088 void TPad::SetBBoxY1(const Int_t y)
7089 {
7090  fHNDC = (gPad->PixeltoY(y-gPad->VtoPixel(0)) - gPad->GetY1())/(gPad->GetY2()-gPad->GetY1())-fYlowNDC;
7091  ResizePad();
7092 }
7093 
7094 ////////////////////////////////////////////////////////////////////////////////
7095 /// Set bottom of BoundingBox to a value
7096 /// (resize in y direction on bottom)
7097 
7098 void TPad::SetBBoxY2(const Int_t y)
7099 {
7100  fYlowNDC = (gPad->PixeltoY(y-gPad->VtoPixel(0)) - gPad->GetY1())/(gPad->GetY2()-gPad->GetY1());
7101  fHNDC = fYUpNDC - fYlowNDC;
7102  ResizePad();
7103 }
7104