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