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