Logo ROOT  
Reference Guide
TPad.cxx
Go to the documentation of this file.
1// @(#)root/gpad:$Id$
2// Author: Rene Brun 12/12/94
3
4/*************************************************************************
5 * Copyright (C) 1995-2000, Rene Brun and Fons Rademakers. *
6 * All rights reserved. *
7 * *
8 * For the licensing terms see $ROOTSYS/LICENSE. *
9 * For the list of contributors see $ROOTSYS/README/CREDITS. *
10 *************************************************************************/
11
12#include <cstring>
13#include <cstdlib>
14#include <iostream>
15#include <memory>
16
17#include "TROOT.h"
18#include "TBuffer.h"
19#include "TError.h"
20#include "TMath.h"
21#include "TSystem.h"
22#include "TStyle.h"
23#include "TFile.h"
24#include "TH1.h"
25#include "TH2.h"
26#include "TH3.h"
27#include "TClass.h"
28#include "TBaseClass.h"
29#include "TClassTable.h"
30#include "TVirtualPS.h"
31#include "TVirtualX.h"
32#include "TVirtualViewer3D.h"
33#include "TView.h"
34#include "TPoint.h"
35#include "TGraph.h"
36#include "TMultiGraph.h"
37#include "THStack.h"
38#include "TPaveText.h"
39#include "TPaveStats.h"
40#include "TGroupButton.h"
41#include "TBrowser.h"
42#include "TVirtualGL.h"
43#include "TString.h"
44#include "TDataMember.h"
45#include "TMethod.h"
46#include "TDataType.h"
47#include "TFrame.h"
48#include "TExec.h"
49#include "TDatime.h"
50#include "TColor.h"
51#include "TCanvas.h"
52#include "TPluginManager.h"
53#include "TEnv.h"
54#include "TImage.h"
55#include "TViewer3DPad.h"
56#include "TCreatePrimitives.h"
57#include "TLegend.h"
58#include "TAtt3D.h"
59#include "TVirtualPadPainter.h"
60#include "strlcpy.h"
61#include "snprintf.h"
62
63#include "TVirtualMutex.h"
64
65static Int_t gReadLevel = 0;
66
68
70
71/** \class TPad
72\ingroup gpad
73
74The most important graphics class in the ROOT system.
75
76A Pad is contained in a Canvas.
77
78A Pad may contain other pads (unlimited pad hierarchy).
79
80A pad is a linked list of primitives of any type (graphics objects,
81histograms, detectors, tracks, etc.).
82
83Adding a new element into a pad is in general performed by the Draw
84member function of the object classes.
85
86It is important to realize that the pad is a linked list of references
87to the original object.
88For example, in case of a histogram, the histogram.Draw() operation
89only stores a reference to the histogram object and not a graphical
90representation of this histogram.
91When the mouse is used to change (say the bin content), the bin content
92of the original histogram is changed.
93
94The convention used in ROOT is that a Draw operation only adds
95a reference to the object. The effective drawing is performed
96when the canvas receives a signal to be painted.
97
98\image html gpad_pad1.png
99
100This signal is generally sent when typing carriage return in the
101command input or when a graphical operation has been performed on one
102of the pads of this canvas.
103When a Canvas/Pad is repainted, the member function Paint for all
104objects in the Pad linked list is invoked.
105
106\image html gpad_pad2.png
107
108When the mouse is moved on the Pad, The member function DistancetoPrimitive
109is called for all the elements in the pad. DistancetoPrimitive returns
110the distance in pixels to this object.
111
112When the object is within the distance window, the member function
113ExecuteEvent is called for this object.
114
115In ExecuteEvent, move, changes can be performed on the object.
116
117For examples of DistancetoPrimitive and ExecuteEvent functions,
118see classes
119~~~ {.cpp}
120 TLine::DistancetoPrimitive, TLine::ExecuteEvent
121 TBox::DistancetoPrimitive, TBox::ExecuteEvent
122 TH1::DistancetoPrimitive, TH1::ExecuteEvent
123~~~
124A Pad supports linear and log scales coordinate systems.
125The transformation coefficients are explained in TPad::ResizePad.
126*/
127
128////////////////////////////////////////////////////////////////////////////////
129/// Pad default constructor.
130
132{
133 fModified = kTRUE;
134 fTip = nullptr;
135 fPadPointer = nullptr;
136 fPrimitives = nullptr;
137 fExecs = nullptr;
138 fCanvas = nullptr;
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 = nullptr;
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 = nullptr;
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 = nullptr;
198 fView = nullptr;
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 = nullptr;
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
246TPad::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{
252 fTip = nullptr;
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 = nullptr;
261 fTheta = 30;
262 fPhi = 30;
267 fFrame = nullptr;
268 fView = nullptr;
269 fPadPaint = 0;
270 fPadView3D = nullptr;
271 fPixmapID = -1; // -1 means pixmap will be created by ResizePad()
274 fNumber = 0;
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;
313
315 fAspectRatio = 0.;
316
319 fCollideGrid = nullptr;
320 fCGnx = 0;
321 fCGny = 0;
322
323 fViewer3D = nullptr;
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 if (xup-xlow <= 0) {
349 Error("TPad", "illegal width: %f", xup-xlow);
350 goto zombie;
351 }
352 if (yup-ylow <= 0) {
353 Error("TPad", "illegal height: %f", yup-ylow);
354 goto zombie;
355 }
356
360
361 fUxmin = fUymin = fUxmax = fUymax = 0;
362
363 // Set pad parameters and Compute conversion coefficients
364 SetPad(name, title, xlow, ylow, xup, yup, color, bordersize, bordermode);
365 Range(0, 0, 1, 1);
368
369 padsav->cd();
370 return;
371
372zombie:
373 // error in creating pad occurred, make this pad a zombie
374 MakeZombie();
375 padsav->cd();
376}
377
378
379////////////////////////////////////////////////////////////////////////////////
380/// Pad destructor.
381
383{
384 if (!TestBit(kNotDeleted)) return;
385 Close();
388 auto primitives = fPrimitives;
389 // In some cases, fPrimitives has the kMustCleanup bit set which will lead
390 // its destructor to call RecursiveRemove and since this pad is still
391 // likely to be (indirectly) in the list of cleanups, we must set
392 // fPrimitives to nullptr to avoid TPad::RecursiveRemove from calling
393 // a member function of a partially destructed object.
394 fPrimitives = nullptr;
395 delete primitives;
397 delete fViewer3D;
398 if (fCollideGrid) delete [] fCollideGrid;
399
400 // Required since we overload TObject::Hash.
402 if (this == gPad) gPad=nullptr;
403}
404
405////////////////////////////////////////////////////////////////////////////////
406/// Add a new TExec object to the list of Execs.
407///
408/// When an event occurs in the pad (mouse click, etc) the list of C++ commands
409/// in the list of Execs are executed via TPad::AutoExec.
410///
411/// When a pad event occurs (mouse move, click, etc) all the commands
412/// contained in the fExecs list are executed in the order found in the list.
413///
414/// This facility is activated by default. It can be deactivated by using
415/// the canvas "Option" menu.
416///
417/// The following examples of TExec commands are provided in the tutorials:
418/// macros exec1.C and exec2.C.
419///
420/// ### Example1 of use of exec1.C
421///
422/// ~~~ {.cpp}
423/// Root > TFile f("hsimple.root")
424/// Root > hpx.Draw()
425/// Root > c1.AddExec("ex1",".x exec1.C")
426/// ~~~
427///
428/// At this point you can use the mouse to click on the contour of
429/// the histogram hpx. When the mouse is clicked, the bin number and its
430/// contents are printed.
431///
432/// ### Example2 of use of exec1.C
433///
434/// ~~~ {.cpp}
435/// Root > TFile f("hsimple.root")
436/// Root > hpxpy.Draw()
437/// Root > c1.AddExec("ex2",".x exec2.C")
438/// ~~~
439///
440/// When moving the mouse in the canvas, a second canvas shows the
441/// projection along X of the bin corresponding to the Y position
442/// of the mouse. The resulting histogram is fitted with a gaussian.
443/// A "dynamic" line shows the current bin position in Y.
444/// This more elaborated example can be used as a starting point
445/// to develop more powerful interactive applications exploiting the C++
446/// interpreter as a development engine.
447
448void TPad::AddExec(const char *name, const char*command)
449{
450 if (!fExecs) fExecs = new TList;
451 TExec *ex = new TExec(name,command);
452 fExecs->Add(ex);
453}
454
455////////////////////////////////////////////////////////////////////////////////
456/// Execute the list of Execs when a pad event occurs.
457
459{
461
462 if (!fExecs) fExecs = new TList;
463 TIter next(fExecs);
464 TExec *exec;
465 while ((exec = (TExec*)next())) {
466 exec->Exec();
467 }
468}
469
470////////////////////////////////////////////////////////////////////////////////
471/// Browse pad.
472
474{
475 cd();
477}
478
479////////////////////////////////////////////////////////////////////////////////
480/// Build a legend from the graphical objects in the pad.
481///
482/// A simple method to build automatically a TLegend from the primitives in a TPad.
483///
484/// Only those deriving from TAttLine, TAttMarker and TAttFill are added, excluding
485/// TPave and TFrame derived classes.
486///
487/// \return The built TLegend
488///
489/// \param[in] x1, y1, x2, y2 The TLegend coordinates
490/// \param[in] title The legend title. By default it is " "
491/// \param[in] option The TLegend option
492///
493/// The caller program owns the returned TLegend.
494///
495/// If the pad contains some TMultiGraph or THStack the individual
496/// graphs or histograms in them are added to the TLegend.
497///
498/// ### Automatic placement of the legend
499/// If `x1` is equal to `x2` and `y1` is equal to `y2` the legend will be automatically
500/// placed to avoid overlapping with the existing primitives already displayed.
501/// `x1` is considered as the width of the legend and `y1` the height. By default
502/// the legend is automatically placed with width = `x1`= `x2` = 0.3 and
503/// height = `y1`= `y2` = 0.21.
504
506 const char* title, Option_t *option)
507{
509 if (!lop) return 0;
510 TLegend *leg=0;
511 TIter next(lop);
512 TString mes;
513 TObject *o=0;
514 TString opt("");
515 while( (o=next()) ) {
518 ( !(o->InheritsFrom(TFrame::Class())) && !(o->InheritsFrom(TPave::Class())) )) {
519 if (!leg) leg = new TLegend(x1, y1, x2, y2, title);
520 if (o->InheritsFrom(TNamed::Class()) && strlen(((TNamed *)o)->GetTitle()))
521 mes = ((TNamed *)o)->GetTitle();
522 else if (strlen(o->GetName()))
523 mes = o->GetName();
524 else
525 mes = o->ClassName();
526 if (strlen(option)) {
527 opt = option;
528 } else {
529 if (o->InheritsFrom(TAttLine::Class())) opt += "l";
530 if (o->InheritsFrom(TAttMarker::Class())) opt += "p";
531 if (o->InheritsFrom(TAttFill::Class())) opt += "f";
532 }
533 leg->AddEntry(o,mes.Data(),opt.Data());
534 } else if ( o->InheritsFrom(TMultiGraph::Class() ) ) {
535 if (!leg) leg = new TLegend(x1, y1, x2, y2, title);
536 TList * grlist = ((TMultiGraph *)o)->GetListOfGraphs();
537 TIter nextgraph(grlist);
538 TGraph * gr;
539 TObject * obj;
540 while ((obj = nextgraph())) {
541 gr = (TGraph*) obj;
542 if (strlen(gr->GetTitle())) mes = gr->GetTitle();
543 else if (strlen(gr->GetName())) mes = gr->GetName();
544 else mes = gr->ClassName();
545 if (strlen(option)) opt = option;
546 else opt = "lpf";
547 leg->AddEntry( obj, mes.Data(), opt );
548 }
549 } else if ( o->InheritsFrom(THStack::Class() ) ) {
550 if (!leg) leg = new TLegend(x1, y1, x2, y2, title);
551 TList * hlist = ((THStack *)o)->GetHists();
552 TIter nexthist(hlist);
553 TH1 * hist;
554 TObject * obj;
555 while ((obj = nexthist())) {
556 hist = (TH1*) obj;
557 if (strlen(hist->GetTitle())) mes = hist->GetTitle();
558 else if (strlen(hist->GetName())) mes = hist->GetName();
559 else mes = hist->ClassName();
560 if (strlen(option)) opt = option;
561 else opt = "lpf";
562 leg->AddEntry( obj, mes.Data(), opt );
563 }
564 }
565 opt = "";
566 }
567 if (leg) {
568 TVirtualPad *gpadsave;
569 gpadsave = gPad;
570 this->cd();
571 leg->Draw();
572 gpadsave->cd();
573 } else {
574 Info("BuildLegend(void)","No object to build a TLegend.");
575 }
576 return leg;
577}
578
579////////////////////////////////////////////////////////////////////////////////
580/// Set Current pad.
581///
582/// When a canvas/pad is divided via TPad::Divide, one can directly
583/// set the current path to one of the subdivisions.
584/// See TPad::Divide for the convention to number sub-pads.
585///
586/// Returns the new current pad, or 0 in case of failure.
587///
588/// For example:
589/// ~~~ {.cpp}
590/// c1.Divide(2,3); // create 6 pads (2 divisions along x, 3 along y).
591/// ~~~
592/// To set the current pad to the bottom right pad, do
593/// ~~~ {.cpp}
594/// c1.cd(6);
595/// ~~~
596/// Note1: c1.cd() is equivalent to c1.cd(0) and sets the current pad
597/// to c1 itself.
598///
599/// Note2: after a statement like c1.cd(6), the global variable gPad
600/// points to the current pad. One can use gPad to set attributes
601/// of the current pad.
602///
603/// Note3: One can get a pointer to one of the sub-pads of pad with:
604/// TPad *subpad = (TPad*)pad->GetPad(subpadnumber);
605
607{
608 if (!subpadnumber) {
609 gPad = this;
610 if (!gPad->IsBatch() && GetPainter()) GetPainter()->SelectDrawable(fPixmapID);
611 if (!fPrimitives) fPrimitives = new TList;
612 return gPad;
613 }
614
615 TObject *obj;
616 if (!fPrimitives) fPrimitives = new TList;
617 TIter next(fPrimitives);
618 while ((obj = next())) {
619 if (obj->InheritsFrom(TPad::Class())) {
620 Int_t n = ((TPad*)obj)->GetNumber();
621 if (n == subpadnumber) {
622 return ((TPad*)obj)->cd();
623 }
624 }
625 }
626 return 0;
627}
628
629////////////////////////////////////////////////////////////////////////////////
630/// Delete all pad primitives.
631///
632/// If the bit kClearAfterCR has been set for this pad, the Clear function
633/// will execute only after having pressed a CarriageReturn
634/// Set the bit with `mypad->SetBit(TPad::kClearAfterCR)`
635
637{
638 if (!IsEditable()) return;
639
641
642 if (!fPadPaint) {
645 if (fFrame) {
646 if (fFrame->TestBit(kNotDeleted)) delete fFrame;
647 fFrame = nullptr;
648 }
649 }
650 if (fCanvas) fCanvas->Cleared(this);
651
652 cd();
653
654 if (TestBit(kClearAfterCR)) {
655 // Intentional do not use the return value of getchar,
656 // we just want to get it and forget it
657 getchar();
658 }
659
660 if (!gPad->IsBatch() && GetPainter()) GetPainter()->ClearDrawable();
661 if (gVirtualPS && gPad == gPad->GetCanvas()) gVirtualPS->NewPage();
662
664 fCrosshairPos = 0;
666 if (fCollideGrid) {
667 delete [] fCollideGrid;
668 fCollideGrid = nullptr;
669 fCGnx = 0;
670 fCGny = 0;
671 }
673}
674
675////////////////////////////////////////////////////////////////////////////////
676/// Clipping routine: Cohen Sutherland algorithm.
677///
678/// - If Clip ==2 the segment is outside the boundary.
679/// - If Clip ==1 the segment has one point outside the boundary.
680/// - If Clip ==0 the segment is inside the boundary.
681///
682/// \param[inout] x[],y[] Segment coordinates (2 points)
683/// \param[in] xclipl,yclipb,xclipr,yclipt Clipping boundary
684
685Int_t TPad::Clip(Float_t *x, Float_t *y, Float_t xclipl, Float_t yclipb, Float_t xclipr, Float_t yclipt)
686{
687 const Float_t kP=10000;
688 Int_t clip = 0;
689
690 for (Int_t i=0;i<2;i++) {
691 if (TMath::Abs(xclipl-x[i]) <= TMath::Abs(xclipr-xclipl)/kP) x[i] = xclipl;
692 if (TMath::Abs(xclipr-x[i]) <= TMath::Abs(xclipr-xclipl)/kP) x[i] = xclipr;
693 if (TMath::Abs(yclipb-y[i]) <= TMath::Abs(yclipt-yclipb)/kP) y[i] = yclipb;
694 if (TMath::Abs(yclipt-y[i]) <= TMath::Abs(yclipt-yclipb)/kP) y[i] = yclipt;
695 }
696
697 // Compute the first endpoint codes.
698 Int_t code1 = ClippingCode(x[0],y[0],xclipl,yclipb,xclipr,yclipt);
699 Int_t code2 = ClippingCode(x[1],y[1],xclipl,yclipb,xclipr,yclipt);
700
701 Double_t xt=0, yt=0;
702 Int_t clipped = 0; //this variable could be used in a future version
703 while(code1 + code2) {
704 clipped = 1;
705
706 // The line lies entirely outside the clipping boundary
707 if (code1&code2) {
708 clip = 2;
709 return clip;
710 }
711
712 // The line is subdivided into several parts
713 Int_t ic = code1;
714 if (ic == 0) ic = code2;
715 if (ic & 0x1) {
716 yt = y[0] + (y[1]-y[0])*(xclipl-x[0])/(x[1]-x[0]);
717 xt = xclipl;
718 }
719 if (ic & 0x2) {
720 yt = y[0] + (y[1]-y[0])*(xclipr-x[0])/(x[1]-x[0]);
721 xt = xclipr;
722 }
723 if (ic & 0x4) {
724 xt = x[0] + (x[1]-x[0])*(yclipb-y[0])/(y[1]-y[0]);
725 yt = yclipb;
726 }
727 if (ic & 0x8) {
728 xt = x[0] + (x[1]-x[0])*(yclipt-y[0])/(y[1]-y[0]);
729 yt = yclipt;
730 }
731 if (ic == code1) {
732 x[0] = xt;
733 y[0] = yt;
734 code1 = ClippingCode(xt,yt,xclipl,yclipb,xclipr,yclipt);
735 } else {
736 x[1] = xt;
737 y[1] = yt;
738 code2 = ClippingCode(xt,yt,xclipl,yclipb,xclipr,yclipt);
739 }
740 }
741 clip = clipped;
742 return clip;
743}
744
745/// @copydoc TPad::Clip(Float_t*,Float_t*,Float_t,Float_t,Float_t,Float_t)
746
748{
749 const Double_t kP=10000;
750 Int_t clip = 0;
751
752 for (Int_t i=0;i<2;i++) {
753 if (TMath::Abs(xclipl-x[i]) <= TMath::Abs(xclipr-xclipl)/kP) x[i] = xclipl;
754 if (TMath::Abs(xclipr-x[i]) <= TMath::Abs(xclipr-xclipl)/kP) x[i] = xclipr;
755 if (TMath::Abs(yclipb-y[i]) <= TMath::Abs(yclipt-yclipb)/kP) y[i] = yclipb;
756 if (TMath::Abs(yclipt-y[i]) <= TMath::Abs(yclipt-yclipb)/kP) y[i] = yclipt;
757 }
758
759 // Compute the first endpoint codes.
760 Int_t code1 = 0;
761 if (x[0] < xclipl) code1 = code1 | 0x1;
762 if (x[0] > xclipr) code1 = code1 | 0x2;
763 if (y[0] < yclipb) code1 = code1 | 0x4;
764 if (y[0] > yclipt) code1 = code1 | 0x8;
765 Int_t code2 = 0;
766 if (x[1] < xclipl) code2 = code2 | 0x1;
767 if (x[1] > xclipr) code2 = code2 | 0x2;
768 if (y[1] < yclipb) code2 = code2 | 0x4;
769 if (y[1] > yclipt) code2 = code2 | 0x8;
770
771 Double_t xt=0, yt=0;
772 Int_t clipped = 0; //this variable could be used in a future version
773 while(code1 + code2) {
774 clipped = 1;
775
776 // The line lies entirely outside the clipping boundary
777 if (code1&code2) {
778 clip = 2;
779 return clip;
780 }
781
782 // The line is subdivided into several parts
783 Int_t ic = code1;
784 if (ic == 0) ic = code2;
785 if (ic & 0x1) {
786 yt = y[0] + (y[1]-y[0])*(xclipl-x[0])/(x[1]-x[0]);
787 xt = xclipl;
788 }
789 if (ic & 0x2) {
790 yt = y[0] + (y[1]-y[0])*(xclipr-x[0])/(x[1]-x[0]);
791 xt = xclipr;
792 }
793 if (ic & 0x4) {
794 xt = x[0] + (x[1]-x[0])*(yclipb-y[0])/(y[1]-y[0]);
795 yt = yclipb;
796 }
797 if (ic & 0x8) {
798 xt = x[0] + (x[1]-x[0])*(yclipt-y[0])/(y[1]-y[0]);
799 yt = yclipt;
800 }
801 if (ic == code1) {
802 x[0] = xt;
803 y[0] = yt;
804 code1 = ClippingCode(xt,yt,xclipl,yclipb,xclipr,yclipt);
805 } else {
806 x[1] = xt;
807 y[1] = yt;
808 code2 = ClippingCode(xt,yt,xclipl,yclipb,xclipr,yclipt);
809 }
810 }
811 clip = clipped;
812 return clip;
813}
814
815////////////////////////////////////////////////////////////////////////////////
816/// Compute the endpoint codes for TPad::Clip.
817
819{
820 Int_t code = 0;
821 if (x < xcl1) code = code | 0x1;
822 if (x > xcl2) code = code | 0x2;
823 if (y < ycl1) code = code | 0x4;
824 if (y > ycl2) code = code | 0x8;
825 return code;
826}
827
828////////////////////////////////////////////////////////////////////////////////
829/// Clip polygon using the Sutherland-Hodgman algorithm.
830///
831/// \param[in] n Number of points in the polygon to
832/// be clipped
833/// \param[in] x,y Polygon x[n], y[n] do be clipped vertices
834/// \param[in] xclipl,yclipb,xclipr,yclipt Clipping boundary
835/// \param[out] nn Number of points in xc and yc
836/// \param[out] xc,yc Clipped polygon vertices. The Int_t
837/// returned by this function is
838/// the number of points in the clipped
839/// polygon. These vectors must
840/// be allocated by the calling function.
841/// A size of 2*n for each is
842/// enough.
843///
844/// Sutherland and Hodgman's polygon-clipping algorithm uses a divide-and-conquer
845/// strategy: It solves a series of simple and identical problems that, when
846/// combined, solve the overall problem. The simple problem is to clip a polygon
847/// against a single infinite clip edge. Four clip edges, each defining one boundary
848/// of the clip rectangle, successively clip a polygon against a clip rectangle.
849///
850/// Steps of Sutherland-Hodgman's polygon-clipping algorithm:
851///
852/// * Polygons can be clipped against each edge of the window one at a time.
853/// Windows/edge intersections, if any, are easy to find since the X or Y coordinates
854/// are already known.
855/// * Vertices which are kept after clipping against one window edge are saved for
856/// clipping against the remaining edges.
857/// * Note that the number of vertices usually changes and will often increases.
858///
859/// The clip boundary determines a visible and invisible region. The edges from
860/// vertex i to vertex i+1 can be one of four types:
861///
862/// * Case 1 : Wholly inside visible region - save endpoint
863/// * Case 2 : Exit visible region - save the intersection
864/// * Case 3 : Wholly outside visible region - save nothing
865/// * Case 4 : Enter visible region - save intersection and endpoint
866
868{
869 Int_t nc, nc2;
870 Double_t x1, y1, x2, y2, slope; // Segment to be clipped
871
872 Double_t *xc2 = new Double_t[nn];
873 Double_t *yc2 = new Double_t[nn];
874
875 // Clip against the left boundary
876 x1 = x[n-1]; y1 = y[n-1];
877 nc2 = 0;
878 Int_t i;
879 for (i=0; i<n; i++) {
880 x2 = x[i]; y2 = y[i];
881 if (x1 == x2) {
882 slope = 0;
883 } else {
884 slope = (y2-y1)/(x2-x1);
885 }
886 if (x1 >= xclipl) {
887 if (x2 < xclipl) {
888 xc2[nc2] = xclipl; yc2[nc2++] = slope*(xclipl-x1)+y1;
889 } else {
890 xc2[nc2] = x2; yc2[nc2++] = y2;
891 }
892 } else {
893 if (x2 >= xclipl) {
894 xc2[nc2] = xclipl; yc2[nc2++] = slope*(xclipl-x1)+y1;
895 xc2[nc2] = x2; yc2[nc2++] = y2;
896 }
897 }
898 x1 = x2; y1 = y2;
899 }
900
901 // Clip against the top boundary
902 x1 = xc2[nc2-1]; y1 = yc2[nc2-1];
903 nc = 0;
904 for (i=0; i<nc2; i++) {
905 x2 = xc2[i]; y2 = yc2[i];
906 if (y1 == y2) {
907 slope = 0;
908 } else {
909 slope = (x2-x1)/(y2-y1);
910 }
911 if (y1 <= yclipt) {
912 if (y2 > yclipt) {
913 xc[nc] = x1+(yclipt-y1)*slope; yc[nc++] = yclipt;
914 } else {
915 xc[nc] = x2; yc[nc++] = y2;
916 }
917 } else {
918 if (y2 <= yclipt) {
919 xc[nc] = x1+(yclipt-y1)*slope; yc[nc++] = yclipt;
920 xc[nc] = x2; yc[nc++] = y2;
921 }
922 }
923 x1 = x2; y1 = y2;
924 }
925
926 if (nc>0) {
927
928 // Clip against the right boundary
929 x1 = xc[nc-1]; y1 = yc[nc-1];
930 nc2 = 0;
931 for (i=0; i<nc; i++) {
932 x2 = xc[i]; y2 = yc[i];
933 if (x1 == x2) {
934 slope = 0;
935 } else {
936 slope = (y2-y1)/(x2-x1);
937 }
938 if (x1 <= xclipr) {
939 if (x2 > xclipr) {
940 xc2[nc2] = xclipr; yc2[nc2++] = slope*(xclipr-x1)+y1;
941 } else {
942 xc2[nc2] = x2; yc2[nc2++] = y2;
943 }
944 } else {
945 if (x2 <= xclipr) {
946 xc2[nc2] = xclipr; yc2[nc2++] = slope*(xclipr-x1)+y1;
947 xc2[nc2] = x2; yc2[nc2++] = y2;
948 }
949 }
950 x1 = x2; y1 = y2;
951 }
952
953 // Clip against the bottom boundary
954 x1 = xc2[nc2-1]; y1 = yc2[nc2-1];
955 nc = 0;
956 for (i=0; i<nc2; i++) {
957 x2 = xc2[i]; y2 = yc2[i];
958 if (y1 == y2) {
959 slope = 0;
960 } else {
961 slope = (x2-x1)/(y2-y1);
962 }
963 if (y1 >= yclipb) {
964 if (y2 < yclipb) {
965 xc[nc] = x1+(yclipb-y1)*slope; yc[nc++] = yclipb;
966 } else {
967 xc[nc] = x2; yc[nc++] = y2;
968 }
969 } else {
970 if (y2 >= yclipb) {
971 xc[nc] = x1+(yclipb-y1)*slope; yc[nc++] = yclipb;
972 xc[nc] = x2; yc[nc++] = y2;
973 }
974 }
975 x1 = x2; y1 = y2;
976 }
977 }
978
979 delete [] xc2;
980 delete [] yc2;
981
982 if (nc < 3) nc =0;
983 return nc;
984}
985
986////////////////////////////////////////////////////////////////////////////////
987/// Delete all primitives in pad and pad itself.
988/// Pad cannot be used anymore after this call.
989/// Emits signal "Closed()".
990
992{
993 if (!TestBit(kNotDeleted)) return;
994 if (!fMother) return;
995 if (!fMother->TestBit(kNotDeleted)) return;
996
997 if (fPrimitives)
999 if (fView) {
1000 if (fView->TestBit(kNotDeleted)) delete fView;
1001 fView = nullptr;
1002 }
1003 if (fFrame) {
1004 if (fFrame->TestBit(kNotDeleted)) delete fFrame;
1005 fFrame = nullptr;
1006 }
1007
1008 // emit signal
1009 if (IsA() != TCanvas::Class())
1010 Closed();
1011
1012 if (fPixmapID != -1) {
1013 if (gPad) {
1014 if (!gPad->IsBatch() && GetPainter())
1016 }
1017 fPixmapID = -1;
1018
1019 if (!gROOT->GetListOfCanvases()) return;
1020 if (fMother == this) {
1021 gROOT->GetListOfCanvases()->Remove(this);
1022 return; // in case of TCanvas
1023 }
1024
1025 // remove from the mother's list of primitives
1026 if (fMother) {
1029
1030 if (gPad == this) fMother->cd();
1031 }
1032 if (fCanvas) {
1033 if (fCanvas->GetPadSave() == this)
1035 if (fCanvas->GetSelectedPad() == this)
1037 if (fCanvas->GetClickSelectedPad() == this)
1039 }
1040 }
1041
1042 fMother = nullptr;
1043 if (gROOT->GetSelectedPad() == this) gROOT->SetSelectedPad(nullptr);
1044}
1045
1046////////////////////////////////////////////////////////////////////////////////
1047/// Copy the pixmap of the pad to the canvas.
1048
1050{
1051 int px, py;
1052 XYtoAbsPixel(fX1, fY2, px, py);
1053
1054 if (fPixmapID != -1 && GetPainter())
1055 GetPainter()->CopyDrawable(fPixmapID, px, py);
1056
1057 if (this == gPad) HighLight(gPad->GetHighLightColor());
1058}
1059
1060////////////////////////////////////////////////////////////////////////////////
1061/// Copy the sub-pixmaps of the pad to the canvas.
1062
1064{
1065 TObject *obj;
1066 if (!fPrimitives) fPrimitives = new TList;
1067 TIter next(GetListOfPrimitives());
1068 while ((obj = next())) {
1069 if (obj->InheritsFrom(TPad::Class())) {
1070 ((TPad*)obj)->CopyPixmap();
1071 ((TPad*)obj)->CopyPixmaps();
1072 }
1073 }
1074}
1075
1076////////////////////////////////////////////////////////////////////////////////
1077/// Remove TExec name from the list of Execs.
1078
1079void TPad::DeleteExec(const char *name)
1080{
1081 if (!fExecs) fExecs = new TList;
1083 if (!ex) return;
1084 fExecs->Remove(ex);
1085 delete ex;
1086}
1087
1088////////////////////////////////////////////////////////////////////////////////
1089/// Compute distance from point px,py to a box.
1090///
1091/// Compute the closest distance of approach from point px,py to the
1092/// edges of this pad.
1093/// The distance is computed in pixels units.
1094
1096{
1097 Int_t pxl, pyl, pxt, pyt;
1098 Int_t px1 = gPad->XtoAbsPixel(fX1);
1099 Int_t py1 = gPad->YtoAbsPixel(fY1);
1100 Int_t px2 = gPad->XtoAbsPixel(fX2);
1101 Int_t py2 = gPad->YtoAbsPixel(fY2);
1102 if (px1 < px2) {pxl = px1; pxt = px2;}
1103 else {pxl = px2; pxt = px1;}
1104 if (py1 < py2) {pyl = py1; pyt = py2;}
1105 else {pyl = py2; pyt = py1;}
1106
1107 // Are we inside the box?
1108 // ======================
1109 if ( (px > pxl && px < pxt) && (py > pyl && py < pyt) ) {
1110 if (GetFillStyle()) return 0; //*-* if pad is filled
1111 }
1112
1113 // Are we on the edges?
1114 // ====================
1115 Int_t dxl = TMath::Abs(px - pxl);
1116 if (py < pyl) dxl += pyl - py;
1117 if (py > pyt) dxl += py - pyt;
1118 Int_t dxt = TMath::Abs(px - pxt);
1119 if (py < pyl) dxt += pyl - py;
1120 if (py > pyt) dxt += py - pyt;
1121 Int_t dyl = TMath::Abs(py - pyl);
1122 if (px < pxl) dyl += pxl - px;
1123 if (px > pxt) dyl += px - pxt;
1124 Int_t dyt = TMath::Abs(py - pyt);
1125 if (px < pxl) dyt += pxl - px;
1126 if (px > pxt) dyt += px - pxt;
1127
1128 Int_t distance = dxl;
1129 if (dxt < distance) distance = dxt;
1130 if (dyl < distance) distance = dyl;
1131 if (dyt < distance) distance = dyt;
1132
1133 return distance - Int_t(0.5*fLineWidth);
1134}
1135
1136////////////////////////////////////////////////////////////////////////////////
1137/// Automatic pad generation by division.
1138///
1139/// - The current canvas is divided in nx by ny equal divisions (pads).
1140/// - xmargin is the space along x between pads in percent of canvas.
1141/// - ymargin is the space along y between pads in percent of canvas.
1142/// - color is the color of the new pads. If 0, color is the canvas color.
1143///
1144/// Pads are automatically named `canvasname_n` where `n` is the division number
1145/// starting from top left pad.
1146///
1147/// Example if canvasname=c1 , nx=2, ny=3:
1148///
1149/// \image html gpad_pad3.png
1150///
1151/// Once a pad is divided into sub-pads, one can set the current pad
1152/// to a subpad with a given division number as illustrated above
1153/// with TPad::cd(subpad_number).
1154///
1155/// For example, to set the current pad to c1_4, one can do:
1156/// ~~~ {.cpp}
1157/// c1->cd(4)
1158/// ~~~
1159/// __Note1:__ c1.cd() is equivalent to c1.cd(0) and sets the current pad
1160/// to c1 itself.
1161///
1162/// __Note2:__ after a statement like c1.cd(6), the global variable gPad
1163/// points to the current pad. One can use gPad to set attributes
1164/// of the current pad.
1165///
1166/// __Note3:__ in case xmargin <=0 and ymargin <= 0, there is no space
1167/// between pads. The current pad margins are recomputed to
1168/// optimize the layout.
1169
1170void TPad::Divide(Int_t nx, Int_t ny, Float_t xmargin, Float_t ymargin, Int_t color)
1171{
1172 if (!IsEditable()) return;
1173
1174
1175 if (gThreadXAR) {
1176 void *arr[7];
1177 arr[1] = this; arr[2] = (void*)&nx;arr[3] = (void*)& ny;
1178 arr[4] = (void*)&xmargin; arr[5] = (void *)& ymargin; arr[6] = (void *)&color;
1179 if ((*gThreadXAR)("PDCD", 7, arr, 0)) return;
1180 }
1181
1182 TPad *padsav = (TPad*)gPad;
1183 cd();
1184 if (nx <= 0) nx = 1;
1185 if (ny <= 0) ny = 1;
1186 Int_t ix,iy;
1187 Double_t x1,y1,x2,y2;
1188 Double_t dx,dy;
1189 TPad *pad;
1190 Int_t nchname = strlen(GetName())+6;
1191 Int_t nchtitle = strlen(GetTitle())+6;
1192 char *name = new char [nchname];
1193 char *title = new char [nchtitle];
1194 Int_t n = 0;
1195 if (color == 0) color = GetFillColor();
1196 if (xmargin > 0 && ymargin > 0) {
1197 //general case
1198 dy = 1/Double_t(ny);
1199 dx = 1/Double_t(nx);
1200 for (iy=0;iy<ny;iy++) {
1201 y2 = 1 - iy*dy - ymargin;
1202 y1 = y2 - dy + 2*ymargin;
1203 if (y1 < 0) y1 = 0;
1204 if (y1 > y2) continue;
1205 for (ix=0;ix<nx;ix++) {
1206 x1 = ix*dx + xmargin;
1207 x2 = x1 +dx -2*xmargin;
1208 if (x1 > x2) continue;
1209 n++;
1210 snprintf(name,nchname,"%s_%d",GetName(),n);
1211 pad = new TPad(name,name,x1,y1,x2,y2,color);
1212 pad->SetNumber(n);
1213 pad->Draw();
1214 }
1215 }
1216 } else {
1217 // special case when xmargin <= 0 && ymargin <= 0
1218 Double_t xl = GetLeftMargin();
1219 Double_t xr = GetRightMargin();
1221 Double_t yt = GetTopMargin();
1222 xl /= (1-xl+xr)*nx;
1223 xr /= (1-xl+xr)*nx;
1224 yb /= (1-yb+yt)*ny;
1225 yt /= (1-yb+yt)*ny;
1226 SetLeftMargin(xl);
1227 SetRightMargin(xr);
1228 SetBottomMargin(yb);
1229 SetTopMargin(yt);
1230 dx = (1-xl-xr)/nx;
1231 dy = (1-yb-yt)/ny;
1232 Int_t number = 0;
1233 for (Int_t i=0;i<nx;i++) {
1234 x1 = i*dx+xl;
1235 x2 = x1 + dx;
1236 if (i == 0) x1 = 0;
1237 if (i == nx-1) x2 = 1-xr;
1238 for (Int_t j=0;j<ny;j++) {
1239 number = j*nx + i +1;
1240 y2 = 1 -j*dy -yt;
1241 y1 = y2 - dy;
1242 if (j == 0) y2 = 1-yt;
1243 if (j == ny-1) y1 = 0;
1244 snprintf(name,nchname,"%s_%d",GetName(),number);
1245 snprintf(title,nchtitle,"%s_%d",GetTitle(),number);
1246 pad = new TPad(name,title,x1,y1,x2,y2);
1247 pad->SetNumber(number);
1248 pad->SetBorderMode(0);
1249 if (i == 0) pad->SetLeftMargin(xl*nx);
1250 else pad->SetLeftMargin(0);
1251 pad->SetRightMargin(0);
1252 pad->SetTopMargin(0);
1253 if (j == ny-1) pad->SetBottomMargin(yb*ny);
1254 else pad->SetBottomMargin(0);
1255 pad->Draw();
1256 }
1257 }
1258 }
1259 delete [] name;
1260 delete [] title;
1261 Modified();
1262 if (padsav) padsav->cd();
1263}
1264
1265////////////////////////////////////////////////////////////////////////////////
1266/// "n" is the total number of sub-pads. The number of sub-pads along the X
1267/// and Y axis are computed according to the square root of n.
1268
1269void TPad::DivideSquare(Int_t n, Float_t xmargin, Float_t ymargin, Int_t color)
1270{
1271 Int_t w = 1, h = 1;
1272 if (!fCanvas) {
1273 Error("DivideSquare", "No canvas associated with this pad.");
1274 return;
1275 }
1279 if (w*h < n) w++;
1280 } else {
1283 if (w*h < n) h++;
1284 }
1285
1286 Divide( w, h, xmargin, ymargin, color);
1287}
1288
1289////////////////////////////////////////////////////////////////////////////////
1290/// Draw Pad in Current pad (re-parent pad if necessary).
1291
1293{
1294 // if no canvas opened yet create a default canvas
1295 if (!gPad) {
1296 gROOT->MakeDefCanvas();
1297 }
1298
1299 // pad cannot be in itself and it can only be in one other pad at a time
1300 if (!fPrimitives) fPrimitives = new TList;
1301 if (gPad != this) {
1304 TPad *oldMother = fMother;
1305 fCanvas = gPad->GetCanvas();
1306 //
1307 fMother = (TPad*)gPad;
1308 if (oldMother != fMother || fPixmapID == -1) ResizePad();
1309 }
1310
1311 Paint();
1312
1313 if (gPad->IsRetained() && gPad != this && fMother)
1315}
1316
1317////////////////////////////////////////////////////////////////////////////////
1318/// Draw class inheritance tree of the class to which obj belongs.
1319///
1320/// If a class B inherits from a class A, description of B is drawn
1321/// on the right side of description of A.
1322///
1323/// Member functions overridden by B are shown in class A with a blue line
1324/// crossing-out the corresponding member function.
1325
1327{
1328 if (!classobj) return;
1329 char dname[256];
1330 const Int_t kMAXLEVELS = 10;
1331 TClass *clevel[kMAXLEVELS], *cl, *cll;
1332 TBaseClass *base, *cinherit;
1333 TText *ptext = 0;
1334 TString opt=option;
1335 Double_t x,y,dy,y1,v1,v2,dv;
1336 Int_t nd,nf,nc,nkd,nkf,i,j;
1337 TPaveText *pt;
1338 Int_t maxlev = 4;
1339 if (opt.Contains("2")) maxlev = 2;
1340 if (opt.Contains("3")) maxlev = 3;
1341 if (opt.Contains("5")) maxlev = 5;
1342 if (opt.Contains("6")) maxlev = 6;
1343 if (opt.Contains("7")) maxlev = 7;
1344
1345 // Clear and Set Pad range
1346 Double_t xpad = 20.5;
1347 Double_t ypad = 27.5;
1348 Clear();
1349 Range(0,0,xpad,ypad);
1350
1351 // Find number of levels
1352 Int_t nlevel = 0;
1353 TClass *obj = (TClass*)classobj;
1354 clevel[nlevel] = obj;
1355 TList *lbase = obj->GetListOfBases();
1356 while(lbase) {
1357 base = (TBaseClass*)lbase->First();
1358 if (!base) break;
1359 if ( base->GetClassPointer() == 0) break;
1360 nlevel++;
1361 clevel[nlevel] = base->GetClassPointer();
1362 lbase = clevel[nlevel]->GetListOfBases();
1363 if (nlevel >= maxlev-1) break;
1364 }
1365 Int_t maxelem = 0;
1366 Int_t ncdraw = 0;
1367 Int_t ilevel, nelem;
1368 for (ilevel=nlevel;ilevel>=0;ilevel--) {
1369 cl = clevel[ilevel];
1370 nelem = cl->GetNdata() + cl->GetNmethods();
1371 if (nelem > maxelem) maxelem = nelem;
1372 nc = (nelem/50) + 1;
1373 ncdraw += nc;
1374 }
1375
1376 Double_t tsizcm = 0.40;
1377 Double_t x1 = 0.25;
1378 Double_t x2 = 0;
1379 Double_t dx = 3.5;
1380 if (ncdraw > 4) {
1381 dx = dx - 0.42*Double_t(ncdraw-5);
1382 if (dx < 1.3) dx = 1.3;
1383 tsizcm = tsizcm - 0.03*Double_t(ncdraw-5);
1384 if (tsizcm < 0.27) tsizcm = 0.27;
1385 }
1386 Double_t tsiz = 1.2*tsizcm/ypad;
1387
1388 // Now loop on levels
1389 for (ilevel=nlevel;ilevel>=0;ilevel--) {
1390 cl = clevel[ilevel];
1391 nelem = cl->GetNdata() + cl->GetNmethods();
1392 if (nelem > maxelem) maxelem = nelem;
1393 nc = (nelem/50) + 1;
1394 dy = 0.45;
1395 if (ilevel < nlevel) x1 = x2 + 0.5;
1396 x2 = x1 + nc*dx;
1397 v2 = ypad - 0.5;
1398 lbase = cl->GetListOfBases();
1399 cinherit = 0;
1400 if (lbase) cinherit = (TBaseClass*)lbase->First();
1401
1402 do {
1403 nd = cl->GetNdata();
1404 nf = cl->GetNmethods() - 2; //do not show default constructor and destructor
1405 if (cl->GetListOfMethods()->FindObject("Dictionary")) {
1406 nf -= 6; // do not count the Dictionary/ClassDef functions
1407 }
1408 nkf= nf/nc +1;
1409 nkd= nd/nc +1;
1410 if (nd == 0) nkd=0;
1411 if (nf == 0) nkf=0;
1412 y1 = v2 - 0.7;
1413 v1 = y1 - Double_t(nkf+nkd+nc-1)*dy;
1414 dv = v2 - v1;
1415
1416 // Create a new PaveText
1417 pt = new TPaveText(x1,v1,x2,v2);
1419 pt->SetFillColor(19);
1420 pt->Draw();
1421 pt->SetTextColor(4);
1422 pt->SetTextFont(61);
1423 pt->SetTextAlign(12);
1424 pt->SetTextSize(tsiz);
1425 TBox *box = pt->AddBox(0,(y1+0.01-v1)/dv,0,(v2-0.01-v1)/dv);
1426 if (box) box->SetFillColor(17);
1427 pt->AddLine(0,(y1-v1)/dv,0,(y1-v1)/dv);
1428 TText *title = pt->AddText(0.5,(0.5*(y1+v2)-v1)/dv,(char*)cl->GetName());
1429 title->SetTextAlign(22);
1430 title->SetTextSize(0.6*(v2-y1)/ypad);
1431
1432 // Draw data Members
1433 i = 0;
1434 x = 0.03;
1435 y = y1 + 0.5*dy;
1436 TDataMember *d;
1437 TIter nextd(cl->GetListOfDataMembers());
1438 while ((d = (TDataMember *) nextd())) {
1439 if (i >= nkd) { i = 1; y = y1 - 0.5*dy; x += 1/Double_t(nc); }
1440 else { i++; y -= dy; }
1441
1442 // Take in account the room the array index will occupy
1443
1444 Int_t dim = d->GetArrayDim();
1445 Int_t indx = 0;
1446 snprintf(dname,256,"%s",d->GetName());
1447 Int_t ldname = 0;
1448 while (indx < dim ){
1449 ldname = strlen(dname);
1450 snprintf(&dname[ldname],256-ldname,"[%d]",d->GetMaxIndex(indx));
1451 indx++;
1452 }
1453 pt->AddText(x,(y-v1)/dv,dname);
1454 }
1455
1456 // Draw a separator line
1457 Double_t ysep;
1458 if (nd) {
1459 ysep = y1 - Double_t(nkd)*dy;
1460 pt->AddLine(0,(ysep-v1)/dv,0,(ysep-v1)/dv);
1461 ysep -= 0.5*dy;
1462 } else ysep = y1;
1463
1464 // Draw Member Functions
1465 Int_t fcount = 0;
1466 i = 0;
1467 x = 0.03;
1468 y = ysep + 0.5*dy;
1469 TMethod *m;
1470 TIter nextm(cl->GetListOfMethods());
1471 while ((m = (TMethod *) nextm())) {
1472 if (
1473 !strcmp( m->GetName(), "Dictionary" ) ||
1474 !strcmp( m->GetName(), "Class_Version" ) ||
1475 !strcmp( m->GetName(), "DeclFileName" ) ||
1476 !strcmp( m->GetName(), "DeclFileLine" ) ||
1477 !strcmp( m->GetName(), "ImplFileName" ) ||
1478 !strcmp( m->GetName(), "ImplFileLine" )
1479 ) continue;
1480 fcount++;
1481 if (fcount > nf) break;
1482 if (i >= nkf) { i = 1; y = ysep - 0.5*dy; x += 1/Double_t(nc); }
1483 else { i++; y -= dy; }
1484
1485 ptext = pt->AddText(x,(y-v1)/dv,m->GetName());
1486 // Check if method is overloaded in a derived class
1487 // If yes, Change the color of the text to blue
1488 for (j=ilevel-1;j>=0;j--) {
1489 if (cl == clevel[ilevel]) {
1490 if (clevel[j]->GetMethodAny((char*)m->GetName())) {
1491 ptext->SetTextColor(15);
1492 break;
1493 }
1494 }
1495 }
1496 }
1497
1498 // Draw second inheritance classes for this class
1499 cll = 0;
1500 if (cinherit) {
1501 cinherit = (TBaseClass*)lbase->After(cinherit);
1502 if (cinherit) {
1503 cl = cinherit->GetClassPointer();
1504 cll = cl;
1505 v2 = v1 -0.4;
1506 dy = 0.35;
1507 }
1508 }
1509 } while (cll);
1510 }
1511 Update();
1512}
1513
1514////////////////////////////////////////////////////////////////////////////////
1515/// Function called to draw a crosshair in the canvas
1516///
1517/// Example:
1518/// ~~~ {.cpp}
1519/// Root > TFile f("hsimple.root");
1520/// Root > hpxpy.Draw();
1521/// Root > c1.SetCrosshair();
1522/// ~~~
1523/// When moving the mouse in the canvas, a crosshair is drawn
1524///
1525/// - if the canvas fCrosshair = 1 , the crosshair spans the full canvas
1526/// - if the canvas fCrosshair > 1 , the crosshair spans only the pad
1527
1529{
1530 if (gPad->GetEvent() == kMouseEnter) return;
1531
1532 TPad *cpad = (TPad*)gPad;
1533 TCanvas *canvas = cpad->GetCanvas();
1534 canvas->FeedbackMode(kTRUE);
1535
1536 //erase old position and draw a line at current position
1537 Int_t pxmin,pxmax,pymin,pymax,px,py;
1538#ifndef R__HAS_COCOA
1539 Int_t pxold = fCrosshairPos%10000;
1540 Int_t pyold = fCrosshairPos/10000;
1541#endif // R__HAS_COCOA
1542 px = cpad->GetEventX();
1543 py = cpad->GetEventY()+1;
1544 if (canvas->GetCrosshair() > 1) { //crosshair only in the current pad
1545 pxmin = cpad->XtoAbsPixel(fX1);
1546 pxmax = cpad->XtoAbsPixel(fX2);
1547 pymin = cpad->YtoAbsPixel(fY1);
1548 pymax = cpad->YtoAbsPixel(fY2);
1549 } else { //default; crosshair spans the full canvas
1550 pxmin = 0;
1551 pxmax = canvas->GetWw();
1552 pymin = 0;
1553 pymax = cpad->GetWh();
1554 }
1555#ifndef R__HAS_COCOA
1556 // Not needed, no XOR with Cocoa.
1557 if(pxold) gVirtualX->DrawLine(pxold,pymin,pxold,pymax);
1558 if(pyold) gVirtualX->DrawLine(pxmin,pyold,pxmax,pyold);
1559#endif // R__HAS_COCOA
1560 if (cpad->GetEvent() == kButton1Down ||
1561 cpad->GetEvent() == kButton1Up ||
1562 cpad->GetEvent() == kMouseLeave) {
1563 fCrosshairPos = 0;
1564 return;
1565 }
1566 gVirtualX->DrawLine(px,pymin,px,pymax);
1567 gVirtualX->DrawLine(pxmin,py,pxmax,py);
1568 fCrosshairPos = px + 10000*py;
1569}
1570
1571////////////////////////////////////////////////////////////////////////////////
1572/// Draw an empty pad frame with X and Y axis.
1573///
1574/// \return The pointer to the histogram used to draw the frame.
1575///
1576/// \param[in] xmin X axis lower limit
1577/// \param[in] xmax X axis upper limit
1578/// \param[in] ymin Y axis lower limit
1579/// \param[in] ymax Y axis upper limit
1580/// \param[in] title Pad title.If title is of the form "stringt;stringx;stringy"
1581/// the pad title is set to stringt, the x axis title to
1582/// stringx, the y axis title to stringy.
1583///
1584/// #### Example:
1585///
1586/// Begin_Macro(source)
1587/// {
1588/// auto c = new TCanvas("c","c",200,10,500,300);
1589///
1590/// const Int_t n = 50;
1591/// auto g = new TGraph();
1592/// for (Int_t i=0;i<n;i++) g->SetPoint(i,i*0.1,100*sin(i*0.1+0.2));
1593///
1594/// auto frame = c->DrawFrame(0, -110, 2, 110);
1595/// frame->GetXaxis()->SetTitle("X axis");
1596///
1597/// g->Draw("L*");
1598/// }
1599/// End_Macro
1600
1602{
1603 if (!IsEditable()) return 0;
1604 TPad *padsav = (TPad*)gPad;
1605 if (this != padsav) {
1606 Warning("DrawFrame","Must be called for the current pad only");
1607 return padsav->DrawFrame(xmin,ymin,xmax,ymax,title);
1608 }
1609
1610 cd();
1611
1612 TH1F *hframe = (TH1F*)FindObject("hframe");
1613 if (hframe) delete hframe;
1614 Int_t nbins = 1000;
1615 //if log scale in X, use variable bin size linear with log(x)
1616 //this gives a better precision when zooming on the axis
1617 if (fLogx && xmin > 0 && xmax > xmin) {
1618 Double_t xminl = TMath::Log(xmin);
1619 Double_t xmaxl = TMath::Log(xmax);
1620 Double_t dx = (xmaxl-xminl)/nbins;
1621 Double_t *xbins = new Double_t[nbins+1];
1622 xbins[0] = xmin;
1623 for (Int_t i=1;i<=nbins;i++) {
1624 xbins[i] = TMath::Exp(xminl+i*dx);
1625 }
1626 hframe = new TH1F("hframe",title,nbins,xbins);
1627 delete [] xbins;
1628 } else {
1629 hframe = new TH1F("hframe",title,nbins,xmin,xmax);
1630 }
1631 hframe->SetBit(TH1::kNoStats);
1632 hframe->SetBit(kCanDelete);
1633 hframe->SetMinimum(ymin);
1634 hframe->SetMaximum(ymax);
1635 hframe->GetYaxis()->SetLimits(ymin,ymax);
1636 hframe->SetDirectory(0);
1637 hframe->Draw(" ");
1638 Update();
1639 if (padsav) padsav->cd();
1640 return hframe;
1641}
1642
1643////////////////////////////////////////////////////////////////////////////////
1644/// Static function to Display Color Table in a pad.
1645
1647{
1648 Int_t i, j;
1649 Int_t color;
1650 Double_t xlow, ylow, xup, yup, hs, ws;
1651 Double_t x1, y1, x2, y2;
1652 x1 = y1 = 0;
1653 x2 = y2 = 20;
1654
1655 gPad->SetFillColor(0);
1656 gPad->Clear();
1657 gPad->Range(x1,y1,x2,y2);
1658
1659 TText *text = new TText(0,0,"");
1660 text->SetTextFont(61);
1661 text->SetTextSize(0.07);
1662 text->SetTextAlign(22);
1663
1664 TBox *box = new TBox();
1665
1666 // Draw color table boxes.
1667 hs = (y2-y1)/Double_t(5);
1668 ws = (x2-x1)/Double_t(10);
1669 for (i=0;i<10;i++) {
1670 xlow = x1 + ws*(Double_t(i)+0.1);
1671 xup = x1 + ws*(Double_t(i)+0.9);
1672 for (j=0;j<5;j++) {
1673 ylow = y1 + hs*(Double_t(j)+0.1);
1674 yup = y1 + hs*(Double_t(j)+0.9);
1675 color = 10*j + i;
1676 box->SetFillStyle(1001);
1677 box->SetFillColor(color);
1678 box->DrawBox(xlow, ylow, xup, yup);
1679 box->SetFillStyle(0);
1680 box->SetLineColor(1);
1681 box->DrawBox(xlow, ylow, xup, yup);
1682 if (color == 1) text->SetTextColor(0);
1683 else text->SetTextColor(1);
1684 text->DrawText(0.5*(xlow+xup), 0.5*(ylow+yup), Form("%d",color));
1685 }
1686 }
1687}
1688
1689////////////////////////////////////////////////////////////////////////////////
1690/// Execute action corresponding to one event.
1691///
1692/// This member function is called when a TPad object is clicked.
1693///
1694/// If the mouse is clicked in one of the 4 corners of the pad (pA,pB,pC,pD)
1695/// the pad is resized with the rubber rectangle.
1696///
1697/// If the mouse is clicked inside the pad, the pad is moved.
1698///
1699/// If the mouse is clicked on the 4 edges (pL,pR,pTop,pBot), the pad is scaled
1700/// parallel to this edge.
1701///
1702/// \image html gpad_pad4.png
1703///
1704/// Note that this function duplicates on purpose the functionality
1705/// already implemented in TBox::ExecuteEvent.
1706/// If somebody modifies this function, may be similar changes should also
1707/// be applied to TBox::ExecuteEvent.
1708
1710{
1711 const Int_t kMaxDiff = 5;
1712 const Int_t kMinSize = 20;
1713 static Int_t pxorg, pyorg;
1714 static Int_t px1, px2, py1, py2, pxl, pyl, pxt, pyt, pxold, pyold;
1715 static Int_t px1p, px2p, py1p, py2p, pxlp, pylp, pxtp, pytp;
1716 static Bool_t pA, pB, pC, pD, pTop, pL, pR, pBot, pINSIDE;
1717 Int_t wx, wy;
1718 Bool_t opaque = OpaqueMoving();
1719 Bool_t ropaque = OpaqueResizing();
1720 Bool_t fixedr = HasFixedAspectRatio();
1721
1722 if (!IsEditable() && event != kMouseEnter) return;
1723 TVirtualPad *parent = GetMother();
1724 if (!parent->IsEditable()) return;
1725
1727
1728 if (fXlowNDC < 0 && event != kButton1Down) return;
1729 if (fYlowNDC < 0 && event != kButton1Down) return;
1730
1731 // keep old mouse position
1732 if (event == kButton1Down) {
1733 pxorg = px;
1734 pyorg = py;
1735 }
1736
1737 Int_t newcode = gROOT->GetEditorMode();
1738 if (newcode)
1739 pA = pB = pC = pD = pTop = pL = pR = pBot = pINSIDE = kFALSE;
1740 switch (newcode) {
1741 case kPad:
1743 break;
1744 case kMarker:
1745 case kText:
1746 TCreatePrimitives::Text(event,px,py,newcode);
1747 break;
1748 case kLine:
1750 break;
1751 case kArrow:
1753 break;
1754 case kCurlyLine:
1756 break;
1757 case kCurlyArc:
1759 break;
1760 case kPolyLine:
1762 break;
1763 case kCutG:
1765 break;
1766 case kArc:
1768 break;
1769 case kEllipse:
1771 break;
1772 case kButton:
1773 case kPave:
1774 case kPaveLabel:
1775 case kPaveText:
1776 case kPavesText:
1777 case kDiamond:
1778 TCreatePrimitives::Pave(event,px,py,newcode);
1779 return;
1780 default:
1781 break;
1782 }
1783 if (newcode) return;
1784
1785 switch (event) {
1786
1787 case kMouseEnter:
1788 if (fTip)
1790 break;
1791
1792 case kArrowKeyPress:
1793 case kButton1Down:
1794
1797
1798 GetPainter()->SetLineColor(-1);
1799 TAttLine::Modify(); //Change line attributes only if necessary
1800 if (GetFillColor())
1802 else
1805
1806 // No break !!!
1807
1808 case kMouseMotion:
1809
1810 px1 = XtoAbsPixel(fX1);
1811 py1 = YtoAbsPixel(fY1);
1812 px2 = XtoAbsPixel(fX2);
1813 py2 = YtoAbsPixel(fY2);
1814
1815 if (px1 < px2) {
1816 pxl = px1;
1817 pxt = px2;
1818 } else {
1819 pxl = px2;
1820 pxt = px1;
1821 }
1822 if (py1 < py2) {
1823 pyl = py1;
1824 pyt = py2;
1825 } else {
1826 pyl = py2;
1827 pyt = py1;
1828 }
1829
1830 px1p = parent->XtoAbsPixel(parent->GetX1()) + parent->GetBorderSize();
1831 py1p = parent->YtoAbsPixel(parent->GetY1()) - parent->GetBorderSize();
1832 px2p = parent->XtoAbsPixel(parent->GetX2()) - parent->GetBorderSize();
1833 py2p = parent->YtoAbsPixel(parent->GetY2()) + parent->GetBorderSize();
1834
1835 if (px1p < px2p) {
1836 pxlp = px1p;
1837 pxtp = px2p;
1838 } else {
1839 pxlp = px2p;
1840 pxtp = px1p;
1841 }
1842 if (py1p < py2p) {
1843 pylp = py1p;
1844 pytp = py2p;
1845 } else {
1846 pylp = py2p;
1847 pytp = py1p;
1848 }
1849
1850 pA = pB = pC = pD = pTop = pL = pR = pBot = pINSIDE = kFALSE;
1851
1852 // case pA
1853 if (TMath::Abs(px - pxl) <= kMaxDiff && TMath::Abs(py - pyl) <= kMaxDiff) {
1854 pxold = pxl; pyold = pyl; pA = kTRUE;
1856 }
1857 // case pB
1858 if (TMath::Abs(px - pxt) <= kMaxDiff && TMath::Abs(py - pyl) <= kMaxDiff) {
1859 pxold = pxt; pyold = pyl; pB = kTRUE;
1861 }
1862 // case pC
1863 if (TMath::Abs(px - pxt) <= kMaxDiff && TMath::Abs(py - pyt) <= kMaxDiff) {
1864 pxold = pxt; pyold = pyt; pC = kTRUE;
1866 }
1867 // case pD
1868 if (TMath::Abs(px - pxl) <= kMaxDiff && TMath::Abs(py - pyt) <= kMaxDiff) {
1869 pxold = pxl; pyold = pyt; pD = kTRUE;
1871 }
1872
1873 if ((px > pxl+kMaxDiff && px < pxt-kMaxDiff) &&
1874 TMath::Abs(py - pyl) < kMaxDiff) { // top edge
1875 pxold = pxl; pyold = pyl; pTop = kTRUE;
1877 }
1878
1879 if ((px > pxl+kMaxDiff && px < pxt-kMaxDiff) &&
1880 TMath::Abs(py - pyt) < kMaxDiff) { // bottom edge
1881 pxold = pxt; pyold = pyt; pBot = kTRUE;
1883 }
1884
1885 if ((py > pyl+kMaxDiff && py < pyt-kMaxDiff) &&
1886 TMath::Abs(px - pxl) < kMaxDiff) { // left edge
1887 pxold = pxl; pyold = pyl; pL = kTRUE;
1889 }
1890
1891 if ((py > pyl+kMaxDiff && py < pyt-kMaxDiff) &&
1892 TMath::Abs(px - pxt) < kMaxDiff) { // right edge
1893 pxold = pxt; pyold = pyt; pR = kTRUE;
1895 }
1896
1897 if ((px > pxl+kMaxDiff && px < pxt-kMaxDiff) &&
1898 (py > pyl+kMaxDiff && py < pyt-kMaxDiff)) { // inside box
1899 pxold = px; pyold = py; pINSIDE = kTRUE;
1900 if (event == kButton1Down)
1902 else
1904 }
1905
1906 fResizing = kFALSE;
1907 if (pA || pB || pC || pD || pTop || pL || pR || pBot)
1908 fResizing = kTRUE;
1909
1910 if (!pA && !pB && !pC && !pD && !pTop && !pL && !pR && !pBot && !pINSIDE)
1912
1913 break;
1914
1915 case kArrowKeyRelease:
1916 case kButton1Motion:
1917
1918 if (TestBit(kCannotMove)) break;
1919 wx = wy = 0;
1920
1921 if (pA) {
1922 if (!ropaque) gVirtualX->DrawBox(pxold, pyt, pxt, pyold, TVirtualX::kHollow);
1923 if (px > pxt-kMinSize) { px = pxt-kMinSize; wx = px; }
1924 if (py > pyt-kMinSize) { py = pyt-kMinSize; wy = py; }
1925 if (px < pxlp) { px = pxlp; wx = px; }
1926 if (py < pylp) { py = pylp; wy = py; }
1927 if (fixedr) {
1928 Double_t dy = Double_t(TMath::Abs(pxt-px))/parent->UtoPixel(1.) /
1930 Int_t npy2 = pyt - TMath::Abs(parent->VtoAbsPixel(dy) -
1931 parent->VtoAbsPixel(0));
1932 if (npy2 < pylp) {
1933 px = pxold;
1934 py = pyold;
1935 } else
1936 py = npy2;
1937
1938 wx = wy = 0;
1939 }
1940 if (!ropaque) gVirtualX->DrawBox(px, pyt, pxt, py, TVirtualX::kHollow);
1941 }
1942 if (pB) {
1943 if (!ropaque) gVirtualX->DrawBox(pxl , pyt, pxold, pyold, TVirtualX::kHollow);
1944 if (px < pxl+kMinSize) { px = pxl+kMinSize; wx = px; }
1945 if (py > pyt-kMinSize) { py = pyt-kMinSize; wy = py; }
1946 if (px > pxtp) { px = pxtp; wx = px; }
1947 if (py < pylp) { py = pylp; wy = py; }
1948 if (fixedr) {
1949 Double_t dy = Double_t(TMath::Abs(pxl-px))/parent->UtoPixel(1.) /
1951 Int_t npy2 = pyt - TMath::Abs(parent->VtoAbsPixel(dy) -
1952 parent->VtoAbsPixel(0));
1953 if (npy2 < pylp) {
1954 px = pxold;
1955 py = pyold;
1956 } else
1957 py = npy2;
1958
1959 wx = wy = 0;
1960 }
1961 if (!ropaque) gVirtualX->DrawBox(pxl , pyt, px , py, TVirtualX::kHollow);
1962 }
1963 if (pC) {
1964 if (!ropaque) gVirtualX->DrawBox(pxl , pyl, pxold, pyold, TVirtualX::kHollow);
1965 if (px < pxl+kMinSize) { px = pxl+kMinSize; wx = px; }
1966 if (py < pyl+kMinSize) { py = pyl+kMinSize; wy = py; }
1967 if (px > pxtp) { px = pxtp; wx = px; }
1968 if (py > pytp) { py = pytp; wy = py; }
1969 if (fixedr) {
1970 Double_t dy = Double_t(TMath::Abs(pxl-px))/parent->UtoPixel(1.) /
1972 Int_t npy2 = pyl + TMath::Abs(parent->VtoAbsPixel(dy) -
1973 parent->VtoAbsPixel(0));
1974 if (npy2 > pytp) {
1975 px = pxold;
1976 py = pyold;
1977 } else
1978 py = npy2;
1979
1980 wx = wy = 0;
1981 }
1982 if (!ropaque) gVirtualX->DrawBox(pxl, pyl, px, py, TVirtualX::kHollow);
1983 }
1984 if (pD) {
1985 if (!ropaque) gVirtualX->DrawBox(pxold, pyold, pxt, pyl, TVirtualX::kHollow);
1986 if (px > pxt-kMinSize) { px = pxt-kMinSize; wx = px; }
1987 if (py < pyl+kMinSize) { py = pyl+kMinSize; wy = py; }
1988 if (px < pxlp) { px = pxlp; wx = px; }
1989 if (py > pytp) { py = pytp; wy = py; }
1990 if (fixedr) {
1991 Double_t dy = Double_t(TMath::Abs(pxt-px))/parent->UtoPixel(1.) /
1993 Int_t npy2 = pyl + TMath::Abs(parent->VtoAbsPixel(dy) -
1994 parent->VtoAbsPixel(0));
1995 if (npy2 > pytp) {
1996 px = pxold;
1997 py = pyold;
1998 } else
1999 py = npy2;
2000
2001 wx = wy = 0;
2002 }
2003 if (!ropaque) gVirtualX->DrawBox(px, py, pxt, pyl, TVirtualX::kHollow);
2004 }
2005 if (pTop) {
2006 if (!ropaque) gVirtualX->DrawBox(px1, py1, px2, py2, TVirtualX::kHollow);
2007 py2 += py - pyold;
2008 if (py2 > py1-kMinSize) { py2 = py1-kMinSize; wy = py2; }
2009 if (py2 < py2p) { py2 = py2p; wy = py2; }
2010 if (fixedr) {
2011 Double_t dx = Double_t(TMath::Abs(py2-py1))/parent->VtoPixel(0) *
2013 Int_t npx2 = px1 + parent->UtoPixel(dx);
2014 if (npx2 > px2p)
2015 py2 -= py - pyold;
2016 else
2017 px2 = npx2;
2018 }
2019 if (!ropaque) gVirtualX->DrawBox(px1, py1, px2, py2, TVirtualX::kHollow);
2020 }
2021 if (pBot) {
2022 if (!ropaque) gVirtualX->DrawBox(px1, py1, px2, py2, TVirtualX::kHollow);
2023 py1 += py - pyold;
2024 if (py1 < py2+kMinSize) { py1 = py2+kMinSize; wy = py1; }
2025 if (py1 > py1p) { py1 = py1p; wy = py1; }
2026 if (fixedr) {
2027 Double_t dx = Double_t(TMath::Abs(py2-py1))/parent->VtoPixel(0) *
2029 Int_t npx2 = px1 + parent->UtoPixel(dx);
2030 if (npx2 > px2p)
2031 py1 -= py - pyold;
2032 else
2033 px2 = npx2;
2034 }
2035 if (!ropaque) gVirtualX->DrawBox(px1, py1, px2, py2, TVirtualX::kHollow);
2036 }
2037 if (pL) {
2038 if (!ropaque) gVirtualX->DrawBox(px1, py1, px2, py2, TVirtualX::kHollow);
2039 px1 += px - pxold;
2040 if (px1 > px2-kMinSize) { px1 = px2-kMinSize; wx = px1; }
2041 if (px1 < px1p) { px1 = px1p; wx = px1; }
2042 if (fixedr) {
2043 Double_t dy = Double_t(TMath::Abs(px2-px1))/parent->UtoPixel(1.) /
2045 Int_t npy2 = py1 - TMath::Abs(parent->VtoAbsPixel(dy) -
2046 parent->VtoAbsPixel(0));
2047 if (npy2 < py2p)
2048 px1 -= px - pxold;
2049 else
2050 py2 = npy2;
2051 }
2052 if (!ropaque) gVirtualX->DrawBox(px1, py1, px2, py2, TVirtualX::kHollow);
2053 }
2054 if (pR) {
2055 if (!ropaque) gVirtualX->DrawBox(px1, py1, px2, py2, TVirtualX::kHollow);
2056 px2 += px - pxold;
2057 if (px2 < px1+kMinSize) { px2 = px1+kMinSize; wx = px2; }
2058 if (px2 > px2p) { px2 = px2p; wx = px2; }
2059 if (fixedr) {
2060 Double_t dy = Double_t(TMath::Abs(px2-px1))/parent->UtoPixel(1.) /
2062 Int_t npy2 = py1 - TMath::Abs(parent->VtoAbsPixel(dy) -
2063 parent->VtoAbsPixel(0));
2064 if (npy2 < py2p)
2065 px2 -= px - pxold;
2066 else
2067 py2 = npy2;
2068 }
2069 if (!ropaque) gVirtualX->DrawBox(px1, py1, px2, py2, TVirtualX::kHollow);
2070 }
2071 if (pINSIDE) {
2072 if (!opaque) gVirtualX->DrawBox(px1, py1, px2, py2, TVirtualX::kHollow); // draw the old box
2073 Int_t dx = px - pxold;
2074 Int_t dy = py - pyold;
2075 px1 += dx; py1 += dy; px2 += dx; py2 += dy;
2076 if (px1 < px1p) { dx = px1p - px1; px1 += dx; px2 += dx; wx = px+dx; }
2077 if (px2 > px2p) { dx = px2 - px2p; px1 -= dx; px2 -= dx; wx = px-dx; }
2078 if (py1 > py1p) { dy = py1 - py1p; py1 -= dy; py2 -= dy; wy = py-dy; }
2079 if (py2 < py2p) { dy = py2p - py2; py1 += dy; py2 += dy; wy = py+dy; }
2080 if (!opaque) gVirtualX->DrawBox(px1, py1, px2, py2, TVirtualX::kHollow); // draw the new box
2081 }
2082
2083 if (wx || wy) {
2084 if (wx) px = wx;
2085 if (wy) py = wy;
2086 gVirtualX->Warp(px, py);
2087 }
2088
2089 pxold = px;
2090 pyold = py;
2091
2092 Double_t x1, y1, x2, y2;
2093 x1 = x2 = y1 = y2 = 0;
2094
2095 if ((!fResizing && opaque) || (fResizing && ropaque)) {
2096 if (pA) {
2097 x1 = AbsPixeltoX(pxold);
2098 y1 = AbsPixeltoY(pyt);
2099 x2 = AbsPixeltoX(pxt);
2100 y2 = AbsPixeltoY(pyold);
2101 }
2102 if (pB) {
2103 x1 = AbsPixeltoX(pxl);
2104 y1 = AbsPixeltoY(pyt);
2105 x2 = AbsPixeltoX(pxold);
2106 y2 = AbsPixeltoY(pyold);
2107 }
2108 if (pC) {
2109 x1 = AbsPixeltoX(pxl);
2110 y1 = AbsPixeltoY(pyold);
2111 x2 = AbsPixeltoX(pxold);
2112 y2 = AbsPixeltoY(pyl);
2113 }
2114 if (pD) {
2115 x1 = AbsPixeltoX(pxold);
2116 y1 = AbsPixeltoY(pyold);
2117 x2 = AbsPixeltoX(pxt);
2118 y2 = AbsPixeltoY(pyl);
2119 }
2120 if (pTop || pBot || pL || pR || pINSIDE) {
2121 x1 = AbsPixeltoX(px1);
2122 y1 = AbsPixeltoY(py1);
2123 x2 = AbsPixeltoX(px2);
2124 y2 = AbsPixeltoY(py2);
2125 }
2126
2127 if (px != pxorg || py != pyorg) {
2128
2129 // Get parent corners pixels coordinates
2130 Int_t parentpx1 = fMother->XtoAbsPixel(parent->GetX1());
2131 Int_t parentpx2 = fMother->XtoAbsPixel(parent->GetX2());
2132 Int_t parentpy1 = fMother->YtoAbsPixel(parent->GetY1());
2133 Int_t parentpy2 = fMother->YtoAbsPixel(parent->GetY2());
2134
2135 // Get pad new corners pixels coordinates
2136 Int_t apx1 = XtoAbsPixel(x1); if (apx1 < parentpx1) {apx1 = parentpx1; }
2137 Int_t apx2 = XtoAbsPixel(x2); if (apx2 > parentpx2) {apx2 = parentpx2; }
2138 Int_t apy1 = YtoAbsPixel(y1); if (apy1 > parentpy1) {apy1 = parentpy1; }
2139 Int_t apy2 = YtoAbsPixel(y2); if (apy2 < parentpy2) {apy2 = parentpy2; }
2140
2141 // Compute new pad positions in the NDC space of parent
2142 fXlowNDC = Double_t(apx1 - parentpx1)/Double_t(parentpx2 - parentpx1);
2143 fYlowNDC = Double_t(apy1 - parentpy1)/Double_t(parentpy2 - parentpy1);
2144 fWNDC = Double_t(apx2 - apx1)/Double_t(parentpx2 - parentpx1);
2145 fHNDC = Double_t(apy2 - apy1)/Double_t(parentpy2 - parentpy1);
2146 }
2147
2148 // Reset pad parameters and recompute conversion coefficients
2149 ResizePad();
2150
2151 if (pINSIDE) gPad->ShowGuidelines(this, event);
2152 if (pTop) gPad->ShowGuidelines(this, event, 't', true);
2153 if (pBot) gPad->ShowGuidelines(this, event, 'b', true);
2154 if (pL) gPad->ShowGuidelines(this, event, 'l', true);
2155 if (pR) gPad->ShowGuidelines(this, event, 'r', true);
2156 if (pA) gPad->ShowGuidelines(this, event, '1', true);
2157 if (pB) gPad->ShowGuidelines(this, event, '2', true);
2158 if (pC) gPad->ShowGuidelines(this, event, '3', true);
2159 if (pD) gPad->ShowGuidelines(this, event, '4', true);
2160
2161 Modified(kTRUE);
2162 }
2163
2164 break;
2165
2166 case kButton1Up:
2167
2168 if (gROOT->IsEscaped()) {
2169 gROOT->SetEscape(kFALSE);
2170 break;
2171 }
2172
2173 if (opaque||ropaque) {
2174 ShowGuidelines(this, event);
2175 } else {
2176 x1 = x2 = y1 = y2 = 0;
2177
2178 if (pA) {
2179 x1 = AbsPixeltoX(pxold);
2180 y1 = AbsPixeltoY(pyt);
2181 x2 = AbsPixeltoX(pxt);
2182 y2 = AbsPixeltoY(pyold);
2183 }
2184 if (pB) {
2185 x1 = AbsPixeltoX(pxl);
2186 y1 = AbsPixeltoY(pyt);
2187 x2 = AbsPixeltoX(pxold);
2188 y2 = AbsPixeltoY(pyold);
2189 }
2190 if (pC) {
2191 x1 = AbsPixeltoX(pxl);
2192 y1 = AbsPixeltoY(pyold);
2193 x2 = AbsPixeltoX(pxold);
2194 y2 = AbsPixeltoY(pyl);
2195 }
2196 if (pD) {
2197 x1 = AbsPixeltoX(pxold);
2198 y1 = AbsPixeltoY(pyold);
2199 x2 = AbsPixeltoX(pxt);
2200 y2 = AbsPixeltoY(pyl);
2201 }
2202 if (pTop || pBot || pL || pR || pINSIDE) {
2203 x1 = AbsPixeltoX(px1);
2204 y1 = AbsPixeltoY(py1);
2205 x2 = AbsPixeltoX(px2);
2206 y2 = AbsPixeltoY(py2);
2207 }
2208
2209 if (pA || pB || pC || pD || pTop || pL || pR || pBot)
2210 Modified(kTRUE);
2211
2212 gVirtualX->SetLineColor(-1);
2213 gVirtualX->SetLineWidth(-1);
2214
2215 if (px != pxorg || py != pyorg) {
2216
2217 // Get parent corners pixels coordinates
2218 Int_t parentpx1 = fMother->XtoAbsPixel(parent->GetX1());
2219 Int_t parentpx2 = fMother->XtoAbsPixel(parent->GetX2());
2220 Int_t parentpy1 = fMother->YtoAbsPixel(parent->GetY1());
2221 Int_t parentpy2 = fMother->YtoAbsPixel(parent->GetY2());
2222
2223 // Get pad new corners pixels coordinates
2224 Int_t apx1 = XtoAbsPixel(x1); if (apx1 < parentpx1) {apx1 = parentpx1; }
2225 Int_t apx2 = XtoAbsPixel(x2); if (apx2 > parentpx2) {apx2 = parentpx2; }
2226 Int_t apy1 = YtoAbsPixel(y1); if (apy1 > parentpy1) {apy1 = parentpy1; }
2227 Int_t apy2 = YtoAbsPixel(y2); if (apy2 < parentpy2) {apy2 = parentpy2; }
2228
2229 // Compute new pad positions in the NDC space of parent
2230 fXlowNDC = Double_t(apx1 - parentpx1)/Double_t(parentpx2 - parentpx1);
2231 fYlowNDC = Double_t(apy1 - parentpy1)/Double_t(parentpy2 - parentpy1);
2232 fWNDC = Double_t(apx2 - apx1)/Double_t(parentpx2 - parentpx1);
2233 fHNDC = Double_t(apy2 - apy1)/Double_t(parentpy2 - parentpy1);
2234 }
2235
2236 // Reset pad parameters and recompute conversion coefficients
2237 ResizePad();
2238
2239
2240 // emit signal
2241 RangeChanged();
2242 }
2243
2244 break;
2245
2246 case kButton1Locate:
2247
2248 ExecuteEvent(kButton1Down, px, py);
2249
2250 while (1) {
2251 px = py = 0;
2252 event = gVirtualX->RequestLocator(1, 1, px, py);
2253
2255
2256 if (event != -1) { // button is released
2257 ExecuteEvent(kButton1Up, px, py);
2258 return;
2259 }
2260 }
2261
2262 case kButton2Down:
2263
2264 Pop();
2265 break;
2266
2267 }
2268}
2269
2270////////////////////////////////////////////////////////////////////////////////
2271/// Execute action corresponding to one event for a TAxis object
2272/// (called by TAxis::ExecuteEvent.)
2273/// This member function is called when an axis is clicked with the locator
2274///
2275/// The axis range is set between the position where the mouse is pressed
2276/// and the position where it is released.
2277///
2278/// If the mouse position is outside the current axis range when it is released
2279/// the axis is unzoomed with the corresponding proportions.
2280///
2281/// Note that the mouse does not need to be in the pad or even canvas
2282/// when it is released.
2283
2285{
2286 if (!IsEditable()) return;
2287 if (!axis) return;
2289
2290 TView *view = GetView();
2291 static Int_t axisNumber;
2292 static Double_t ratio1, ratio2;
2293 static Int_t px1old, py1old, px2old, py2old;
2294 Int_t bin1, bin2, first, last;
2295 Double_t temp, xmin,xmax;
2296 Bool_t opaque = gPad->OpaqueMoving();
2297 static std::unique_ptr<TBox> zoombox;
2298 Double_t zbx1=0,zbx2=0,zby1=0,zby2=0;
2299
2300 // The CONT4 option, used to paint TH2, is a special case; it uses a 3D
2301 // drawing technique to paint a 2D plot.
2302 TString opt = axis->GetParent()->GetDrawOption();
2303 opt.ToLower();
2304 Bool_t kCont4 = kFALSE;
2305 if (strstr(opt,"cont4")) {
2306 view = 0;
2307 kCont4 = kTRUE;
2308 }
2309
2310 switch (event) {
2311
2312 case kButton1Down:
2313 axisNumber = 1;
2314 if (!strcmp(axis->GetName(),"xaxis")) {
2315 axisNumber = 1;
2316 if (!IsVertical()) axisNumber = 2;
2317 }
2318 if (!strcmp(axis->GetName(),"yaxis")) {
2319 axisNumber = 2;
2320 if (!IsVertical()) axisNumber = 1;
2321 }
2322 if (!strcmp(axis->GetName(),"zaxis")) {
2323 axisNumber = 3;
2324 }
2325 if (view) {
2326 view->GetDistancetoAxis(axisNumber, px, py, ratio1);
2327 } else {
2328 if (axisNumber == 1) {
2329 ratio1 = (AbsPixeltoX(px) - GetUxmin())/(GetUxmax() - GetUxmin());
2330 px1old = XtoAbsPixel(GetUxmin()+ratio1*(GetUxmax() - GetUxmin()));
2331 py1old = YtoAbsPixel(GetUymin());
2332 px2old = px1old;
2333 py2old = YtoAbsPixel(GetUymax());
2334 } else if (axisNumber == 2) {
2335 ratio1 = (AbsPixeltoY(py) - GetUymin())/(GetUymax() - GetUymin());
2336 py1old = YtoAbsPixel(GetUymin()+ratio1*(GetUymax() - GetUymin()));
2337 px1old = XtoAbsPixel(GetUxmin());
2338 px2old = XtoAbsPixel(GetUxmax());
2339 py2old = py1old;
2340 } else {
2341 ratio1 = (AbsPixeltoY(py) - GetUymin())/(GetUymax() - GetUymin());
2342 py1old = YtoAbsPixel(GetUymin()+ratio1*(GetUymax() - GetUymin()));
2343 px1old = XtoAbsPixel(GetUxmax());
2344 px2old = XtoAbsPixel(GetX2());
2345 py2old = py1old;
2346 }
2347 if (!opaque) {
2348 gVirtualX->DrawBox(px1old, py1old, px2old, py2old, TVirtualX::kHollow);
2349 } else {
2350 if (axisNumber == 1) {
2351 zbx1 = AbsPixeltoX(px1old);
2352 zbx2 = AbsPixeltoX(px2old);
2353 zby1 = GetUymin();
2354 zby2 = GetUymax();
2355 } else if (axisNumber == 2) {
2356 zbx1 = GetUxmin();
2357 zbx2 = GetUxmax();
2358 zby1 = AbsPixeltoY(py1old);
2359 zby2 = AbsPixeltoY(py2old);
2360 }
2361 if (GetLogx()) {
2362 zbx1 = TMath::Power(10,zbx1);
2363 zbx2 = TMath::Power(10,zbx2);
2364 }
2365 if (GetLogy()) {
2366 zby1 = TMath::Power(10,zby1);
2367 zby2 = TMath::Power(10,zby2);
2368 }
2369 zoombox = std::make_unique<TBox>(zbx1, zby1, zbx2, zby2);
2370 Int_t ci = TColor::GetColor("#7d7dff");
2371 TColor *zoomcolor = gROOT->GetColor(ci);
2372 if (!TCanvas::SupportAlpha() || !zoomcolor) zoombox->SetFillStyle(3002);
2373 else zoomcolor->SetAlpha(0.5);
2374 zoombox->SetFillColor(ci);
2375 zoombox->Draw();
2376 gPad->Modified();
2377 gPad->Update();
2378 }
2379 }
2380 if (!opaque) gVirtualX->SetLineColor(-1);
2381 // No break !!!
2382
2383 case kButton1Motion:
2384 if (view) {
2385 view->GetDistancetoAxis(axisNumber, px, py, ratio2);
2386 } else {
2387 if (!opaque) gVirtualX->DrawBox(px1old, py1old, px2old, py2old, TVirtualX::kHollow);
2388 if (axisNumber == 1) {
2389 ratio2 = (AbsPixeltoX(px) - GetUxmin())/(GetUxmax() - GetUxmin());
2390 px2old = XtoAbsPixel(GetUxmin()+ratio2*(GetUxmax() - GetUxmin()));
2391 } else {
2392 ratio2 = (AbsPixeltoY(py) - GetUymin())/(GetUymax() - GetUymin());
2393 py2old = YtoAbsPixel(GetUymin()+ratio2*(GetUymax() - GetUymin()));
2394 }
2395 if (!opaque) {
2396 gVirtualX->DrawBox(px1old, py1old, px2old, py2old, TVirtualX::kHollow);
2397 } else {
2398 if (axisNumber == 1) {
2399 zbx1 = AbsPixeltoX(px1old);
2400 zbx2 = AbsPixeltoX(px2old);
2401 zby1 = GetUymin();
2402 zby2 = GetUymax();
2403 } else if (axisNumber == 2) {
2404 zbx1 = GetUxmin();
2405 zbx2 = GetUxmax();
2406 zby1 = AbsPixeltoY(py1old);
2407 zby2 = AbsPixeltoY(py2old);
2408 }
2409 if (GetLogx()) {
2410 zbx1 = TMath::Power(10,zbx1);
2411 zbx2 = TMath::Power(10,zbx2);
2412 }
2413 if (GetLogy()) {
2414 zby1 = TMath::Power(10,zby1);
2415 zby2 = TMath::Power(10,zby2);
2416 }
2417 if (zoombox) {
2418 zoombox->SetX1(zbx1);
2419 zoombox->SetY1(zby1);
2420 zoombox->SetX2(zbx2);
2421 zoombox->SetY2(zby2);
2422 }
2423 gPad->Modified();
2424 gPad->Update();
2425 }
2426 }
2427 break;
2428
2429 case kWheelUp:
2430 bin1 = axis->GetFirst()+1;
2431 bin2 = axis->GetLast()-1;
2432 bin1 = TMath::Max(bin1, 1);
2433 bin2 = TMath::Min(bin2, axis->GetNbins());
2434 if (bin2>bin1) {
2435 axis->SetRange(bin1,bin2);
2436 gPad->Modified();
2437 gPad->Update();
2438 }
2439 break;
2440
2441 case kWheelDown:
2442 bin1 = axis->GetFirst()-1;
2443 bin2 = axis->GetLast()+1;
2444 bin1 = TMath::Max(bin1, 1);
2445 bin2 = TMath::Min(bin2, axis->GetNbins());
2446 if (bin2>bin1) {
2447 axis->SetRange(bin1,bin2);
2448 gPad->Modified();
2449 gPad->Update();
2450 }
2451 break;
2452
2453 case kButton1Up:
2454 if (gROOT->IsEscaped()) {
2455 gROOT->SetEscape(kFALSE);
2456 if (opaque && zoombox)
2457 zoombox.reset();
2458 break;
2459 }
2460
2461 if (view) {
2462 view->GetDistancetoAxis(axisNumber, px, py, ratio2);
2463 if (ratio1 > ratio2) {
2464 temp = ratio1;
2465 ratio1 = ratio2;
2466 ratio2 = temp;
2467 }
2468 if (ratio2 - ratio1 > 0.05) {
2469 TH1 *hobj = (TH1*)axis->GetParent();
2470 if (axisNumber == 3 && hobj && hobj->GetDimension() != 3) {
2471 Float_t zmin = hobj->GetMinimum();
2472 Float_t zmax = hobj->GetMaximum();
2473 if(GetLogz()){
2474 if (zmin <= 0 && zmax > 0) zmin = TMath::Min((Double_t)1,
2475 (Double_t)0.001*zmax);
2476 zmin = TMath::Log10(zmin);
2477 zmax = TMath::Log10(zmax);
2478 }
2479 Float_t newmin = zmin + (zmax-zmin)*ratio1;
2480 Float_t newmax = zmin + (zmax-zmin)*ratio2;
2481 if (newmin < zmin) newmin = hobj->GetBinContent(hobj->GetMinimumBin());
2482 if (newmax > zmax) newmax = hobj->GetBinContent(hobj->GetMaximumBin());
2483 if (GetLogz()){
2484 newmin = TMath::Exp(2.302585092994*newmin);
2485 newmax = TMath::Exp(2.302585092994*newmax);
2486 }
2487 hobj->SetMinimum(newmin);
2488 hobj->SetMaximum(newmax);
2489 hobj->SetBit(TH1::kIsZoomed);
2490 } else {
2491 first = axis->GetFirst();
2492 last = axis->GetLast();
2493 bin1 = first + Int_t((last-first+1)*ratio1);
2494 bin2 = first + Int_t((last-first+1)*ratio2);
2495 bin1 = TMath::Max(bin1, 1);
2496 bin2 = TMath::Min(bin2, axis->GetNbins());
2497 axis->SetRange(bin1, bin2);
2498 }
2499 delete view;
2500 SetView(0);
2501 Modified(kTRUE);
2502 }
2503 } else {
2504 if (axisNumber == 1) {
2505 ratio2 = (AbsPixeltoX(px) - GetUxmin())/(GetUxmax() - GetUxmin());
2506 xmin = GetUxmin() +ratio1*(GetUxmax() - GetUxmin());
2507 xmax = GetUxmin() +ratio2*(GetUxmax() - GetUxmin());
2508 if (GetLogx() && !kCont4) {
2509 xmin = PadtoX(xmin);
2510 xmax = PadtoX(xmax);
2511 }
2512 } else if (axisNumber == 2) {
2513 ratio2 = (AbsPixeltoY(py) - GetUymin())/(GetUymax() - GetUymin());
2514 xmin = GetUymin() +ratio1*(GetUymax() - GetUymin());
2515 xmax = GetUymin() +ratio2*(GetUymax() - GetUymin());
2516 if (GetLogy() && !kCont4) {
2517 xmin = PadtoY(xmin);
2518 xmax = PadtoY(xmax);
2519 }
2520 } else {
2521 ratio2 = (AbsPixeltoY(py) - GetUymin())/(GetUymax() - GetUymin());
2522 xmin = ratio1;
2523 xmax = ratio2;
2524 }
2525 if (xmin > xmax) {
2526 temp = xmin;
2527 xmin = xmax;
2528 xmax = temp;
2529 temp = ratio1;
2530 ratio1 = ratio2;
2531 ratio2 = temp;
2532 }
2533
2534 // xmin and xmax need to be adjusted in case of CONT4.
2535 if (kCont4) {
2536 Double_t low = axis->GetBinLowEdge(axis->GetFirst());
2537 Double_t up = axis->GetBinUpEdge(axis->GetLast());
2538 Double_t xmi = GetUxmin();
2539 Double_t xma = GetUxmax();
2540 xmin = ((xmin-xmi)/(xma-xmi))*(up-low)+low;
2541 xmax = ((xmax-xmi)/(xma-xmi))*(up-low)+low;
2542 }
2543
2544 if (!strcmp(axis->GetName(),"xaxis")) axisNumber = 1;
2545 if (!strcmp(axis->GetName(),"yaxis")) axisNumber = 2;
2546 if (ratio2 - ratio1 > 0.05) {
2547 //update object owning this axis
2548 TH1 *hobj1 = (TH1*)axis->GetParent();
2549 bin1 = axis->FindFixBin(xmin);
2550 bin2 = axis->FindFixBin(xmax);
2551 bin1 = TMath::Max(bin1, 1);
2552 bin2 = TMath::Min(bin2, axis->GetNbins());
2553 if (axisNumber == 1) axis->SetRange(bin1,bin2);
2554 if (axisNumber == 2 && hobj1) {
2555 if (hobj1->GetDimension() == 1) {
2556 if (hobj1->GetNormFactor() != 0) {
2557 Double_t norm = hobj1->GetSumOfWeights()/hobj1->GetNormFactor();
2558 xmin *= norm;
2559 xmax *= norm;
2560 }
2561 hobj1->SetMinimum(xmin);
2562 hobj1->SetMaximum(xmax);
2563 hobj1->SetBit(TH1::kIsZoomed);
2564 } else {
2565 axis->SetRange(bin1,bin2);
2566 }
2567 }
2568 //update all histograms in the pad
2569 TIter next(GetListOfPrimitives());
2570 TObject *obj;
2571 while ((obj= next())) {
2572 if (!obj->InheritsFrom(TH1::Class())) continue;
2573 TH1 *hobj = (TH1*)obj;
2574 if (hobj == hobj1) continue;
2575 bin1 = hobj->GetXaxis()->FindFixBin(xmin);
2576 bin2 = hobj->GetXaxis()->FindFixBin(xmax);
2577 if (axisNumber == 1) {
2578 hobj->GetXaxis()->SetRange(bin1,bin2);
2579 } else if (axisNumber == 2) {
2580 if (hobj->GetDimension() == 1) {
2581 Double_t xxmin = xmin;
2582 Double_t xxmax = xmax;
2583 if (hobj->GetNormFactor() != 0) {
2584 Double_t norm = hobj->GetSumOfWeights()/hobj->GetNormFactor();
2585 xxmin *= norm;
2586 xxmax *= norm;
2587 }
2588 hobj->SetMinimum(xxmin);
2589 hobj->SetMaximum(xxmax);
2590 hobj->SetBit(TH1::kIsZoomed);
2591 } else {
2592 bin1 = hobj->GetYaxis()->FindFixBin(xmin);
2593 bin2 = hobj->GetYaxis()->FindFixBin(xmax);
2594 hobj->GetYaxis()->SetRange(bin1,bin2);
2595 }
2596 }
2597 }
2598 Modified(kTRUE);
2599 }
2600 }
2601 if (!opaque) {
2602 gVirtualX->SetLineColor(-1);
2603 } else {
2604 if (zoombox) {
2605 zoombox.reset();
2606 gPad->Modified();
2607 gPad->Update();
2608 }
2609 }
2610 break;
2611 }
2612}
2613
2614////////////////////////////////////////////////////////////////////////////////
2615/// Search if object named name is inside this pad or in pads inside this pad.
2616///
2617/// In case name is in several sub-pads the first one is returned.
2618
2619TObject *TPad::FindObject(const char *name) const
2620{
2621 if (!fPrimitives) return nullptr;
2623 if (found) return found;
2624 TObject *cur;
2625 TIter next(GetListOfPrimitives());
2626 while ((cur = next())) {
2627 if (cur->InheritsFrom(TPad::Class())) {
2628 found = ((TPad*)cur)->FindObject(name);
2629 if (found) return found;
2630 }
2631 }
2632 return nullptr;
2633}
2634
2635////////////////////////////////////////////////////////////////////////////////
2636/// Search if obj is in pad or in pads inside this pad.
2637///
2638/// In case obj is in several sub-pads the first one is returned.
2639
2641{
2642 if (!fPrimitives) return nullptr;
2643 TObject *found = fPrimitives->FindObject(obj);
2644 if (found) return found;
2645 TObject *cur;
2646 TIter next(GetListOfPrimitives());
2647 while ((cur = next())) {
2648 if (cur->InheritsFrom(TPad::Class())) {
2649 found = ((TPad*)cur)->FindObject(obj);
2650 if (found) return found;
2651 }
2652 }
2653 return nullptr;
2654}
2655
2656////////////////////////////////////////////////////////////////////////////////
2657/// Get canvas identifier.
2658
2660{
2661 return fCanvas ? fCanvas->GetCanvasID() : -1;
2662}
2663
2664////////////////////////////////////////////////////////////////////////////////
2665/// Get canvas implementation pointer if any
2666
2668{
2669 return fCanvas ? fCanvas->GetCanvasImp() : nullptr;
2670}
2671
2672////////////////////////////////////////////////////////////////////////////////
2673/// Get Event.
2674
2676{
2677 return fCanvas ? fCanvas->GetEvent() : 0;
2678}
2679
2680////////////////////////////////////////////////////////////////////////////////
2681/// Get X event.
2682
2684{
2685 return fCanvas ? fCanvas->GetEventX() : 0;
2686}
2687
2688////////////////////////////////////////////////////////////////////////////////
2689/// Get Y event.
2690
2692{
2693 return fCanvas ? fCanvas->GetEventY() : 0;
2694}
2695
2696////////////////////////////////////////////////////////////////////////////////
2697/// Get virtual canvas.
2698
2700{
2701 return fCanvas ? (TVirtualPad*) fCanvas : nullptr;
2702}
2703
2704////////////////////////////////////////////////////////////////////////////////
2705/// Get highlight color.
2706
2708{
2709 return fCanvas ? fCanvas->GetHighLightColor() : 0;
2710}
2711
2712////////////////////////////////////////////////////////////////////////////////
2713/// Static function (see also TPad::SetMaxPickDistance)
2714
2716{
2717 return fgMaxPickDistance;
2718}
2719
2720////////////////////////////////////////////////////////////////////////////////
2721/// Get selected.
2722
2724{
2725 if (fCanvas == this) return nullptr;
2726 return fCanvas ? fCanvas->GetSelected() : nullptr;
2727}
2728
2729////////////////////////////////////////////////////////////////////////////////
2730/// Get selected pad.
2731
2733{
2734 if (fCanvas == this) return nullptr;
2735 return fCanvas ? fCanvas->GetSelectedPad() : nullptr;
2736}
2737
2738////////////////////////////////////////////////////////////////////////////////
2739/// Get save pad.
2740
2742{
2743 if (fCanvas == this) return nullptr;
2744 return fCanvas ? fCanvas->GetPadSave() : nullptr;
2745}
2746
2747////////////////////////////////////////////////////////////////////////////////
2748/// Get Wh.
2749
2751{
2752 return fCanvas ? fCanvas->GetWh() : 0;
2753}
2754
2755////////////////////////////////////////////////////////////////////////////////
2756/// Get Ww.
2757
2759{
2760 return fCanvas ? fCanvas->GetWw() : 0;
2761}
2762
2763////////////////////////////////////////////////////////////////////////////////
2764/// Hide tool tip depending on the event type. Typically tool tips
2765/// are hidden when event is not a kMouseEnter and not a kMouseMotion
2766/// event.
2767
2769{
2770 if (event != kMouseEnter && event != kMouseMotion && fTip)
2771 gPad->CloseToolTip(fTip);
2772}
2773
2774////////////////////////////////////////////////////////////////////////////////
2775/// Is pad in batch mode ?
2776
2778{
2779 return fCanvas ? fCanvas->IsBatch() : kFALSE;
2780}
2781
2782////////////////////////////////////////////////////////////////////////////////
2783/// Is pad retained ?
2784
2786{
2787 return fCanvas ? fCanvas->IsRetained() : kFALSE;
2788}
2789
2790////////////////////////////////////////////////////////////////////////////////
2791/// Is pad moving in opaque mode ?
2792
2794{
2795 return fCanvas ? fCanvas->OpaqueMoving() : kFALSE;
2796}
2797
2798////////////////////////////////////////////////////////////////////////////////
2799/// Is pad resizing in opaque mode ?
2800
2802{
2803 return fCanvas ? fCanvas->OpaqueResizing() : kFALSE;
2804}
2805
2806////////////////////////////////////////////////////////////////////////////////
2807/// Set pad in batch mode.
2808
2810{
2811 if (fCanvas) fCanvas->SetBatch(batch);
2812}
2813
2814////////////////////////////////////////////////////////////////////////////////
2815/// Set canvas size.
2816
2818{
2819 if (fCanvas) fCanvas->SetCanvasSize(ww,wh);
2820}
2821
2822////////////////////////////////////////////////////////////////////////////////
2823/// Set cursor type.
2824
2826{
2828}
2829
2830////////////////////////////////////////////////////////////////////////////////
2831/// Set double buffer mode ON or OFF.
2832
2834{
2836}
2837
2838////////////////////////////////////////////////////////////////////////////////
2839/// Set selected.
2840
2842{
2843 if (fCanvas) fCanvas->SetSelected(obj);
2844}
2845
2846////////////////////////////////////////////////////////////////////////////////
2847/// Update pad.
2848
2850{
2851 if (fCanvas) fCanvas->Update();
2852}
2853
2854////////////////////////////////////////////////////////////////////////////////
2855/// Get frame.
2856
2858{
2859 if (!fPrimitives) fPrimitives = new TList;
2861 if (!frame) frame = (TFrame*)GetListOfPrimitives()->FindObject("TFrame");
2862 fFrame = frame;
2863 if (!fFrame) {
2864 if (!frame) fFrame = new TFrame(0,0,1,1);
2865 Int_t framecolor = GetFrameFillColor();
2866 if (!framecolor) framecolor = GetFillColor();
2867 fFrame->SetFillColor(framecolor);
2874 }
2875 return fFrame;
2876}
2877
2878////////////////////////////////////////////////////////////////////////////////
2879/// Get primitive.
2880
2882{
2883 if (!fPrimitives) return nullptr;
2884 TIter next(fPrimitives);
2885 TObject *found, *obj;
2886 while ((obj=next())) {
2887 if (!strcmp(name, obj->GetName())) return obj;
2888 if (obj->InheritsFrom(TPad::Class())) continue;
2889 found = obj->FindObject(name);
2890 if (found) return found;
2891 }
2892 return nullptr;
2893}
2894
2895////////////////////////////////////////////////////////////////////////////////
2896/// Get a pointer to subpadnumber of this pad.
2897
2898TVirtualPad *TPad::GetPad(Int_t subpadnumber) const
2899{
2900 if (!subpadnumber) {
2901 return (TVirtualPad*)this;
2902 }
2903
2904 TObject *obj;
2905 if (!fPrimitives) return nullptr;
2906 TIter next(GetListOfPrimitives());
2907 while ((obj = next())) {
2908 if (obj->InheritsFrom(TVirtualPad::Class())) {
2909 TVirtualPad *pad = (TVirtualPad*)obj;
2910 if (pad->GetNumber() == subpadnumber) return pad;
2911 }
2912 }
2913 return nullptr;
2914}
2915
2916////////////////////////////////////////////////////////////////////////////////
2917/// Return lower and upper bounds of the pad in NDC coordinates.
2918
2919void TPad::GetPadPar(Double_t &xlow, Double_t &ylow, Double_t &xup, Double_t &yup)
2920{
2921 xlow = fXlowNDC;
2922 ylow = fYlowNDC;
2923 xup = fXlowNDC+fWNDC;
2924 yup = fYlowNDC+fHNDC;
2925}
2926
2927////////////////////////////////////////////////////////////////////////////////
2928/// Return pad world coordinates range.
2929
2931{
2932 x1 = fX1;
2933 y1 = fY1;
2934 x2 = fX2;
2935 y2 = fY2;
2936}
2937
2938////////////////////////////////////////////////////////////////////////////////
2939/// Return pad axis coordinates range.
2940
2942{
2943 xmin = fUxmin;
2944 ymin = fUymin;
2945 xmax = fUxmax;
2946 ymax = fUymax;
2947}
2948
2949////////////////////////////////////////////////////////////////////////////////
2950/// Highlight pad.
2951/// do not highlight when printing on Postscript
2952
2954{
2955 if (gVirtualPS && gVirtualPS->TestBit(kPrintingPS)) return;
2956
2957 if (color <= 0) return;
2958
2960
2961 // We do not want to have active(executable) buttons, etc highlighted
2962 // in this manner, unless we want to edit'em
2964 //When doing a DrawClone from the GUI you would do
2965 // - select an empty pad -
2966 // - right click on object -
2967 // - select DrawClone on menu -
2968 //
2969 // Without the SetSelectedPad(); in the HighLight function, the
2970 // above instruction lead to the clone to be drawn in the
2971 // same canvas as the original object. This is because the
2972 // 'right clicking' (via TCanvas::HandleInput) changes gPad
2973 // momentarily such that when DrawClone is called, it is
2974 // not the right value (for DrawClone). Should be FIXED.
2975 gROOT->SetSelectedPad(this);
2976 if (GetBorderMode()>0) {
2977 if (set) PaintBorder(-color, kFALSE);
2979 }
2980 }
2981
2983}
2984
2985////////////////////////////////////////////////////////////////////////////////
2986/// List all primitives in pad.
2987
2989{
2991 std::cout <<IsA()->GetName()<<" fXlowNDC=" <<fXlowNDC<<" fYlowNDC="<<fYlowNDC<<" fWNDC="<<GetWNDC()<<" fHNDC="<<GetHNDC()
2992 <<" Name= "<<GetName()<<" Title= "<<GetTitle()<<" Option="<<option<<std::endl;
2994 if (!fPrimitives) return;
2997}
2998
2999////////////////////////////////////////////////////////////////////////////////
3000/// Increment (i==1) or set (i>1) the number of autocolor in the pad.
3001
3003{
3004 if (opt.Index("pfc")>=0 || opt.Index("plc")>=0 || opt.Index("pmc")>=0) {
3005 if (i==1) fNumPaletteColor++;
3006 else fNumPaletteColor = i;
3007 return fNumPaletteColor;
3008 } else {
3009 return 0;
3010 }
3011}
3012
3013////////////////////////////////////////////////////////////////////////////////
3014/// Get the next autocolor in the pad.
3015
3017{
3018 Int_t i = 0;
3019 Int_t ncolors = gStyle->GetNumberOfColors();
3020 if (fNumPaletteColor>1) {
3021 i = fNextPaletteColor*(ncolors/(fNumPaletteColor-1));
3022 if (i>=ncolors) i = ncolors-1;
3023 }
3026 return gStyle->GetColorPalette(i);
3027}
3028
3029////////////////////////////////////////////////////////////////////////////////
3030/// Initialise the grid used to find empty space when adding a box (Legend) in a pad
3031
3033{
3034 Int_t const cellSize = 10; // Sive of an individual grid cell in pixels.
3035
3036 if (fCGnx == 0 && fCGny == 0) {
3037 fCGnx = (Int_t)(gPad->GetWw())/cellSize;
3038 fCGny = (Int_t)(gPad->GetWh())/cellSize;
3039 } else {
3040 Int_t CGnx = (Int_t)(gPad->GetWw())/cellSize;
3041 Int_t CGny = (Int_t)(gPad->GetWh())/cellSize;
3042 if (fCGnx != CGnx || fCGny != CGny) {
3043 fCGnx = CGnx;
3044 fCGny = CGny;
3045 delete [] fCollideGrid;
3046 fCollideGrid = nullptr;
3047 }
3048 }
3049
3050 // Initialise the collide grid
3051 if (!fCollideGrid) {
3053 for (int i = 0; i<fCGnx; i++) {
3054 for (int j = 0; j<fCGny; j++) {
3055 fCollideGrid[i + j*fCGnx] = kTRUE;
3056 }
3057 }
3058 }
3059
3060 // Fill the collide grid
3062 if (!l) return;
3063 Int_t np = l->GetSize();
3064 TObject *o;
3065
3066 for (int i=0; i<np; i++) {
3067 o = (TObject *) l->At(i);
3068 if (o!=oi) {
3069 if (o->InheritsFrom(TFrame::Class())) { FillCollideGridTFrame(o); continue;}
3070 if (o->InheritsFrom(TBox::Class())) { FillCollideGridTBox(o); continue;}
3071 if (o->InheritsFrom(TH1::Class())) { FillCollideGridTH1(o); continue;}
3072 if (o->InheritsFrom(TGraph::Class())) { FillCollideGridTGraph(o); continue;}
3073 if (o->InheritsFrom(TMultiGraph::Class())) {
3074 TList * grlist = ((TMultiGraph *)o)->GetListOfGraphs();
3075 TIter nextgraph(grlist);
3076 TObject * og;
3077 while ((og = nextgraph())) FillCollideGridTGraph(og);
3078 }
3079 if (o->InheritsFrom(THStack::Class())) {
3080 TList * hlist = ((THStack *)o)->GetHists();
3081 TIter nexthist(hlist);
3082 TObject * oh;
3083 while ((oh = nexthist())) {
3085 }
3086 }
3087 }
3088 }
3089}
3090
3091////////////////////////////////////////////////////////////////////////////////
3092/// Check if a box of size w and h collide some primitives in the pad at
3093/// position i,j
3094
3096{
3097 for (int r=i; r<w+i; r++) {
3098 for (int c=j; c<h+j; c++) {
3099 if (!fCollideGrid[r + c*fCGnx]) return kTRUE;
3100 }
3101 }
3102 return kFALSE;
3103}
3104
3105////////////////////////////////////////////////////////////////////////////////
3106/// Place a box in NDC space
3107///
3108/// \return `true` if the box could be placed, `false` if not.
3109///
3110/// \param[in] o pointer to the box to be placed
3111/// \param[in] w box width to be placed
3112/// \param[in] h box height to be placed
3113/// \param[out] xl x position of the bottom left corner of the placed box
3114/// \param[out] yb y position of the bottom left corner of the placed box
3115
3117{
3118 FillCollideGrid(o);
3119
3120 Int_t iw = (int)(fCGnx*w);
3121 Int_t ih = (int)(fCGny*h);
3122
3123 Int_t nxmax = fCGnx-iw-1;
3124 Int_t nymax = fCGny-ih-1;
3125
3126 for (Int_t i = 0; i<nxmax; i++) {
3127 for (Int_t j = 0; j<=nymax; j++) {
3128 if (Collide(i,j,iw,ih)) {
3129 continue;
3130 } else {
3131 xl = (Double_t)(i)/(Double_t)(fCGnx);
3132 yb = (Double_t)(j)/(Double_t)(fCGny);
3133 return kTRUE;
3134 }
3135 }
3136 }
3137 return kFALSE;
3138}
3139
3140#define NotFree(i, j) fCollideGrid[TMath::Max(TMath::Min(i+j*fCGnx,fCGnx*fCGny),0)] = kFALSE;
3141
3142////////////////////////////////////////////////////////////////////////////////
3143/// Mark as "not free" the cells along a line.
3144
3146{
3147 NotFree(x1, y1);
3148 NotFree(x2, y2);
3149 Int_t i, j, xt, yt;
3150
3151 // horizontal lines
3152 if (y1==y2) {
3153 for (i=x1+1; i<x2; i++) NotFree(i,y1);
3154 return;
3155 }
3156
3157 // vertical lines
3158 if (x1==x2) {
3159 for (i=y1+1; i<y2; i++) NotFree(x1,i);
3160 return;
3161 }
3162
3163 // other lines
3164 if (TMath::Abs(x2-x1)>TMath::Abs(y2-y1)) {
3165 if (x1>x2) {
3166 xt = x1; x1 = x2; x2 = xt;
3167 yt = y1; y1 = y2; y2 = yt;
3168 }
3169 for (i=x1+1; i<x2; i++) {
3170 j = (Int_t)((Double_t)(y2-y1)*(Double_t)((i-x1)/(Double_t)(x2-x1))+y1);
3171 NotFree(i,j);
3172 NotFree(i,(j+1));
3173 }
3174 } else {
3175 if (y1>y2) {
3176 yt = y1; y1 = y2; y2 = yt;
3177 xt = x1; x1 = x2; x2 = xt;
3178 }
3179 for (j=y1+1; j<y2; j++) {
3180 i = (Int_t)((Double_t)(x2-x1)*(Double_t)((j-y1)/(Double_t)(y2-y1))+x1);
3181 NotFree(i,j);
3182 NotFree((i+1),j);
3183 }
3184 }
3185}
3186
3187////////////////////////////////////////////////////////////////////////////////
3189{
3190 TBox *b = (TBox *)o;
3191 if (fCGnx==0||fCGny==0) return;
3192 Double_t xs = (fX2-fX1)/fCGnx;
3193 Double_t ys = (fY2-fY1)/fCGny;
3194
3195 Int_t x1 = (Int_t)((b->GetX1()-fX1)/xs);
3196 Int_t x2 = (Int_t)((b->GetX2()-fX1)/xs);
3197 Int_t y1 = (Int_t)((b->GetY1()-fY1)/ys);
3198 Int_t y2 = (Int_t)((b->GetY2()-fY1)/ys);
3199 for (int i = x1; i<=x2; i++) {
3200 for (int j = y1; j<=y2; j++) NotFree(i, j);
3201 }
3202}
3203
3204////////////////////////////////////////////////////////////////////////////////
3206{
3207 TFrame *f = (TFrame *)o;
3208 if (fCGnx==0||fCGny==0) return;
3209 Double_t xs = (fX2-fX1)/fCGnx;
3210 Double_t ys = (fY2-fY1)/fCGny;
3211
3212 Int_t x1 = (Int_t)((f->GetX1()-fX1)/xs);
3213 Int_t x2 = (Int_t)((f->GetX2()-fX1)/xs);
3214 Int_t y1 = (Int_t)((f->GetY1()-fY1)/ys);
3215 Int_t y2 = (Int_t)((f->GetY2()-fY1)/ys);
3216 Int_t i;
3217
3218 for (i = x1; i<=x2; i++) {
3219 NotFree(i, y1);
3220 NotFree(i, (y1-1));
3221 NotFree(i, (y1-2));
3222 }
3223 for (i = y1; i<=y2; i++) {
3224 NotFree(x1, i);
3225 NotFree((x1-1), i);
3226 NotFree((x1-2), i);
3227 }
3228}
3229
3230////////////////////////////////////////////////////////////////////////////////
3232{
3233 TGraph *g = (TGraph *)o;
3234 if (fCGnx==0||fCGny==0) return;
3235 Double_t xs = (fX2-fX1)/fCGnx;
3236 Double_t ys = (fY2-fY1)/fCGny;
3237
3238 Int_t n = g->GetN();
3239 Int_t s = TMath::Max(n/10,1);
3240 Double_t x1, x2, y1, y2;
3241 for (Int_t i=s; i<n; i=i+s) {
3242 g->GetPoint(TMath::Max(0,i-s),x1,y1);
3243 g->GetPoint(i ,x2,y2);
3244 if (fLogx) {
3245 if (x1 > 0) x1 = TMath::Log10(x1);
3246 else x1 = fUxmin;
3247 if (x2 > 0) x2 = TMath::Log10(x2);
3248 else x2 = fUxmin;
3249 }
3250 if (fLogy) {
3251 if (y1 > 0) y1 = TMath::Log10(y1);
3252 else y1 = fUymin;
3253 if (y2 > 0) y2 = TMath::Log10(y2);
3254 else y2 = fUymin;
3255 }
3256 LineNotFree((int)((x1-fX1)/xs), (int)((x2-fX1)/xs),
3257 (int)((y1-fY1)/ys), (int)((y2-fY1)/ys));
3258 }
3259}
3260
3261////////////////////////////////////////////////////////////////////////////////
3263{
3264 TH1 *h = (TH1 *)o;
3265 if (fCGnx==0||fCGny==0) return;
3266 if (o->InheritsFrom(TH2::Class())) return;
3267 if (o->InheritsFrom(TH3::Class())) return;
3268
3269 TString name = h->GetName();
3270 if (name.Index("hframe") >= 0) return;
3271
3272 Double_t xs = (fX2-fX1)/fCGnx;
3273 Double_t ys = (fY2-fY1)/fCGny;
3274
3275 bool haserrors = false;
3276 TString drawOption = h->GetDrawOption();
3277 drawOption.ToLower();
3278 drawOption.ReplaceAll("same","");
3279
3280 if (drawOption.Index("hist") < 0) {
3281 if (drawOption.Index("e") >= 0) haserrors = true;
3282 }
3283
3284 Int_t nx = h->GetNbinsX();
3285 Int_t x1, y1, y2;
3286 Int_t i, j;
3287 Double_t x1l, y1l, y2l;
3288
3289 for (i = 1; i<nx; i++) {
3290 if (haserrors) {
3291 x1l = h->GetBinCenter(i);
3292 if (fLogx) {
3293 if (x1l > 0) x1l = TMath::Log10(x1l);
3294 else x1l = fUxmin;
3295 }
3296 x1 = (Int_t)((x1l-fX1)/xs);
3297 y1l = h->GetBinContent(i)-h->GetBinErrorLow(i);
3298 if (fLogy) {
3299 if (y1l > 0) y1l = TMath::Log10(y1l);
3300 else y1l = fUymin;
3301 }
3302 y1 = (Int_t)((y1l-fY1)/ys);
3303 y2l = h->GetBinContent(i)+h->GetBinErrorUp(i);
3304 if (fLogy) {
3305 if (y2l > 0) y2l = TMath::Log10(y2l);
3306 else y2l = fUymin;
3307 }
3308 y2 = (Int_t)((y2l-fY1)/ys);
3309 for (j=y1; j<=y2; j++) {
3310 NotFree(x1, j);
3311 }
3312 }
3313 x1l = h->GetBinLowEdge(i);
3314 if (fLogx) {
3315 if (x1l > 0) x1l = TMath::Log10(x1l);
3316 else x1l = fUxmin;
3317 }
3318 x1 = (Int_t)((x1l-fX1)/xs);
3319 y1l = h->GetBinContent(i);
3320 if (fLogy) {
3321 if (y1l > 0) y1l = TMath::Log10(y1l);
3322 else y1l = fUymin;
3323 }
3324 y1 = (Int_t)((y1l-fY1)/ys);
3325 NotFree(x1, y1);
3326 x1l = h->GetBinLowEdge(i)+h->GetBinWidth(i);
3327 if (fLogx) {
3328 if (x1l > 0) x1l = TMath::Log10(x1l);
3329 else x1l = fUxmin;
3330 }
3331 x1 = (int)((x1l-fX1)/xs);
3332 NotFree(x1, y1);
3333 }
3334
3335 // Extra objects in the list of function
3336 TPaveStats *ps = (TPaveStats*)h->GetListOfFunctions()->FindObject("stats");
3338}
3339
3340////////////////////////////////////////////////////////////////////////////////
3341/// This method draws the collide grid on top of the canvas. This is used for
3342/// debugging only. At some point it will be removed.
3343
3345{
3346 if (fCGnx==0||fCGny==0) return;
3347 auto box = new TBox();
3348 box->SetFillColorAlpha(kRed,0.5);
3349
3350 Double_t xs = (fX2-fX1)/fCGnx;
3351 Double_t ys = (fY2-fY1)/fCGny;
3352
3353 Double_t X1L, X2L, Y1L, Y2L;
3354 Double_t t = 0.15;
3355 Double_t Y1, Y2;
3356 Double_t X1 = fX1;
3357 Double_t X2 = X1+xs;
3358
3359 for (int i = 0; i<fCGnx; i++) {
3360 Y1 = fY1;
3361 Y2 = Y1+ys;
3362 for (int j = 0; j<fCGny; j++) {
3363 if (gPad->GetLogx()) {
3364 X1L = TMath::Power(10,X1);
3365 X2L = TMath::Power(10,X2);
3366 } else {
3367 X1L = X1;
3368 X2L = X2;
3369 }
3370 if (gPad->GetLogy()) {
3371 Y1L = TMath::Power(10,Y1);
3372 Y2L = TMath::Power(10,Y2);
3373 } else {
3374 Y1L = Y1;
3375 Y2L = Y2;
3376 }
3377 if (!fCollideGrid[i + j*fCGnx]) {
3378 box->SetFillColorAlpha(kBlack,t);
3379 box->DrawBox(X1L, Y1L, X2L, Y2L);
3380 } else {
3381 box->SetFillColorAlpha(kRed,t);
3382 box->DrawBox(X1L, Y1L, X2L, Y2L);
3383 }
3384 Y1 = Y2;
3385 Y2 = Y1+ys;
3386 if (t==0.15) t = 0.1;
3387 else t = 0.15;
3388 }
3389 X1 = X2;
3390 X2 = X1+xs;
3391 }
3392}
3393
3394
3395////////////////////////////////////////////////////////////////////////////////
3396/// Convert x from pad to X.
3397
3399{
3400 if (fLogx && x < 50) return Double_t(TMath::Exp(2.302585092994*x));
3401 return x;
3402}
3403
3404////////////////////////////////////////////////////////////////////////////////
3405/// Convert y from pad to Y.
3406
3408{
3409 if (fLogy && y < 50) return Double_t(TMath::Exp(2.302585092994*y));
3410 return y;
3411}
3412
3413////////////////////////////////////////////////////////////////////////////////
3414/// Convert x from X to pad.
3415
3417{
3418 if (fLogx) {
3419 if (x > 0) x = TMath::Log10(x);
3420 else x = fUxmin;
3421 }
3422 return x;
3423}
3424
3425////////////////////////////////////////////////////////////////////////////////
3426/// Convert y from Y to pad.
3427
3429{
3430 if (fLogy) {
3431 if (y > 0) y = TMath::Log10(y);
3432 else y = fUymin;
3433 }
3434 return y;
3435}
3436
3437////////////////////////////////////////////////////////////////////////////////
3438/// Paint all primitives in pad.
3439
3440void TPad::Paint(Option_t * /*option*/)
3441{
3442 if (!fPrimitives) fPrimitives = new TList;
3444 fViewer3D->PadPaint(this);
3446 if (GetGLDevice()!=-1 && gVirtualPS) {
3447 TPad *padsav = (TPad*)gPad;
3448 gPad = this;
3449 if (gGLManager) gGLManager->PrintViewer(GetViewer3D());
3450 gPad = padsav;
3451 }
3452 return;
3453 }
3454
3456
3457 TPad *padsav = (TPad*)gPad;
3458
3459 fPadPaint = 1;
3460 cd();
3461
3463 PaintDate();
3464
3466 TObject *obj;
3467
3468 Bool_t began3DScene = kFALSE;
3469 while (lnk) {
3470 obj = lnk->GetObject();
3471
3472 // Create a pad 3D viewer if none exists and we encounter a 3D shape
3473 if (!fViewer3D && obj->InheritsFrom(TAtt3D::Class())) {
3474 GetViewer3D("pad");
3475 }
3476
3477 // Open a 3D scene if required
3478 if (fViewer3D && !fViewer3D->BuildingScene()) {
3480 began3DScene = kTRUE;
3481 }
3482
3483 obj->Paint(lnk->GetOption());
3484 lnk = (TObjOptLink*)lnk->Next();
3485 }
3486
3487 if (padsav) padsav->cd();
3488 fPadPaint = 0;
3490
3491 // Close the 3D scene if we opened it. This must be done after modified
3492 // flag is cleared, as some viewers will invoke another paint by marking pad modified again
3493 if (began3DScene) {
3495 }
3496}
3497
3498////////////////////////////////////////////////////////////////////////////////
3499/// Paint the pad border.
3500/// Draw first a box as a normal filled box
3501
3503{
3504 if (color >= 0) {
3505 TAttLine::Modify(); //Change line attributes only if necessary
3506 TAttFill::Modify(); //Change fill area attributes only if necessary
3507
3508 //With Cocoa we have a transparency. But we also have
3509 //pixmaps, and if you just paint a new content over the old one
3510 //with alpha < 1., you'll be able to see the old content.
3511 if (!gROOT->IsBatch() && gVirtualX->InheritsFrom("TGCocoa") && GetPainter())
3513
3515 }
3516 if (color < 0) color = -color;
3517 // then paint 3d frame (depending on bordermode)
3518 if (IsTransparent()) return;
3519 // Paint a 3D frame around the pad.
3520
3521 if (fBorderMode == 0) return;
3522 Int_t bordersize = fBorderSize;
3523 if (bordersize <= 0) bordersize = 2;
3524
3525 const Double_t realBsX = bordersize / (GetAbsWNDC() * GetWw()) * (fX2 - fX1);
3526 const Double_t realBsY = bordersize / (GetAbsHNDC() * GetWh()) * (fY2 - fY1);
3527
3528 Short_t px1,py1,px2,py2;
3529 Double_t xl, xt, yl, yt;
3530
3531 // GetDarkColor() and GetLightColor() use GetFillColor()
3532 Color_t oldcolor = GetFillColor();
3533 SetFillColor(color);
3535 Color_t light = 0, dark = 0;
3536 if (color != 0) {
3537 light = TColor::GetColorBright(color);
3538 dark = TColor::GetColorDark(color);
3539 }
3540
3541 // Compute real left bottom & top right of the box in pixels
3542 px1 = XtoPixel(fX1); py1 = YtoPixel(fY1);
3543 px2 = XtoPixel(fX2); py2 = YtoPixel(fY2);
3544 if (px1 < px2) {xl = fX1; xt = fX2; }
3545 else {xl = fX2; xt = fX1;}
3546 if (py1 > py2) {yl = fY1; yt = fY2;}
3547 else {yl = fY2; yt = fY1;}
3548
3549 Double_t frameXs[7] = {}, frameYs[7] = {};
3550
3551 if (!IsBatch() && GetPainter()) {
3552 // Draw top&left part of the box
3553 frameXs[0] = xl; frameYs[0] = yl;
3554 frameXs[1] = xl + realBsX; frameYs[1] = yl + realBsY;
3555 frameXs[2] = frameXs[1]; frameYs[2] = yt - realBsY;
3556 frameXs[3] = xt - realBsX; frameYs[3] = frameYs[2];
3557 frameXs[4] = xt; frameYs[4] = yt;
3558 frameXs[5] = xl; frameYs[5] = yt;
3559 frameXs[6] = xl; frameYs[6] = yl;
3560
3561 if (fBorderMode == -1) GetPainter()->SetFillColor(dark);
3562 else GetPainter()->SetFillColor(light);
3563 GetPainter()->DrawFillArea(7, frameXs, frameYs);
3564
3565 // Draw bottom&right part of the box
3566 frameXs[0] = xl; frameYs[0] = yl;
3567 frameXs[1] = xl + realBsX; frameYs[1] = yl + realBsY;
3568 frameXs[2] = xt - realBsX; frameYs[2] = frameYs[1];
3569 frameXs[3] = frameXs[2]; frameYs[3] = yt - realBsY;
3570 frameXs[4] = xt; frameYs[4] = yt;
3571 frameXs[5] = xt; frameYs[5] = yl;
3572 frameXs[6] = xl; frameYs[6] = yl;
3573
3574 if (fBorderMode == -1) GetPainter()->SetFillColor(light);
3575 else GetPainter()->SetFillColor(dark);
3576 GetPainter()->DrawFillArea(7, frameXs, frameYs);
3577
3578 // If this pad is a button, highlight it
3579 if (InheritsFrom(TButton::Class()) && fBorderMode == -1) {
3580 if (TestBit(kFraming)) { // bit set in TButton::SetFraming
3581 if (GetFillColor() != 2) GetPainter()->SetLineColor(2);
3582 else GetPainter()->SetLineColor(4);
3583 GetPainter()->DrawBox(xl + realBsX, yl + realBsY, xt - realBsX, yt - realBsY, TVirtualPadPainter::kHollow);
3584 }
3585 }
3586 GetPainter()->SetFillColor(-1);
3587 SetFillColor(oldcolor);
3588 }
3589
3590 if (!tops) return;
3591
3592 PaintBorderPS(xl, yl, xt, yt, fBorderMode, bordersize, dark, light);
3593}
3594
3595////////////////////////////////////////////////////////////////////////////////
3596/// Paint a frame border with Postscript.
3597
3599{
3600 if (!gVirtualPS) return;
3601 gVirtualPS->DrawFrame(xl, yl, xt, yt, bmode,bsize,dark,light);
3602}
3603
3604////////////////////////////////////////////////////////////////////////////////
3605/// Paint the current date and time if the option `Date` is set on via `gStyle->SetOptDate()`
3606/// Paint the current file name if the option `File` is set on via `gStyle->SetOptFile()`
3607
3609{
3610 if (fCanvas == this) {
3611 if (gStyle->GetOptDate()) {
3612 TDatime dt;
3613 const char *dates;
3614 char iso[16];
3615 if (gStyle->GetOptDate() < 10) {
3616 //by default use format like "Wed Sep 25 17:10:35 2002"
3617 dates = dt.AsString();
3618 } else if (gStyle->GetOptDate() < 20) {
3619 //use ISO format like 2002-09-25
3620 strlcpy(iso,dt.AsSQLString(),16);
3621 dates = iso;
3622 } else {
3623 //use ISO format like 2002-09-25 17:10:35
3624 dates = dt.AsSQLString();
3625 }
3626 TText tdate(gStyle->GetDateX(),gStyle->GetDateY(),dates);
3632 tdate.SetNDC();
3633 tdate.Paint();
3634 }
3635 if (gStyle->GetOptFile() && gFile) {
3636 TText tfile(1. - gStyle->GetDateX(),gStyle->GetDateY(),gFile->GetName());
3640 tfile.SetTextAlign(31);
3642 tfile.SetNDC();
3643 tfile.Paint();
3644 }
3645 }
3646}
3647
3648////////////////////////////////////////////////////////////////////////////////
3649/// Paint histogram/graph frame.
3650
3652{
3653 if (!fPrimitives) fPrimitives = new TList;
3654 TList *glist = GetListOfPrimitives();
3655 TFrame *frame = GetFrame();
3656 frame->SetX1(xmin);
3657 frame->SetX2(xmax);
3658 frame->SetY1(ymin);
3659 frame->SetY2(ymax);
3660 if (!glist->FindObject(fFrame)) {
3661 glist->AddFirst(frame);
3663 }
3664 frame->Paint();
3665}
3666
3667////////////////////////////////////////////////////////////////////////////////
3668/// Traverse pad hierarchy and (re)paint only modified pads.
3669
3671{
3673 if (IsModified()) {
3674 fViewer3D->PadPaint(this);
3676 }
3677 TList *pList = GetListOfPrimitives();
3678 TObjOptLink *lnk = 0;
3679 if (pList) lnk = (TObjOptLink*)pList->FirstLink();
3680 TObject *obj;
3681 while (lnk) {
3682 obj = lnk->GetObject();
3683 if (obj->InheritsFrom(TPad::Class()))
3684 ((TPad*)obj)->PaintModified();
3685 lnk = (TObjOptLink*)lnk->Next();
3686 }
3687 return;
3688 }
3689
3691
3692 TPad *padsav = (TPad*)gPad;
3693 TVirtualPS *saveps = gVirtualPS;
3694 if (gVirtualPS) {
3696 }
3697 fPadPaint = 1;
3698 cd();
3699 if (IsModified() || IsTransparent()) {
3700 if ((fFillStyle < 3026) && (fFillStyle > 3000)) {
3701 if (!gPad->IsBatch() && GetPainter()) GetPainter()->ClearDrawable();
3702 }
3704 }
3705
3706 PaintDate();
3707
3708 TList *pList = GetListOfPrimitives();
3709 TObjOptLink *lnk = 0;
3710 if (pList) lnk = (TObjOptLink*)pList->FirstLink();
3711 TObject *obj;
3712
3713 Bool_t began3DScene = kFALSE;
3714
3715 while (lnk) {
3716 obj = lnk->GetObject();
3717 if (obj->InheritsFrom(TPad::Class())) {
3718 ((TPad*)obj)->PaintModified();
3719 } else if (IsModified() || IsTransparent()) {
3720
3721 // Create a pad 3D viewer if none exists and we encounter a
3722 // 3D shape
3723 if (!fViewer3D && obj->InheritsFrom(TAtt3D::Class())) {
3724 GetViewer3D("pad");
3725 }
3726
3727 // Open a 3D scene if required
3728 if (fViewer3D && !fViewer3D->BuildingScene()) {
3730 began3DScene = kTRUE;
3731 }
3732
3733 obj->Paint(lnk->GetOption());
3734 }
3735 lnk = (TObjOptLink*)lnk->Next();
3736 }
3737
3738 if (padsav) padsav->cd();
3739 fPadPaint = 0;
3741
3742 // This must be done after modified flag is cleared, as some
3743 // viewers will invoke another paint by marking pad modified again
3744 if (began3DScene) {
3746 }
3747
3748 gVirtualPS = saveps;
3749}
3750
3751////////////////////////////////////////////////////////////////////////////////
3752/// Paint box in CurrentPad World coordinates.
3753///
3754/// - if option[0] = 's' the box is forced to be paint with style=0
3755/// - if option[0] = 'l' the box contour is drawn
3756
3758{
3759 if (!gPad->IsBatch() && GetPainter()) {
3760 Int_t style0 = GetPainter()->GetFillStyle();
3761 Int_t style = style0;
3762 if (option[0] == 's') {
3764 style = 0;
3765 }
3766 if (style) {
3767 if (style > 3000 && style < 4000) {
3768 if (style < 3026) {
3769 // draw stipples with fFillColor foreground
3771 }
3772
3773 if (style >= 3100 && style < 4000) {
3774 Double_t xb[4], yb[4];
3775 xb[0] = x1; xb[1] = x1; xb[2] = x2; xb[3] = x2;
3776 yb[0] = y1; yb[1] = y2; yb[2] = y2; yb[3] = y1;
3777 PaintFillAreaHatches(4, xb, yb, style);
3778 return;
3779 }
3780 //special case for TAttFillCanvas
3781 if (GetPainter()->GetFillColor() == 10) {
3784 GetPainter()->SetFillColor(10);
3785 }
3786 } else if (style >= 4000 && style <= 4100) {
3787 // For style >=4000 we make the window transparent.
3788 // From 4000 to 4100 the window is 100% transparent to 100% opaque
3789
3790 //ignore this style option when this is the canvas itself
3791 if (this == fMother) {
3792 //It's clear, that virtual X checks a style (4000) and will render a hollow rect!
3793 const Style_t oldFillStyle = GetPainter()->GetFillStyle();
3794 if (gVirtualX->InheritsFrom("TGCocoa"))
3795 GetPainter()->SetFillStyle(1000);
3797 if (gVirtualX->InheritsFrom("TGCocoa"))
3798 GetPainter()->SetFillStyle(oldFillStyle);
3799 } else {
3800 //draw background by blitting all bottom pads
3801 int px, py;
3802 XYtoAbsPixel(fX1, fY2, px, py);
3803
3804 if (fMother) {
3806 CopyBackgroundPixmaps(fMother, this, px, py);
3807 }
3808
3809 GetPainter()->SetOpacity(style - 4000);
3810 }
3811 } else if (style >= 1000 && style <= 1999) {
3813 } else {
3815 }
3817 } else {
3819 if (option[0] == 's') GetPainter()->SetFillStyle(style0);
3820 }
3821 }
3822
3823 if (gVirtualPS) {
3824 Int_t style0 = gVirtualPS->GetFillStyle();
3825 if (option[0] == 's') {
3827 } else {
3828 if (style0 >= 3100 && style0 < 4000) {
3829 Double_t xb[4], yb[4];
3830 xb[0] = x1; xb[1] = x1; xb[2] = x2; xb[3] = x2;
3831 yb[0] = y1; yb[1] = y2; yb[2] = y2; yb[3] = y1;
3832 PaintFillAreaHatches(4, xb, yb, style0);
3833 return;
3834 }
3835 }
3836 gVirtualPS->DrawBox(x1, y1, x2, y2);
3837 if (option[0] == 'l') {
3839 gVirtualPS->DrawBox(x1, y1, x2, y2);
3840 }
3841 if (option[0] == 's' || option[0] == 'l') gVirtualPS->SetFillStyle(style0);
3842 }
3843
3844 Modified();
3845}
3846
3847////////////////////////////////////////////////////////////////////////////////
3848/// Copy pixmaps of pads laying below pad "stop" into pad "stop". This
3849/// gives the effect of pad "stop" being transparent.
3850
3852{
3853 if (!start) return;
3854 TObject *obj;
3855 if (!fPrimitives) fPrimitives = new TList;
3856 TIter next(start->GetListOfPrimitives());
3857 while ((obj = next())) {
3858 if (obj->InheritsFrom(TPad::Class())) {
3859 if (obj == stop) break;
3860 ((TPad*)obj)->CopyBackgroundPixmap(x, y);
3861 ((TPad*)obj)->CopyBackgroundPixmaps((TPad*)obj, stop, x, y);
3862 }
3863 }
3864}
3865
3866////////////////////////////////////////////////////////////////////////////////
3867/// Copy pixmap of this pad as background of the current pad.
3868
3870{
3871 int px, py;
3872 XYtoAbsPixel(fX1, fY2, px, py);
3873 if (GetPainter()) GetPainter()->CopyDrawable(GetPixmapID(), px-x, py-y);
3874}
3875
3876////////////////////////////////////////////////////////////////////////////////
3877
3879{
3880 Warning("TPad::PaintFillArea", "Float_t signature is obsolete. Use Double_t signature.");
3881}
3882
3883////////////////////////////////////////////////////////////////////////////////
3884/// Paint fill area in CurrentPad World coordinates.
3885
3887{
3888 if (nn <3) return;
3889 Int_t n=0;
3893 } else {
3894 xmin = fX1; ymin = fY1; xmax = fX2; ymax = fY2;
3895 }
3896
3897 Int_t nc = 2*nn+1;
3898 std::vector<Double_t> x(nc, 0.);
3899 std::vector<Double_t> y(nc, 0.);
3900
3901 n = ClipPolygon(nn, xx, yy, nc, &x.front(), &y.front(),xmin,ymin,xmax,ymax);
3902 if (!n)
3903 return;
3904
3905 // Paint the fill area with hatches
3906 Int_t fillstyle = GetPainter()?GetPainter()->GetFillStyle():1;
3907 if (gPad->IsBatch() && GetPainter() && gVirtualPS) fillstyle = gVirtualPS->GetFillStyle();
3908 if (fillstyle >= 3100 && fillstyle < 4000) {
3909 PaintFillAreaHatches(nn, &x.front(), &y.front(), fillstyle);
3910 return;
3911 }
3912
3913 if (!gPad->IsBatch() && GetPainter())
3914 // invoke the graphics subsystem
3915 GetPainter()->DrawFillArea(n, &x.front(), &y.front());
3916
3917 if (gVirtualPS)
3918 gVirtualPS->DrawPS(-n, &x.front(), &y.front());
3919
3920 Modified();
3921}
3922
3923////////////////////////////////////////////////////////////////////////////////
3924/// Paint fill area in CurrentPad NDC coordinates.
3925
3927{
3928 auto xw = new Double_t[n];
3929 auto yw = new Double_t[n];
3930 for (int i=0; i<n; i++) {
3931 xw[i] = fX1 + x[i]*(fX2 - fX1);
3932 yw[i] = fY1 + y[i]*(fY2 - fY1);
3933 }
3934 PaintFillArea(n, xw, yw, option);
3935 delete [] xw;
3936 delete [] yw;
3937}
3938
3939////////////////////////////////////////////////////////////////////////////////
3940/// This function paints hatched fill area according to the FillStyle value
3941/// The convention for the Hatch is the following:
3942///
3943/// `FillStyle = 3ijk`
3944///
3945/// - i (1-9) : specify the space between each hatch
3946/// 1 = minimum 9 = maximum
3947/// the final spacing is i*GetHatchesSpacing(). The hatches spacing
3948/// is set by SetHatchesSpacing()
3949/// - j (0-9) : specify angle between 0 and 90 degrees
3950/// * 0 = 0
3951/// * 1 = 10
3952/// * 2 = 20
3953/// * 3 = 30
3954/// * 4 = 45
3955/// * 5 = Not drawn
3956/// * 6 = 60
3957/// * 7 = 70
3958/// * 8 = 80
3959/// * 9 = 90
3960/// - k (0-9) : specify angle between 90 and 180 degrees
3961/// * 0 = 180
3962/// * 1 = 170
3963/// * 2 = 160
3964/// * 3 = 150
3965/// * 4 = 135
3966/// * 5 = Not drawn
3967/// * 6 = 120
3968/// * 7 = 110
3969/// * 8 = 100
3970/// * 9 = 90
3971
3973{
3974 static Double_t ang1[10] = { 0., 10., 20., 30., 45.,5., 60., 70., 80., 89.99};
3975 static Double_t ang2[10] = {180.,170.,160.,150.,135.,5.,120.,110.,100., 89.99};
3976
3977 Int_t fasi = FillStyle%1000;
3978 Int_t idSPA = (Int_t)(fasi/100);
3979 Int_t iAng2 = (Int_t)((fasi-100*idSPA)/10);
3980 Int_t iAng1 = fasi%10;
3981 Double_t dy = 0.003*(Double_t)(idSPA)*gStyle->GetHatchesSpacing();
3983 Short_t lws = 0;
3984 Int_t lss = 0;
3985 Int_t lcs = 0;
3986
3987 // Save the current line attributes
3988 if (!gPad->IsBatch() && GetPainter()) {
3989 lws = GetPainter()->GetLineWidth();
3990 lss = GetPainter()->GetLineStyle();
3991 lcs = GetPainter()->GetLineColor();
3992 } else {
3993 if (gVirtualPS) {
3994 lws = gVirtualPS->GetLineWidth();
3995 lss = gVirtualPS->GetLineStyle();
3996 lcs = gVirtualPS->GetLineColor();
3997 }
3998 }
3999
4000 // Change the current line attributes to draw the hatches
4001 if (!gPad->IsBatch() && GetPainter()) {
4005 }
4006 if (gVirtualPS) {
4010 }
4011
4012 // Draw the hatches
4013 if (ang1[iAng1] != 5.) PaintHatches(dy, ang1[iAng1], nn, xx, yy);
4014 if (ang2[iAng2] != 5.) PaintHatches(dy, ang2[iAng2], nn, xx, yy);
4015
4016 // Restore the line attributes
4017 if (!gPad->IsBatch() && GetPainter()) {
4018 GetPainter()->SetLineStyle(lss);
4019 GetPainter()->SetLineWidth(lws);
4020 GetPainter()->SetLineColor(lcs);
4021 }
4022 if (gVirtualPS) {
4026 }
4027}
4028
4029////////////////////////////////////////////////////////////////////////////////
4030/// This routine draw hatches inclined with the
4031/// angle "angle" and spaced of "dy" in normalized device
4032/// coordinates in the surface defined by n,xx,yy.
4033
4035 Int_t nn, Double_t *xx, Double_t *yy)
4036{
4037 Int_t i, i1, i2, nbi, m, inv;
4038 Double_t ratiox, ratioy, ymin, ymax, yrot, ycur;
4039 const Double_t angr = TMath::Pi()*(180.-angle)/180.;
4040 const Double_t epsil = 0.0001;
4041 const Int_t maxnbi = 100;
4042 Double_t xli[maxnbi], xlh[2], ylh[2], xt1, xt2, yt1, yt2;
4043 Double_t ll, x, y, x1, x2, y1, y2, a, b, xi, xip, xin, yi, yip;
4044
4045 Double_t rwxmin = gPad->GetX1();
4046 Double_t rwxmax = gPad->GetX2();
4047 Double_t rwymin = gPad->GetY1();
4048 Double_t rwymax = gPad->GetY2();
4049 ratiox = 1./(rwxmax-rwxmin);
4050 ratioy = 1./(rwymax-rwymin);
4051
4052 Double_t sina = TMath::Sin(angr), sinb;
4053 Double_t cosa = TMath::Cos(angr), cosb;
4054 if (TMath::Abs(cosa) <= epsil) cosa=0.;
4055 if (TMath::Abs(sina) <= epsil) sina=0.;
4056 sinb = -sina;
4057 cosb = cosa;
4058
4059 // Values needed to compute the hatches in TRUE normalized space (NDC)
4060 Int_t iw = (Int_t)gPad->GetWw();
4061 Int_t ih = (Int_t)gPad->GetWh();
4062 Double_t x1p,y1p,x2p,y2p;
4063 gPad->GetPadPar(x1p,y1p,x2p,y2p);
4064 iw = (Int_t)(iw*x2p)-(Int_t)(iw*x1p);
4065 ih = (Int_t)(ih*y2p)-(Int_t)(ih*y1p);
4066 Double_t wndc = TMath::Min(1.,(Double_t)iw/(Double_t)ih);
4067 Double_t hndc = TMath::Min(1.,(Double_t)ih/(Double_t)iw);
4068
4069 // Search ymin and ymax
4070 ymin = 1.;
4071 ymax = 0.;
4072 for (i=1; i<=nn; i++) {
4073 x = wndc*ratiox*(xx[i-1]-rwxmin);
4074 y = hndc*ratioy*(yy[i-1]-rwymin);
4075 yrot = sina*x+cosa*y;
4076 if (yrot > ymax) ymax = yrot;
4077 if (yrot < ymin) ymin = yrot;
4078 }
4079 ymax = (Double_t)((Int_t)(ymax/dy))*dy;
4080
4081 for (ycur=ymax; ycur>=ymin; ycur=ycur-dy) {
4082 nbi = 0;
4083 for (i=2; i<=nn+1; i++) {
4084 i2 = i;
4085 i1 = i-1;
4086 if (i == nn+1) i2=1;
4087 x1 = wndc*ratiox*(xx[i1-1]-rwxmin);
4088 y1 = hndc*ratioy*(yy[i1-1]-rwymin);
4089 x2 = wndc*ratiox*(xx[i2-1]-rwxmin);
4090 y2 = hndc*ratioy*(yy[i2-1]-rwymin);
4091 xt1 = cosa*x1-sina*y1;
4092 yt1 = sina*x1+cosa*y1;
4093 xt2 = cosa*x2-sina*y2;
4094 yt2 = sina*x2+cosa*y2;
4095
4096 // Line segment parallel to oy
4097 if (xt1 == xt2) {
4098 if (yt1 < yt2) {
4099 yi = yt1;
4100 yip = yt2;
4101 } else {
4102 yi = yt2;
4103 yip = yt1;
4104 }
4105 if ((yi <= ycur) && (ycur < yip)) {
4106 nbi++;
4107 if (nbi >= maxnbi) return;
4108 xli[nbi-1] = xt1;
4109 }
4110 continue;
4111 }
4112
4113 // Line segment parallel to ox
4114 if (yt1 == yt2) {
4115 if (yt1 == ycur) {
4116 nbi++;
4117 if (nbi >= maxnbi) return;
4118 xli[nbi-1] = xt1;
4119 nbi++;
4120 if (nbi >= maxnbi) return;
4121 xli[nbi-1] = xt2;
4122 }
4123 continue;
4124 }
4125
4126 // Other line segment
4127 a = (yt1-yt2)/(xt1-xt2);
4128 b = (yt2*xt1-xt2*yt1)/(xt1-xt2);
4129 if (xt1 < xt2) {
4130 xi = xt1;
4131 xip = xt2;
4132 } else {
4133 xi = xt2;
4134 xip = xt1;
4135 }
4136 xin = (ycur-b)/a;
4137 if ((xi <= xin) && (xin < xip) &&
4138 (TMath::Min(yt1,yt2) <= ycur) &&
4139 (ycur < TMath::Max(yt1,yt2))) {
4140 nbi++;
4141 if (nbi >= maxnbi) return;
4142 xli[nbi-1] = xin;
4143 }
4144 }
4145
4146 // Sorting of the x coordinates intersections
4147 inv = 0;
4148 m = nbi-1;
4149L30:
4150 for (i=1; i<=m; i++) {
4151 if (xli[i] < xli[i-1]) {
4152 inv++;
4153 ll = xli[i-1];
4154 xli[i-1] = xli[i];
4155 xli[i] = ll;
4156 }
4157 }
4158 m--;
4159 if (inv == 0) goto L50;
4160 inv = 0;
4161 goto L30;
4162
4163 // Draw the hatches
4164L50:
4165 if (nbi%2 != 0) continue;
4166
4167 for (i=1; i<=nbi; i=i+2) {
4168 // Rotate back the hatches
4169 xlh[0] = cosb*xli[i-1]-sinb*ycur;
4170 ylh[0] = sinb*xli[i-1]+cosb*ycur;
4171 xlh[1] = cosb*xli[i] -sinb*ycur;
4172 ylh[1] = sinb*xli[i] +cosb*ycur;
4173 // Convert hatches' positions from true NDC to WC
4174 xlh[0] = (xlh[0]/wndc)*(rwxmax-rwxmin)+rwxmin;
4175 ylh[0] = (ylh[0]/hndc)*(rwymax-rwymin)+rwymin;
4176 xlh[1] = (xlh[1]/wndc)*(rwxmax-rwxmin)+rwxmin;
4177 ylh[1] = (ylh[1]/hndc)*(rwymax-rwymin)+rwymin;
4178 gPad->PaintLine(xlh[0], ylh[0], xlh[1], ylh[1]);
4179 }
4180 }
4181}
4182
4183////////////////////////////////////////////////////////////////////////////////
4184/// Paint line in CurrentPad World coordinates.
4185
4187{
4188 Double_t x[2], y[2];
4189 x[0] = x1; x[1] = x2; y[0] = y1; y[1] = y2;
4190
4191 //If line is totally clipped, return
4193 if (Clip(x,y,fUxmin,fUymin,fUxmax,fUymax) == 2) return;
4194 } else {
4195 if (Clip(x,y,fX1,fY1,fX2,fY2) == 2) return;
4196 }
4197
4198 if (!gPad->IsBatch() && GetPainter())
4199 GetPainter()->DrawLine(x[0], y[0], x[1], y[1]);
4200
4201 if (gVirtualPS) {
4202 gVirtualPS->DrawPS(2, x, y);
4203 }
4204
4205 Modified();
4206}
4207
4208////////////////////////////////////////////////////////////////////////////////
4209/// Paint line in normalized coordinates.
4210
4212{
4213 static Double_t xw[2], yw[2];
4214 if (!gPad->IsBatch() && GetPainter())
4215 GetPainter()->DrawLineNDC(u1, v1, u2, v2);
4216
4217 if (gVirtualPS) {
4218 xw[0] = fX1 + u1*(fX2 - fX1);
4219 xw[1] = fX1 + u2*(fX2 - fX1);
4220 yw[0] = fY1 + v1*(fY2 - fY1);
4221 yw[1] = fY1 + v2*(fY2 - fY1);
4222 gVirtualPS->DrawPS(2, xw, yw);
4223 }
4224
4225 Modified();
4226}
4227
4228////////////////////////////////////////////////////////////////////////////////
4229/// Paint 3-D line in the CurrentPad.
4230
4232{
4233 if (!fView) return;
4234
4235 // convert from 3-D to 2-D pad coordinate system
4236 Double_t xpad[6];
4237 Double_t temp[3];
4238 Int_t i;
4239 for (i=0;i<3;i++) temp[i] = p1[i];
4240 fView->WCtoNDC(temp, &xpad[0]);
4241 for (i=0;i<3;i++) temp[i] = p2[i];
4242 fView->WCtoNDC(temp, &xpad[3]);
4243 PaintLine(xpad[0],xpad[1],xpad[3],xpad[4]);
4244}
4245
4246////////////////////////////////////////////////////////////////////////////////
4247/// Paint 3-D line in the CurrentPad.
4248
4250{
4251 //take into account perspective view
4252 if (!fView) return;
4253 // convert from 3-D to 2-D pad coordinate system
4254 Double_t xpad[6];
4255 Double_t temp[3];
4256 Int_t i;
4257 for (i=0;i<3;i++) temp[i] = p1[i];
4258 fView->WCtoNDC(temp, &xpad[0]);
4259 for (i=0;i<3;i++) temp[i] = p2[i];
4260 fView->WCtoNDC(temp, &xpad[3]);
4261 PaintLine(xpad[0],xpad[1],xpad[3],xpad[4]);
4262}
4263
4264////////////////////////////////////////////////////////////////////////////////
4265/// Paint polyline in CurrentPad World coordinates.
4266
4268{
4269 if (n < 2) return;
4270
4274 } else {
4275 xmin = fX1; ymin = fY1; xmax = fX2; ymax = fY2;
4276 }
4277 Int_t i, i1=-1,np=1;
4278 for (i=0; i<n-1; i++) {
4279 Double_t x1=x[i];
4280 Double_t y1=y[i];
4281 Double_t x2=x[i+1];
4282 Double_t y2=y[i+1];
4283 Int_t iclip = Clip(&x[i],&y[i],xmin,ymin,xmax,ymax);
4284 if (iclip == 2) {
4285 i1 = -1;
4286 continue;
4287 }
4288 np++;
4289 if (i1 < 0) i1 = i;
4290 if (iclip == 0 && i < n-2) continue;
4291 if (!gPad->IsBatch() && GetPainter())
4292 GetPainter()->DrawPolyLine(np, &x[i1], &y[i1]);
4293 if (gVirtualPS) {
4294 gVirtualPS->DrawPS(np, &x[i1], &y[i1]);
4295 }
4296 if (iclip) {
4297 x[i] = x1;
4298 y[i] = y1;
4299 x[i+1] = x2;
4300 y[i+1] = y2;
4301 }
4302 i1 = -1;
4303 np = 1;
4304 }
4305
4306 Modified();
4307}
4308
4309////////////////////////////////////////////////////////////////////////////////
4310/// Paint polyline in CurrentPad World coordinates.
4311///
4312/// If option[0] == 'C' no clipping
4313
4315{
4316 if (n < 2) return;
4317
4319 Bool_t mustClip = kTRUE;
4322 } else {
4323 xmin = fX1; ymin = fY1; xmax = fX2; ymax = fY2;
4324 if (option && (option[0] == 'C')) mustClip = kFALSE;
4325 }
4326
4327 Int_t i, i1=-1, np=1, iclip=0;
4328
4329 for (i=0; i < n-1; i++) {
4330 Double_t x1=x[i];
4331 Double_t y1=y[i];
4332 Double_t x2=x[i+1];
4333 Double_t y2=y[i+1];
4334 if (mustClip) {
4335 iclip = Clip(&x[i],&y[i],xmin,ymin,xmax,ymax);
4336 if (iclip == 2) {
4337 i1 = -1;
4338 continue;
4339 }
4340 }
4341 np++;
4342 if (i1 < 0) i1 = i;
4343 if (iclip == 0 && i < n-2) continue;
4344 if (!gPad->IsBatch() && GetPainter())
4345 GetPainter()->DrawPolyLine(np, &x[i1], &y[i1]);
4346 if (gVirtualPS) {
4347 gVirtualPS->DrawPS(np, &x[i1], &y[i1]);
4348 }
4349 if (iclip) {
4350 x[i] = x1;
4351 y[i] = y1;
4352 x[i+1] = x2;
4353 y[i+1] = y2;
4354 }
4355 i1 = -1;
4356 np = 1;
4357 }
4358
4359 Modified();
4360}
4361
4362////////////////////////////////////////////////////////////////////////////////
4363/// Paint polyline in CurrentPad NDC coordinates.
4364
4366{
4367 if (n <=0) return;
4368
4369 if (!gPad->IsBatch() && GetPainter())
4371
4372 if (gVirtualPS) {
4373 Double_t *xw = new Double_t[n];
4374 Double_t *yw = new Double_t[n];
4375 for (Int_t i=0; i<n; i++) {
4376 xw[i] = fX1 + x[i]*(fX2 - fX1);
4377 yw[i] = fY1 + y[i]*(fY2 - fY1);
4378 }
4379 gVirtualPS->DrawPS(n, xw, yw);
4380 delete [] xw;
4381 delete [] yw;
4382 }
4383 Modified();
4384}
4385
4386////////////////////////////////////////////////////////////////////////////////
4387/// Paint 3-D polyline in the CurrentPad.
4388
4390{
4391 if (!fView) return;
4392
4393 // Loop on each individual line
4394 for (Int_t i = 1; i < n; i++)
4395 PaintLine3D(&p[3*i-3], &p[3*i]);
4396
4397 Modified();
4398}
4399
4400////////////////////////////////////////////////////////////////////////////////
4401/// Paint polymarker in CurrentPad World coordinates.
4402
4404{
4405 Int_t n = TMath::Abs(nn);
4407 if (nn > 0 || TestBit(TGraph::kClipFrame)) {
4409 } else {
4410 xmin = fX1; ymin = fY1; xmax = fX2; ymax = fY2;
4411 }
4412 Int_t i,i1=-1,np=0;
4413 for (i=0; i<n; i++) {
4414 if (x[i] >= xmin && x[i] <= xmax && y[i] >= ymin && y[i] <= ymax) {
4415 np++;
4416 if (i1 < 0) i1 = i;
4417 if (i < n-1) continue;
4418 }
4419 if (np == 0) continue;
4420 if (!gPad->IsBatch() && GetPainter())
4421 GetPainter()->DrawPolyMarker(np, &x[i1], &y[i1]);
4422 if (gVirtualPS) {
4423 gVirtualPS->DrawPolyMarker(np, &x[i1], &y[i1]);
4424 }
4425 i1 = -1;
4426 np = 0;
4427 }
4428 Modified();
4429}
4430
4431////////////////////////////////////////////////////////////////////////////////
4432/// Paint polymarker in CurrentPad World coordinates.
4433
4435{
4436 Int_t n = TMath::Abs(nn);
4438 if (nn > 0 || TestBit(TGraph::kClipFrame)) {
4440 } else {
4441 xmin = fX1; ymin = fY1; xmax = fX2; ymax = fY2;
4442 }
4443 Int_t i,i1=-1,np=0;
4444 for (i=0; i<n; i++) {
4445 if (x[i] >= xmin && x[i] <= xmax && y[i] >= ymin && y[i] <= ymax) {
4446 np++;
4447 if (i1 < 0) i1 = i;
4448 if (i < n-1) continue;
4449 }
4450 if (np == 0) continue;
4451 if (!gPad->IsBatch() && GetPainter())
4452 GetPainter()->DrawPolyMarker(np, &x[i1], &y[i1]);
4453 if (gVirtualPS) {
4454 gVirtualPS->DrawPolyMarker(np, &x[i1], &y[i1]);
4455 }
4456 i1 = -1;
4457 np = 0;
4458 }
4459 Modified();
4460}
4461
4462////////////////////////////////////////////////////////////////////////////////
4463/// Paint text in CurrentPad World coordinates.
4464
4466{
4467 Modified();
4468
4469 if (!gPad->IsBatch() && GetPainter())
4471
4472 if (gVirtualPS) gVirtualPS->Text(x, y, text);
4473}
4474
4475////////////////////////////////////////////////////////////////////////////////
4476/// Paint text in CurrentPad World coordinates.
4477
4478void TPad::PaintText(Double_t x, Double_t y, const wchar_t *text)
4479{
4480 Modified();
4481
4482 if (!gPad->IsBatch() && GetPainter())
4484
4485 if (gVirtualPS) gVirtualPS->Text(x, y, text);
4486}
4487
4488////////////////////////////////////////////////////////////////////////////////
4489/// Paint text in CurrentPad NDC coordinates.
4490
4492{
4493 Modified();
4494
4495 if (!gPad->IsBatch() && GetPainter())
4497
4498 if (gVirtualPS) {
4499 Double_t x = fX1 + u*(fX2 - fX1);
4500 Double_t y = fY1 + v*(fY2 - fY1);
4501 gVirtualPS->Text(x, y, text);
4502 }
4503}
4504
4505////////////////////////////////////////////////////////////////////////////////
4506/// Paint text in CurrentPad NDC coordinates.
4507
4509{
4510 Modified();
4511
4512 if (!gPad->IsBatch() && GetPainter())
4514
4515 if (gVirtualPS) {
4516 Double_t x = fX1 + u*(fX2 - fX1);
4517 Double_t y = fY1 + v*(fY2 - fY1);
4518 gVirtualPS->Text(x, y, text);
4519 }
4520}
4521
4522////////////////////////////////////////////////////////////////////////////////
4523/// Search for an object at pixel position px,py.
4524///
4525/// Check if point is in this pad.
4526///
4527/// If yes, check if it is in one of the sub-pads
4528///
4529/// If found in the pad, compute closest distance of approach
4530/// to each primitive.
4531///
4532/// If one distance of approach is found to be within the limit Distancemaximum
4533/// the corresponding primitive is selected and the routine returns.
4534
4536{
4537 //the two following statements are necessary under NT (multithreaded)
4538 //when a TCanvas object is being created and a thread calling TPad::Pick
4539 //before the TPad constructor has completed in the other thread
4540 if (gPad == 0) return 0; //Andy Haas
4541 if (GetListOfPrimitives() == 0) return 0; //Andy Haas
4542
4543 Int_t dist;
4544 // Search if point is in pad itself
4545 Double_t x = AbsPixeltoX(px);
4546 Double_t y = AbsPixeltoY(py);
4547 if (this != gPad->GetCanvas()) {
4548 if (!((x >= fX1 && x <= fX2) && (y >= fY1 && y <= fY2))) return 0;
4549 }
4550
4551 // search for a primitive in this pad or its sub-pads
4552 static