Logo ROOT   6.30.04
Reference Guide
 All Namespaces Files Pages
TCanvas.cxx
Go to the documentation of this file.
1 // @(#)root/gpad:$Id$
2 // Author: Rene Brun 12/12/94
3 
4 /*************************************************************************
5  * Copyright (C) 1995-2000, Rene Brun and Fons Rademakers. *
6  * All rights reserved. *
7  * *
8  * For the licensing terms see $ROOTSYS/LICENSE. *
9  * For the list of contributors see $ROOTSYS/README/CREDITS. *
10  *************************************************************************/
11 
12 #include <string.h>
13 #include <stdlib.h>
14 
15 #include "Riostream.h"
16 #include "TROOT.h"
17 #include "TCanvas.h"
18 #include "TClass.h"
19 #include "TStyle.h"
20 #include "TText.h"
21 #include "TBox.h"
22 #include "TCanvasImp.h"
23 #include "TDialogCanvas.h"
24 #include "TGuiFactory.h"
25 #include "TEnv.h"
26 #include "TError.h"
27 #include "TContextMenu.h"
28 #include "TControlBar.h"
29 #include "TInterpreter.h"
30 #include "TApplication.h"
31 #include "TColor.h"
32 #include "TVirtualPadEditor.h"
33 #include "TVirtualViewer3D.h"
34 #include "TPadPainter.h"
35 #include "TVirtualGL.h"
36 #include "TVirtualPS.h"
37 #include "TAxis.h"
38 #include "TH1.h"
39 #include "TGraph.h"
40 #include "TView.h"
41 
42 #include "TVirtualMutex.h"
43 
44 class TCanvasInit {
45 public:
46  TCanvasInit() { TApplication::NeedGraphicsLibs(); }
47 };
48 static TCanvasInit gCanvasInit;
49 
50 
51 //*-*x16 macros/layout_canvas
52 
53 Bool_t TCanvas::fgIsFolder = kFALSE;
54 
55 const Size_t kDefaultCanvasSize = 20;
56 
57 ClassImpQ(TCanvas)
58 
59 
60 /** \class TCanvas
61 \ingroup gpad
62 
63 The Canvas class.
64 
65 A Canvas is an area mapped to a window directly under the control of the display
66 manager. A ROOT session may have several canvases open at any given time.
67 
68 A Canvas may be subdivided into independent graphical areas: the __Pads__.
69 A canvas has a default pad which has the name of the canvas itself.
70 An example of a Canvas layout is sketched in the picture below.
71 
72 \image html gpad_canvas.png
73 
74 This canvas contains two pads named P1 and P2. Both Canvas, P1 and P2 can be
75 moved, grown, shrunk using the normal rules of the Display manager.
76 
77 Once objects have been drawn in a canvas, they can be edited/moved by pointing
78 directly to them. The cursor shape is changed to suggest the type of action that
79 one can do on this object. Clicking with the right mouse button on an object
80 pops-up a contextmenu with a complete list of actions possible on this object.
81 
82 A graphical editor may be started from the canvas "View" menu under the menu
83 entry "Toolbar".
84 
85 An interactive HELP is available by clicking on the HELP button at the top right
86 of the canvas. It gives a short explanation about the canvas' menus.
87 
88 A canvas may be automatically divided into pads via `TPad::Divide`.
89 
90 At creation time, no matter if in interactive or batch mode, the canvas size
91 defines the size of the canvas window (including the size of the window
92 manager's decoration). To define precisely the graphics area size of a canvas in
93 the interactive mode, the following four lines of code should be used:
94 ~~~ {.cpp}
95  {
96  Double_t w = 600;
97  Double_t h = 600;
98  auto c = new TCanvas("c", "c", w, h);
99  c->SetWindowSize(w + (w - c->GetWw()), h + (h - c->GetWh()));
100  }
101 ~~~
102 and in the batch mode simply do:
103 ~~~ {.cpp}
104  c->SetCanvasSize(w,h);
105 ~~~
106 
107 If the canvas size this exceed the window size, scroll bars will be added to the canvas
108 This allows to display very large canvases (even bigger than the screen size). The
109 Following example shows how to proceed.
110 ~~~ {.cpp}
111  {
112  auto c = new TCanvas("c","c");
113  c->SetCanvasSize(1500, 1500);
114  c->SetWindowSize(500, 500);
115  }
116 ~~~
117 */
118 
119 ////////////////////////////////////////////////////////////////////////////////
120 /// Canvas default constructor.
121 
122 TCanvas::TCanvas(Bool_t build) : TPad(), fDoubleBuffer(0)
123 {
124  fPainter = 0;
125  fWindowTopX = 0;
126  fWindowTopY = 0;
127  fWindowWidth = 0;
128  fWindowHeight = 0;
129  fCw = 0;
130  fCh = 0;
131  fXsizeUser = 0;
132  fYsizeUser = 0;
133  fXsizeReal = kDefaultCanvasSize;
134  fYsizeReal = kDefaultCanvasSize;
135  fHighLightColor = gEnv->GetValue("Canvas.HighLightColor", kRed);
136  fEvent = -1;
137  fEventX = -1;
138  fEventY = -1;
139  fSelectedX = 0;
140  fSelectedY = 0;
141  fRetained = kTRUE;
142  fDrawn = kFALSE;
143  fSelected = 0;
144  fClickSelected = 0;
145  fSelectedPad = 0;
146  fClickSelectedPad = 0;
147  fPadSave = 0;
148  fCanvasImp = 0;
149  fContextMenu = 0;
150 
151  fUseGL = gStyle->GetCanvasPreferGL();
152 
153  if (!build || TClass::IsCallingNew() != TClass::kRealNew) {
154  Constructor();
155  } else {
156  const char *defcanvas = gROOT->GetDefCanvasName();
157  char *cdef;
158 
159  auto lc = (TList*)gROOT->GetListOfCanvases();
160  if (lc->FindObject(defcanvas)) {
161  Int_t n = lc->GetSize()+1;
162  while (lc->FindObject(Form("%s_n%d",defcanvas,n))) n++;
163  cdef = StrDup(Form("%s_n%d",defcanvas,n));
164  } else {
165  cdef = StrDup(Form("%s",defcanvas));
166  }
167  Constructor(cdef, cdef, 1);
168  delete [] cdef;
169  }
170 }
171 
172 ////////////////////////////////////////////////////////////////////////////////
173 /// Canvas default constructor
174 
175 void TCanvas::Constructor()
176 {
177  if (gThreadXAR) {
178  void *arr[2];
179  arr[1] = this;
180  if ((*gThreadXAR)("CANV", 2, arr, 0)) return;
181  }
182 
183  fCanvas = 0;
184  fCanvasID = -1;
185  fCanvasImp = 0;
186  fBatch = kTRUE;
187  fUpdating = kFALSE;
188 
189  fContextMenu = 0;
190  fSelected = 0;
191  fClickSelected = 0;
192  fSelectedPad = 0;
193  fClickSelectedPad = 0;
194  fPadSave = 0;
195  SetBit(kAutoExec);
196  SetBit(kShowEditor);
197  SetBit(kShowToolBar);
198 }
199 
200 ////////////////////////////////////////////////////////////////////////////////
201 /// Create an embedded canvas, i.e. a canvas that is in a TGCanvas widget
202 /// which is placed in a TGFrame. This ctor is only called via the
203 /// TRootEmbeddedCanvas class.
204 ///
205 /// If "name" starts with "gl" the canvas is ready to receive GL output.
206 
207 TCanvas::TCanvas(const char *name, Int_t ww, Int_t wh, Int_t winid) : TPad(), fDoubleBuffer(0)
208 {
209  fCanvasImp = 0;
210  fPainter = 0;
211  Init();
212 
213  fCanvasID = winid;
214  fWindowTopX = 0;
215  fWindowTopY = 0;
216  fWindowWidth = ww;
217  fWindowHeight = wh;
218  fCw = ww + 4;
219  fCh = wh +28;
220  fBatch = kFALSE;
221  fUpdating = kFALSE;
222 
223  //This is a very special ctor. A window exists already!
224  //Can create painter now.
225  fUseGL = gStyle->GetCanvasPreferGL();
226 
227  if (fUseGL) {
228  fGLDevice = gGLManager->CreateGLContext(winid);
229  if (fGLDevice == -1)
230  fUseGL = kFALSE;
231  }
232 
233  fCanvasImp = gBatchGuiFactory->CreateCanvasImp(this, name, fCw, fCh);
234  if (!fCanvasImp) return;
235 
236  CreatePainter();
237  SetName(name);
238  Build();
239 }
240 
241 ////////////////////////////////////////////////////////////////////////////////
242 /// Create a new canvas with a predefined size form.
243 /// If form < 0 the menubar is not shown.
244 ///
245 /// - form = 1 700x500 at 10,10 (set by TStyle::SetCanvasDefH,W,X,Y)
246 /// - form = 2 500x500 at 20,20
247 /// - form = 3 500x500 at 30,30
248 /// - form = 4 500x500 at 40,40
249 /// - form = 5 500x500 at 50,50
250 ///
251 /// If "name" starts with "gl" the canvas is ready to receive GL output.
252 
253 TCanvas::TCanvas(const char *name, const char *title, Int_t form) : TPad(), fDoubleBuffer(0)
254 {
255  fPainter = 0;
256  fUseGL = gStyle->GetCanvasPreferGL();
257 
258  Constructor(name, title, form);
259 }
260 
261 ////////////////////////////////////////////////////////////////////////////////
262 /// Create a new canvas with a predefined size form.
263 /// If form < 0 the menubar is not shown.
264 ///
265 /// - form = 1 700x500 at 10,10 (set by TStyle::SetCanvasDefH,W,X,Y)
266 /// - form = 2 500x500 at 20,20
267 /// - form = 3 500x500 at 30,30
268 /// - form = 4 500x500 at 40,40
269 /// - form = 5 500x500 at 50,50
270 
271 void TCanvas::Constructor(const char *name, const char *title, Int_t form)
272 {
273  if (gThreadXAR) {
274  void *arr[6];
275  static Int_t ww = 500;
276  static Int_t wh = 500;
277  arr[1] = this; arr[2] = (void*)name; arr[3] = (void*)title; arr[4] =&ww; arr[5] = &wh;
278  if ((*gThreadXAR)("CANV", 6, arr, 0)) return;
279  }
280 
281  Init();
282  SetBit(kMenuBar,1);
283  if (form < 0) {
284  form = -form;
285  SetBit(kMenuBar,0);
286  }
287 
288  fCanvas = this;
289 
290  fCanvasID = -1;
291  TCanvas *old = (TCanvas*)gROOT->GetListOfCanvases()->FindObject(name);
292  if (old && old->IsOnHeap()) {
293  Warning("Constructor","Deleting canvas with same name: %s",name);
294  delete old;
295  }
296  if (gROOT->IsBatch()) { //We are in Batch mode
297  fWindowTopX = fWindowTopY = 0;
298  if (form == 1) {
299  fWindowWidth = gStyle->GetCanvasDefW();
300  fWindowHeight = gStyle->GetCanvasDefH();
301  } else {
302  fWindowWidth = 500;
303  fWindowHeight = 500;
304  }
305  fCw = fWindowWidth;
306  fCh = fWindowHeight;
307  fCanvasImp = gBatchGuiFactory->CreateCanvasImp(this, name, fCw, fCh);
308  if (!fCanvasImp) return;
309  fBatch = kTRUE;
310  } else { //normal mode with a screen window
311  Float_t cx = gStyle->GetScreenFactor();
312  if (form < 1 || form > 5) form = 1;
313  if (form == 1) {
314  UInt_t uh = UInt_t(cx*gStyle->GetCanvasDefH());
315  UInt_t uw = UInt_t(cx*gStyle->GetCanvasDefW());
316  Int_t ux = Int_t(cx*gStyle->GetCanvasDefX());
317  Int_t uy = Int_t(cx*gStyle->GetCanvasDefY());
318  fCanvasImp = gGuiFactory->CreateCanvasImp(this, name, ux, uy, uw, uh);
319  }
320  fCw = 500;
321  fCh = 500;
322  if (form == 2) fCanvasImp = gGuiFactory->CreateCanvasImp(this, name, 20, 20, UInt_t(cx*500), UInt_t(cx*500));
323  if (form == 3) fCanvasImp = gGuiFactory->CreateCanvasImp(this, name, 30, 30, UInt_t(cx*500), UInt_t(cx*500));
324  if (form == 4) fCanvasImp = gGuiFactory->CreateCanvasImp(this, name, 40, 40, UInt_t(cx*500), UInt_t(cx*500));
325  if (form == 5) fCanvasImp = gGuiFactory->CreateCanvasImp(this, name, 50, 50, UInt_t(cx*500), UInt_t(cx*500));
326  if (!fCanvasImp) return;
327 
328  if (!gROOT->IsBatch() && fCanvasID == -1)
329  fCanvasID = fCanvasImp->InitWindow();
330 
331  fCanvasImp->ShowMenuBar(TestBit(kMenuBar));
332  fBatch = kFALSE;
333  }
334 
335  CreatePainter();
336 
337  SetName(name);
338  SetTitle(title); // requires fCanvasImp set
339  Build();
340 
341  // Popup canvas
342  fCanvasImp->Show();
343 }
344 
345 ////////////////////////////////////////////////////////////////////////////////
346 /// Create a new canvas at a random position.
347 ///
348 /// \param[in] name canvas name
349 /// \param[in] title canvas title
350 /// \param[in] ww is the canvas size in pixels along X
351 /// (if ww < 0 the menubar is not shown)
352 /// \param[in] wh is the canvas size in pixels along Y
353 ///
354 /// If "name" starts with "gl" the canvas is ready to receive GL output.
355 
356 TCanvas::TCanvas(const char *name, const char *title, Int_t ww, Int_t wh) : TPad(), fDoubleBuffer(0)
357 {
358  fPainter = 0;
359  fUseGL = gStyle->GetCanvasPreferGL();
360 
361  Constructor(name, title, ww, wh);
362 }
363 
364 ////////////////////////////////////////////////////////////////////////////////
365 /// Create a new canvas at a random position.
366 ///
367 /// \param[in] name canvas name
368 /// \param[in] title canvas title
369 /// \param[in] ww is the canvas size in pixels along X
370 /// (if ww < 0 the menubar is not shown)
371 /// \param[in] wh is the canvas size in pixels along Y
372 
373 void TCanvas::Constructor(const char *name, const char *title, Int_t ww, Int_t wh)
374 {
375  if (gThreadXAR) {
376  void *arr[6];
377  arr[1] = this; arr[2] = (void*)name; arr[3] = (void*)title; arr[4] =&ww; arr[5] = &wh;
378  if ((*gThreadXAR)("CANV", 6, arr, 0)) return;
379  }
380 
381  Init();
382  SetBit(kMenuBar,1);
383  if (ww < 0) {
384  ww = -ww;
385  SetBit(kMenuBar,0);
386  }
387  fCw = ww;
388  fCh = wh;
389  fCanvasID = -1;
390  TCanvas *old = (TCanvas*)gROOT->GetListOfCanvases()->FindObject(name);
391  if (old && old->IsOnHeap()) {
392  Warning("Constructor","Deleting canvas with same name: %s",name);
393  delete old;
394  }
395  if (gROOT->IsBatch()) { //We are in Batch mode
396  fWindowTopX = fWindowTopY = 0;
397  fWindowWidth = ww;
398  fWindowHeight = wh;
399  fCw = ww;
400  fCh = wh;
401  fCanvasImp = gBatchGuiFactory->CreateCanvasImp(this, name, fCw, fCh);
402  if (!fCanvasImp) return;
403  fBatch = kTRUE;
404  } else {
405  Float_t cx = gStyle->GetScreenFactor();
406  fCanvasImp = gGuiFactory->CreateCanvasImp(this, name, UInt_t(cx*ww), UInt_t(cx*wh));
407  if (!fCanvasImp) return;
408 
409  if (!gROOT->IsBatch() && fCanvasID == -1)
410  fCanvasID = fCanvasImp->InitWindow();
411 
412  fCanvasImp->ShowMenuBar(TestBit(kMenuBar));
413  fBatch = kFALSE;
414  }
415 
416  CreatePainter();
417 
418  SetName(name);
419  SetTitle(title); // requires fCanvasImp set
420  Build();
421 
422  // Popup canvas
423  fCanvasImp->Show();
424 }
425 
426 ////////////////////////////////////////////////////////////////////////////////
427 /// Create a new canvas.
428 ///
429 /// \param[in] name canvas name
430 /// \param[in] title canvas title
431 /// \param[in] wtopx,wtopy are the pixel coordinates of the top left corner of
432 /// the canvas (if wtopx < 0) the menubar is not shown)
433 /// \param[in] ww is the canvas size in pixels along X
434 /// \param[in] wh is the canvas size in pixels along Y
435 ///
436 /// If "name" starts with "gl" the canvas is ready to receive GL output.
437 
438 TCanvas::TCanvas(const char *name, const char *title, Int_t wtopx, Int_t wtopy, Int_t ww, Int_t wh)
439  : TPad(), fDoubleBuffer(0)
440 {
441  fPainter = 0;
442  fUseGL = gStyle->GetCanvasPreferGL();
443 
444  Constructor(name, title, wtopx, wtopy, ww, wh);
445 }
446 
447 ////////////////////////////////////////////////////////////////////////////////
448 /// Create a new canvas.
449 ///
450 /// \param[in] name canvas name
451 /// \param[in] title canvas title
452 /// \param[in] wtopx,wtopy are the pixel coordinates of the top left corner of
453 /// the canvas (if wtopx < 0) the menubar is not shown)
454 /// \param[in] ww is the canvas size in pixels along X
455 /// \param[in] wh is the canvas size in pixels along Y
456 
457 void TCanvas::Constructor(const char *name, const char *title, Int_t wtopx,
458  Int_t wtopy, Int_t ww, Int_t wh)
459 {
460  if (gThreadXAR) {
461  void *arr[8];
462  arr[1] = this; arr[2] = (void*)name; arr[3] = (void*)title;
463  arr[4] = &wtopx; arr[5] = &wtopy; arr[6] = &ww; arr[7] = &wh;
464  if ((*gThreadXAR)("CANV", 8, arr, 0)) return;
465  }
466 
467  Init();
468  SetBit(kMenuBar,1);
469  if (wtopx < 0) {
470  wtopx = -wtopx;
471  SetBit(kMenuBar,0);
472  }
473  fCw = ww;
474  fCh = wh;
475  fCanvasID = -1;
476  TCanvas *old = (TCanvas*)gROOT->GetListOfCanvases()->FindObject(name);
477  if (old && old->IsOnHeap()) {
478  Warning("Constructor","Deleting canvas with same name: %s",name);
479  delete old;
480  }
481  if (gROOT->IsBatch()) { //We are in Batch mode
482  fWindowTopX = fWindowTopY = 0;
483  fWindowWidth = ww;
484  fWindowHeight = wh;
485  fCw = ww;
486  fCh = wh;
487  fCanvasImp = gBatchGuiFactory->CreateCanvasImp(this, name, fCw, fCh);
488  if (!fCanvasImp) return;
489  fBatch = kTRUE;
490  } else { //normal mode with a screen window
491  Float_t cx = gStyle->GetScreenFactor();
492  fCanvasImp = gGuiFactory->CreateCanvasImp(this, name, Int_t(cx*wtopx), Int_t(cx*wtopy), UInt_t(cx*ww), UInt_t(cx*wh));
493  if (!fCanvasImp) return;
494 
495  if (!gROOT->IsBatch() && fCanvasID == -1)
496  fCanvasID = fCanvasImp->InitWindow();
497 
498  fCanvasImp->ShowMenuBar(TestBit(kMenuBar));
499  fBatch = kFALSE;
500  }
501 
502  CreatePainter();
503 
504  SetName(name);
505  SetTitle(title); // requires fCanvasImp set
506  Build();
507 
508  // Popup canvas
509  fCanvasImp->Show();
510 }
511 
512 ////////////////////////////////////////////////////////////////////////////////
513 /// Initialize the TCanvas members. Called by all constructors.
514 
515 void TCanvas::Init()
516 {
517  // Make sure the application environment exists. It is need for graphics
518  // (colors are initialized in the TApplication ctor).
519  if (!gApplication)
520  TApplication::CreateApplication();
521 
522  // Load and initialize graphics libraries if
523  // TApplication::NeedGraphicsLibs() has been called by a
524  // library static initializer.
525  if (gApplication)
526  gApplication->InitializeGraphics();
527 
528  // Get some default from .rootrc. Used in fCanvasImp->InitWindow().
529  fHighLightColor = gEnv->GetValue("Canvas.HighLightColor", kRed);
530  SetBit(kMoveOpaque, gEnv->GetValue("Canvas.MoveOpaque", 0));
531  SetBit(kResizeOpaque, gEnv->GetValue("Canvas.ResizeOpaque", 0));
532  if (gEnv->GetValue("Canvas.ShowEventStatus", kFALSE)) SetBit(kShowEventStatus);
533  if (gEnv->GetValue("Canvas.ShowToolTips", kFALSE)) SetBit(kShowToolTips);
534  if (gEnv->GetValue("Canvas.ShowToolBar", kFALSE)) SetBit(kShowToolBar);
535  if (gEnv->GetValue("Canvas.ShowEditor", kFALSE)) SetBit(kShowEditor);
536  if (gEnv->GetValue("Canvas.AutoExec", kTRUE)) SetBit(kAutoExec);
537 
538  // Fill canvas ROOT data structure
539  fXsizeUser = 0;
540  fYsizeUser = 0;
541  fXsizeReal = kDefaultCanvasSize;
542  fYsizeReal = kDefaultCanvasSize;
543 
544  fDISPLAY = "$DISPLAY";
545  fUpdating = kFALSE;
546  fRetained = kTRUE;
547  fSelected = 0;
548  fClickSelected = 0;
549  fSelectedX = 0;
550  fSelectedY = 0;
551  fSelectedPad = 0;
552  fClickSelectedPad= 0;
553  fPadSave = 0;
554  fEvent = -1;
555  fEventX = -1;
556  fEventY = -1;
557  fContextMenu = 0;
558  fDrawn = kFALSE;
559 }
560 
561 ////////////////////////////////////////////////////////////////////////////////
562 /// Build a canvas. Called by all constructors.
563 
564 void TCanvas::Build()
565 {
566  // Get window identifier
567  if (fCanvasID == -1 && fCanvasImp)
568  fCanvasID = fCanvasImp->InitWindow();
569  if (fCanvasID == -1) return;
570 
571  if (fCw !=0 && fCh !=0) {
572  if (fCw < fCh) fXsizeReal = fYsizeReal*Float_t(fCw)/Float_t(fCh);
573  else fYsizeReal = fXsizeReal*Float_t(fCh)/Float_t(fCw);
574  }
575 
576  // Set Pad parameters
577  gPad = this;
578  fCanvas = this;
579  fMother = (TPad*)gPad;
580 
581  if (IsBatch()) {
582  // Make sure that batch interactive canvas sizes are the same
583  fCw -= 4;
584  fCh -= 28;
585  } else if (IsWeb()) {
586  // mark canvas as batch - avoid virtualx in many places
587  SetBatch(kTRUE);
588  } else {
589  //normal mode with a screen window
590  // Set default physical canvas attributes
591  //Should be done via gVirtualX, not via fPainter (at least now). No changes here.
592  gVirtualX->SelectWindow(fCanvasID);
593  gVirtualX->SetFillColor(1); //Set color index for fill area
594  gVirtualX->SetLineColor(1); //Set color index for lines
595  gVirtualX->SetMarkerColor(1); //Set color index for markers
596  gVirtualX->SetTextColor(1); //Set color index for text
597  // Clear workstation
598  gVirtualX->ClearWindow();
599 
600  // Set Double Buffer on by default
601  SetDoubleBuffer(1);
602 
603  // Get effective window parameters (with borders and menubar)
604  fCanvasImp->GetWindowGeometry(fWindowTopX, fWindowTopY,
605  fWindowWidth, fWindowHeight);
606 
607  // Get effective canvas parameters without borders
608  Int_t dum1, dum2;
609  gVirtualX->GetGeometry(fCanvasID, dum1, dum2, fCw, fCh);
610 
611  fContextMenu = new TContextMenu("ContextMenu");
612  }
613 
614  gROOT->GetListOfCanvases()->Add(this);
615 
616  if (!fPrimitives) {
617  fPrimitives = new TList;
618  SetFillColor(gStyle->GetCanvasColor());
619  SetFillStyle(1001);
620  SetGrid(gStyle->GetPadGridX(),gStyle->GetPadGridY());
621  SetTicks(gStyle->GetPadTickX(),gStyle->GetPadTickY());
622  SetLogx(gStyle->GetOptLogx());
623  SetLogy(gStyle->GetOptLogy());
624  SetLogz(gStyle->GetOptLogz());
625  SetBottomMargin(gStyle->GetPadBottomMargin());
626  SetTopMargin(gStyle->GetPadTopMargin());
627  SetLeftMargin(gStyle->GetPadLeftMargin());
628  SetRightMargin(gStyle->GetPadRightMargin());
629  SetBorderSize(gStyle->GetCanvasBorderSize());
630  SetBorderMode(gStyle->GetCanvasBorderMode());
631  fBorderMode=gStyle->GetCanvasBorderMode(); // do not call SetBorderMode (function redefined in TCanvas)
632  SetPad(0, 0, 1, 1);
633  Range(0, 0, 1, 1); //pad range is set by default to [0,1] in x and y
634 
635  TVirtualPadPainter *vpp = GetCanvasPainter();
636  if (vpp) vpp->SelectDrawable(fPixmapID);//gVirtualX->SelectPixmap(fPixmapID); //pixmap must be selected
637  PaintBorder(GetFillColor(), kTRUE); //paint background
638  }
639 
640  // transient canvases have typically no menubar and should not get
641  // by default the event status bar (if set by default)
642  if (TestBit(kMenuBar) && fCanvasImp) {
643  if (TestBit(kShowEventStatus)) fCanvasImp->ShowStatusBar(kTRUE);
644  // ... and toolbar + editor
645  if (TestBit(kShowToolBar)) fCanvasImp->ShowToolBar(kTRUE);
646  if (TestBit(kShowEditor)) fCanvasImp->ShowEditor(kTRUE);
647  if (TestBit(kShowToolTips)) fCanvasImp->ShowToolTips(kTRUE);
648  }
649 }
650 
651 ////////////////////////////////////////////////////////////////////////////////
652 /// Canvas destructor
653 
654 TCanvas::~TCanvas()
655 {
656  Destructor();
657 }
658 
659 ////////////////////////////////////////////////////////////////////////////////
660 /// Browse.
661 
662 void TCanvas::Browse(TBrowser *b)
663 {
664  Draw();
665  cd();
666  if (fgIsFolder) fPrimitives->Browse(b);
667 }
668 
669 ////////////////////////////////////////////////////////////////////////////////
670 /// Actual canvas destructor.
671 
672 void TCanvas::Destructor()
673 {
674  if (gThreadXAR) {
675  void *arr[2];
676  arr[1] = this;
677  if ((*gThreadXAR)("CDEL", 2, arr, 0)) return;
678  }
679 
680  if (!TestBit(kNotDeleted)) return;
681 
682  if (fContextMenu) { delete fContextMenu; fContextMenu = 0; }
683  if (!gPad) return;
684 
685  Close();
686 
687  //If not yet (batch mode?).
688  delete fPainter;
689 }
690 
691 ////////////////////////////////////////////////////////////////////////////////
692 /// Set current canvas & pad. Returns the new current pad,
693 /// or 0 in case of failure.
694 /// See TPad::cd() for an explanation of the parameter.
695 
696 TVirtualPad *TCanvas::cd(Int_t subpadnumber)
697 {
698  if (fCanvasID == -1) return 0;
699 
700  TPad::cd(subpadnumber);
701 
702  // in case doublebuffer is off, draw directly onto display window
703  if (!IsBatch()) {
704  if (!fDoubleBuffer)
705  gVirtualX->SelectWindow(fCanvasID);//Ok, does not matter for glpad.
706  }
707  return gPad;
708 }
709 
710 ////////////////////////////////////////////////////////////////////////////////
711 /// Remove all primitives from the canvas.
712 /// If option "D" is specified, direct sub-pads are cleared but not deleted.
713 /// This option is not recursive, i.e. pads in direct sub-pads are deleted.
714 
715 void TCanvas::Clear(Option_t *option)
716 {
717  if (fCanvasID == -1) return;
718 
719  R__LOCKGUARD(gROOTMutex);
720 
721  TString opt = option;
722  opt.ToLower();
723  if (opt.Contains("d")) {
724  // clear subpads, but do not delete pads in case the canvas
725  // has been divided (note: option "D" is propagated so could cause
726  // conflicts for primitives using option "D" for something else)
727  if (fPrimitives) {
728  TIter next(fPrimitives);
729  TObject *obj;
730  while ((obj=next())) {
731  obj->Clear(option);
732  }
733  }
734  } else {
735  //default, clear everything in the canvas. Subpads are deleted
736  TPad::Clear(option); //Remove primitives from pad
737  }
738 
739  fSelected = 0;
740  fClickSelected = 0;
741  fSelectedPad = 0;
742  fClickSelectedPad = 0;
743 }
744 
745 ////////////////////////////////////////////////////////////////////////////////
746 /// Emit pad Cleared signal.
747 
748 void TCanvas::Cleared(TVirtualPad *pad)
749 {
750  Emit("Cleared(TVirtualPad*)", (Long_t)pad);
751 }
752 
753 ////////////////////////////////////////////////////////////////////////////////
754 /// Emit Closed signal.
755 
756 void TCanvas::Closed()
757 {
758  Emit("Closed()");
759 }
760 
761 ////////////////////////////////////////////////////////////////////////////////
762 /// Close canvas.
763 ///
764 /// Delete window/pads data structure
765 
766 void TCanvas::Close(Option_t *option)
767 {
768  TPad *padsave = (TPad*)gPad;
769  TCanvas *cansave = 0;
770  if (padsave) cansave = (TCanvas*)gPad->GetCanvas();
771 
772  if (fCanvasID != -1) {
773 
774  if ((!gROOT->IsLineProcessing()) && (!gVirtualX->IsCmdThread())) {
775  gInterpreter->Execute(this, IsA(), "Close", option);
776  return;
777  }
778 
779  R__LOCKGUARD(gROOTMutex);
780 
781  FeedbackMode(kFALSE);
782 
783  cd();
784  TPad::Close(option);
785 
786  if (!IsBatch()) {
787  gVirtualX->SelectWindow(fCanvasID); //select current canvas
788 
789  DeleteCanvasPainter();
790 
791  if (fCanvasImp)
792  fCanvasImp->Close();
793  }
794  fCanvasID = -1;
795  fBatch = kTRUE;
796 
797  gROOT->GetListOfCanvases()->Remove(this);
798 
799  // Close actual window on screen
800  SafeDelete(fCanvasImp);
801  }
802 
803  if (cansave == this) {
804  gPad = (TCanvas *) gROOT->GetListOfCanvases()->First();
805  } else {
806  gPad = padsave;
807  }
808 
809  Closed();
810 }
811 
812 ////////////////////////////////////////////////////////////////////////////////
813 /// Copy the canvas pixmap of the pad to the canvas.
814 
815 void TCanvas::CopyPixmaps()
816 {
817  if (!IsBatch()) {
818  CopyPixmap();
819  TPad::CopyPixmaps();
820  }
821 }
822 
823 ////////////////////////////////////////////////////////////////////////////////
824 /// Draw a canvas.
825 /// If a canvas with the name is already on the screen, the canvas is repainted.
826 /// This function is useful when a canvas object has been saved in a Root file.
827 /// One can then do:
828 /// ~~~ {.cpp}
829 /// Root > Tfile f("file.root");
830 /// Root > canvas.Draw();
831 /// ~~~
832 
833 void TCanvas::Draw(Option_t *)
834 {
835  // Load and initialize graphics libraries if
836  // TApplication::NeedGraphicsLibs() has been called by a
837  // library static initializer.
838  if (gApplication)
839  gApplication->InitializeGraphics();
840 
841  fDrawn = kTRUE;
842 
843  TCanvas *old = (TCanvas*)gROOT->GetListOfCanvases()->FindObject(GetName());
844  if (old == this) {
845  Paint();
846  return;
847  }
848  if (old) { gROOT->GetListOfCanvases()->Remove(old); delete old;}
849 
850  if (fWindowWidth == 0) {
851  if (fCw !=0) fWindowWidth = fCw+4;
852  else fWindowWidth = 800;
853  }
854  if (fWindowHeight == 0) {
855  if (fCh !=0) fWindowHeight = fCh+28;
856  else fWindowHeight = 600;
857  }
858  if (gROOT->IsBatch()) { //We are in Batch mode
859  fCanvasImp = gBatchGuiFactory->CreateCanvasImp(this, GetName(), fWindowWidth, fWindowHeight);
860  if (!fCanvasImp) return;
861  fBatch = kTRUE;
862 
863  } else { //normal mode with a screen window
864  fCanvasImp = gGuiFactory->CreateCanvasImp(this, GetName(), fWindowTopX, fWindowTopY,
865  fWindowWidth, fWindowHeight);
866  if (!fCanvasImp) return;
867  fCanvasImp->ShowMenuBar(TestBit(kMenuBar));
868  }
869  Build();
870  ResizePad();
871  fCanvasImp->SetWindowTitle(fTitle);
872  fCanvasImp->Show();
873  Modified();
874 }
875 
876 ////////////////////////////////////////////////////////////////////////////////
877 /// Draw a clone of this canvas
878 /// A new canvas is created that is a clone of this canvas
879 
880 TObject *TCanvas::DrawClone(Option_t *option) const
881 {
882  TCanvas *newCanvas = (TCanvas*)Clone();
883  newCanvas->SetName();
884 
885  newCanvas->Draw(option);
886  newCanvas->Update();
887  return newCanvas;
888 }
889 
890 ////////////////////////////////////////////////////////////////////////////////
891 /// Draw a clone of this canvas into the current pad
892 /// In an interactive session, select the destination/current pad
893 /// with the middle mouse button, then point to the canvas area to select
894 /// the canvas context menu item DrawClonePad.
895 /// Note that the original canvas may have subpads.
896 
897 TObject *TCanvas::DrawClonePad()
898 {
899  TPad *padsav = (TPad*)gPad;
900  TPad *selpad = (TPad*)gROOT->GetSelectedPad();
901  TPad *pad = padsav;
902  if (pad == this) pad = selpad;
903  if (padsav == 0 || pad == 0 || pad == this) {
904  TCanvas *newCanvas = (TCanvas*)DrawClone();
905  newCanvas->SetWindowSize(GetWindowWidth(),GetWindowHeight());
906  return newCanvas;
907  }
908  if (fCanvasID == -1) {
909  fCanvasImp = gGuiFactory->CreateCanvasImp(this, GetName(), fWindowTopX, fWindowTopY,
910  fWindowWidth, fWindowHeight);
911  if (!fCanvasImp) return 0;
912  fCanvasImp->ShowMenuBar(TestBit(kMenuBar));
913  fCanvasID = fCanvasImp->InitWindow();
914  }
915  this->cd();
916  TObject *obj, *clone;
917  //copy pad attributes
918  pad->Range(fX1,fY1,fX2,fY2);
919  pad->SetTickx(GetTickx());
920  pad->SetTicky(GetTicky());
921  pad->SetGridx(GetGridx());
922  pad->SetGridy(GetGridy());
923  pad->SetLogx(GetLogx());
924  pad->SetLogy(GetLogy());
925  pad->SetLogz(GetLogz());
926  pad->SetBorderSize(GetBorderSize());
927  pad->SetBorderMode(GetBorderMode());
928  TAttLine::Copy((TAttLine&)*pad);
929  TAttFill::Copy((TAttFill&)*pad);
930  TAttPad::Copy((TAttPad&)*pad);
931 
932  //copy primitives
933  TIter next(GetListOfPrimitives());
934  while ((obj=next())) {
935  pad->cd();
936  clone = obj->Clone();
937  pad->GetListOfPrimitives()->Add(clone,next.GetOption());
938  }
939  pad->ResizePad();
940  pad->Modified();
941  pad->Update();
942  if (padsav) padsav->cd();
943  return 0;
944 }
945 
946 ////////////////////////////////////////////////////////////////////////////////
947 /// Report name and title of primitive below the cursor.
948 ///
949 /// This function is called when the option "Event Status"
950 /// in the canvas menu "Options" is selected.
951 
952 void TCanvas::DrawEventStatus(Int_t event, Int_t px, Int_t py, TObject *selected)
953 {
954  const Int_t kTMAX=256;
955  static char atext[kTMAX];
956 
957  if (!TestBit(kShowEventStatus) || !selected) return;
958 
959  if (!fCanvasImp) return; //this may happen when closing a TAttCanvas
960 
961  TVirtualPad* savepad;
962  savepad = gPad;
963  gPad = GetSelectedPad();
964 
965  fCanvasImp->SetStatusText(selected->GetTitle(),0);
966  fCanvasImp->SetStatusText(selected->GetName(),1);
967  if (event == kKeyPress)
968  snprintf(atext, kTMAX, "%c", (char) px);
969  else
970  snprintf(atext, kTMAX, "%d,%d", px, py);
971  fCanvasImp->SetStatusText(atext,2);
972 
973  // Show date/time if TimeDisplay is selected
974  TAxis *xaxis = NULL;
975  if ( selected->InheritsFrom("TH1") )
976  xaxis = ((TH1*)selected)->GetXaxis();
977  else if ( selected->InheritsFrom("TGraph") )
978  xaxis = ((TGraph*)selected)->GetXaxis();
979  else if ( selected->InheritsFrom("TAxis") )
980  xaxis = (TAxis*)selected;
981  if ( xaxis != NULL && xaxis->GetTimeDisplay()) {
982  TString objinfo = selected->GetObjectInfo(px,py);
983  // check if user has overwritten GetObjectInfo and altered
984  // the default text from TObject::GetObjectInfo "x=.. y=.."
985  if (objinfo.Contains("x=") && objinfo.Contains("y=") ) {
986  UInt_t toff = 0;
987  TString time_format(xaxis->GetTimeFormat());
988  // TimeFormat may contain offset: %F2000-01-01 00:00:00
989  Int_t idF = time_format.Index("%F");
990  if (idF>=0) {
991  Int_t lnF = time_format.Length();
992  // minimal check for correct format
993  if (lnF - idF == 21) {
994  time_format = time_format(idF+2, lnF);
995  TDatime dtoff(time_format);
996  toff = dtoff.Convert();
997  }
998  } else {
999  toff = (UInt_t)gStyle->GetTimeOffset();
1000  }
1001  TDatime dt((UInt_t)gPad->AbsPixeltoX(px) + toff);
1002  snprintf(atext, kTMAX, "%s, y=%g",
1003  dt.AsSQLString(),gPad->AbsPixeltoY(py));
1004  fCanvasImp->SetStatusText(atext,3);
1005  gPad = savepad;
1006  return;
1007  }
1008  }
1009  // default
1010  fCanvasImp->SetStatusText(selected->GetObjectInfo(px,py),3);
1011 
1012  gPad = savepad;
1013 }
1014 
1015 ////////////////////////////////////////////////////////////////////////////////
1016 /// Get editor bar.
1017 
1018 void TCanvas::EditorBar()
1019 {
1020  TVirtualPadEditor::GetPadEditor();
1021 }
1022 
1023 ////////////////////////////////////////////////////////////////////////////////
1024 /// Embedded a canvas into a TRootEmbeddedCanvas. This method is only called
1025 /// via TRootEmbeddedCanvas::AdoptCanvas.
1026 
1027 void TCanvas::EmbedInto(Int_t winid, Int_t ww, Int_t wh)
1028 {
1029  // If fCanvasImp already exists, no need to go further.
1030  if(fCanvasImp) return;
1031 
1032  fCanvasID = winid;
1033  fWindowTopX = 0;
1034  fWindowTopY = 0;
1035  fWindowWidth = ww;
1036  fWindowHeight = wh;
1037  fCw = ww;
1038  fCh = wh;
1039  fBatch = kFALSE;
1040  fUpdating = kFALSE;
1041 
1042  fCanvasImp = gBatchGuiFactory->CreateCanvasImp(this, GetName(), fCw, fCh);
1043  if (!fCanvasImp) return;
1044  Build();
1045  Resize();
1046 }
1047 
1048 ////////////////////////////////////////////////////////////////////////////////
1049 /// Generate kMouseEnter and kMouseLeave events depending on the previously
1050 /// selected object and the currently selected object. Does nothing if the
1051 /// selected object does not change.
1052 
1053 void TCanvas::EnterLeave(TPad *prevSelPad, TObject *prevSelObj)
1054 {
1055  if (prevSelObj == fSelected) return;
1056 
1057  TPad *padsav = (TPad *)gPad;
1058  Int_t sevent = fEvent;
1059 
1060  if (prevSelObj) {
1061  gPad = prevSelPad;
1062  prevSelObj->ExecuteEvent(kMouseLeave, fEventX, fEventY);
1063  fEvent = kMouseLeave;
1064  RunAutoExec();
1065  ProcessedEvent(kMouseLeave, fEventX, fEventY, prevSelObj); // emit signal
1066  }
1067 
1068  gPad = fSelectedPad;
1069 
1070  if (fSelected) {
1071  fSelected->ExecuteEvent(kMouseEnter, fEventX, fEventY);
1072  fEvent = kMouseEnter;
1073  RunAutoExec();
1074  ProcessedEvent(kMouseEnter, fEventX, fEventY, fSelected); // emit signal
1075  }
1076 
1077  fEvent = sevent;
1078  gPad = padsav;
1079 }
1080 
1081 ////////////////////////////////////////////////////////////////////////////////
1082 /// Execute action corresponding to one event.
1083 ///
1084 /// This member function must be implemented to realize the action
1085 /// corresponding to the mouse click on the object in the canvas
1086 ///
1087 /// Only handle mouse motion events in TCanvas, all other events are
1088 /// ignored for the time being
1089 
1090 void TCanvas::ExecuteEvent(Int_t event, Int_t px, Int_t py)
1091 {
1092  if (gROOT->GetEditorMode()) {
1093  TPad::ExecuteEvent(event,px,py);
1094  return;
1095  }
1096 
1097  switch (event) {
1098 
1099  case kMouseMotion:
1100  SetCursor(kCross);
1101  break;
1102  }
1103 }
1104 
1105 ////////////////////////////////////////////////////////////////////////////////
1106 /// Turn rubberband feedback mode on or off.
1107 
1108 void TCanvas::FeedbackMode(Bool_t set)
1109 {
1110  if (set) {
1111  SetDoubleBuffer(0); // turn off double buffer mode
1112  gVirtualX->SetDrawMode(TVirtualX::kInvert); // set the drawing mode to XOR mode
1113  } else {
1114  SetDoubleBuffer(1); // turn on double buffer mode
1115  gVirtualX->SetDrawMode(TVirtualX::kCopy); // set drawing mode back to normal (copy) mode
1116  }
1117 }
1118 
1119 ////////////////////////////////////////////////////////////////////////////////
1120 /// Flush canvas buffers.
1121 
1122 void TCanvas::Flush()
1123 {
1124  if ((fCanvasID == -1) || IsWeb()) return;
1125 
1126  TPad *padsav = (TPad*)gPad;
1127  cd();
1128  if (!IsBatch()) {
1129  if (!UseGL()) {
1130  gVirtualX->SelectWindow(fCanvasID);
1131  gPad = padsav; //don't do cd() because than also the pixmap is changed
1132  CopyPixmaps();
1133  gVirtualX->UpdateWindow(1);
1134  } else {
1135  TVirtualPS *tvps = gVirtualPS;
1136  gVirtualPS = 0;
1137  gGLManager->MakeCurrent(fGLDevice);
1138  fPainter->InitPainter();
1139  Paint();
1140  if (padsav && padsav->GetCanvas() == this) {
1141  padsav->cd();
1142  padsav->HighLight(padsav->GetHighLightColor());
1143  //cd();
1144  }
1145  fPainter->LockPainter();
1146  gGLManager->Flush(fGLDevice);
1147  gVirtualPS = tvps;
1148  }
1149  }
1150  if (padsav) padsav->cd();
1151 }
1152 
1153 ////////////////////////////////////////////////////////////////////////////////
1154 /// Force a copy of current style for all objects in canvas.
1155 
1156 void TCanvas::UseCurrentStyle()
1157 {
1158  if ((!gROOT->IsLineProcessing()) && (!gVirtualX->IsCmdThread())) {
1159  gInterpreter->Execute(this, IsA(), "UseCurrentStyle", "");
1160  return;
1161  }
1162 
1163  R__LOCKGUARD(gROOTMutex);
1164 
1165  TPad::UseCurrentStyle();
1166 
1167  if (gStyle->IsReading()) {
1168  SetFillColor(gStyle->GetCanvasColor());
1169  fBorderSize = gStyle->GetCanvasBorderSize();
1170  fBorderMode = gStyle->GetCanvasBorderMode();
1171  } else {
1172  gStyle->SetCanvasColor(GetFillColor());
1173  gStyle->SetCanvasBorderSize(fBorderSize);
1174  gStyle->SetCanvasBorderMode(fBorderMode);
1175  }
1176 }
1177 
1178 ////////////////////////////////////////////////////////////////////////////////
1179 /// Returns current top x position of window on screen.
1180 
1181 Int_t TCanvas::GetWindowTopX()
1182 {
1183  if (fCanvasImp) fCanvasImp->GetWindowGeometry(fWindowTopX, fWindowTopY,
1184  fWindowWidth,fWindowHeight);
1185 
1186  return fWindowTopX;
1187 }
1188 
1189 ////////////////////////////////////////////////////////////////////////////////
1190 /// Returns current top y position of window on screen.
1191 
1192 Int_t TCanvas::GetWindowTopY()
1193 {
1194  if (fCanvasImp) fCanvasImp->GetWindowGeometry(fWindowTopX, fWindowTopY,
1195  fWindowWidth,fWindowHeight);
1196 
1197  return fWindowTopY;
1198 }
1199 
1200 ////////////////////////////////////////////////////////////////////////////////
1201 /// Handle Input Events.
1202 ///
1203 /// Handle input events, like button up/down in current canvas.
1204 
1205 void TCanvas::HandleInput(EEventType event, Int_t px, Int_t py)
1206 {
1207  TPad *pad;
1208  TPad *prevSelPad = (TPad*) fSelectedPad;
1209  TObject *prevSelObj = fSelected;
1210 
1211  fPadSave = (TPad*)gPad;
1212  cd(); // make sure this canvas is the current canvas
1213 
1214  fEvent = event;
1215  fEventX = px;
1216  fEventY = py;
1217 
1218  switch (event) {
1219 
1220  case kMouseMotion:
1221  // highlight object tracked over
1222  pad = Pick(px, py, prevSelObj);
1223  if (!pad) return;
1224 
1225  EnterLeave(prevSelPad, prevSelObj);
1226 
1227  gPad = pad; // don't use cd() we will use the current
1228  // canvas via the GetCanvas member and not via
1229  // gPad->GetCanvas
1230 
1231  if (fSelected) {
1232  fSelected->ExecuteEvent(event, px, py);
1233  RunAutoExec();
1234  }
1235 
1236  break;
1237 
1238  case kMouseEnter:
1239  // mouse enters canvas
1240  if (!fDoubleBuffer) FeedbackMode(kTRUE);
1241  break;
1242 
1243  case kMouseLeave:
1244  // mouse leaves canvas
1245  {
1246  // force popdown of tooltips
1247  TObject *sobj = fSelected;
1248  TPad *spad = fSelectedPad;
1249  fSelected = 0;
1250  fSelectedPad = 0;
1251  EnterLeave(prevSelPad, prevSelObj);
1252  fSelected = sobj;
1253  fSelectedPad = spad;
1254  if (!fDoubleBuffer) FeedbackMode(kFALSE);
1255  }
1256  break;
1257 
1258  case kButton1Double:
1259  // triggered on the second button down within 350ms and within
1260  // 3x3 pixels of the first button down, button up finishes action
1261 
1262  case kButton1Down:
1263  // find pad in which input occurred
1264  pad = Pick(px, py, prevSelObj);
1265  if (!pad) return;
1266 
1267  gPad = pad; // don't use cd() because we won't draw in pad
1268  // we will only use its coordinate system
1269 
1270  if (fSelected) {
1271  FeedbackMode(kTRUE); // to draw in rubberband mode
1272  fSelected->ExecuteEvent(event, px, py);
1273 
1274  RunAutoExec();
1275  }
1276 
1277  break;
1278 
1279  case kArrowKeyPress:
1280  case kArrowKeyRelease:
1281  case kButton1Motion:
1282  case kButton1ShiftMotion: //8 == kButton1Motion + shift modifier
1283  if (fSelected) {
1284  gPad = fSelectedPad;
1285 
1286  fSelected->ExecuteEvent(event, px, py);
1287  gVirtualX->Update();
1288  if (fSelected && !fSelected->InheritsFrom(TAxis::Class())) {
1289  Bool_t resize = kFALSE;
1290  if (fSelected->InheritsFrom(TBox::Class()))
1291  resize = ((TBox*)fSelected)->IsBeingResized();
1292  if (fSelected->InheritsFrom(TVirtualPad::Class()))
1293  resize = ((TVirtualPad*)fSelected)->IsBeingResized();
1294 
1295  if ((!resize && TestBit(kMoveOpaque)) || (resize && TestBit(kResizeOpaque))) {
1296  gPad = fPadSave;
1297  Update();
1298  FeedbackMode(kTRUE);
1299  }
1300  }
1301 
1302  RunAutoExec();
1303  }
1304 
1305  break;
1306 
1307  case kButton1Up:
1308 
1309  if (fSelected) {
1310  gPad = fSelectedPad;
1311 
1312  fSelected->ExecuteEvent(event, px, py);
1313 
1314  RunAutoExec();
1315 
1316  if (fPadSave)
1317  gPad = fPadSave;
1318  else {
1319  gPad = this;
1320  fPadSave = this;
1321  }
1322 
1323  Update(); // before calling update make sure gPad is reset
1324  }
1325  break;
1326 
1327 //*-*----------------------------------------------------------------------
1328 
1329  case kButton2Down:
1330  // find pad in which input occurred
1331  pad = Pick(px, py, prevSelObj);
1332  if (!pad) return;
1333 
1334  gPad = pad; // don't use cd() because we won't draw in pad
1335  // we will only use its coordinate system
1336 
1337  FeedbackMode(kTRUE);
1338 
1339  if (fSelected) fSelected->Pop(); // pop object to foreground
1340  pad->cd(); // and make its pad the current pad
1341  if (gDebug)
1342  printf("Current Pad: %s / %s\n", pad->GetName(), pad->GetTitle());
1343 
1344  // loop over all canvases to make sure that only one pad is highlighted
1345  {
1346  TIter next(gROOT->GetListOfCanvases());
1347  TCanvas *tc;
1348  while ((tc = (TCanvas *)next()))
1349  tc->Update();
1350  }
1351 
1352  //if (pad->GetGLDevice() != -1 && fSelected)
1353  // fSelected->ExecuteEvent(event, px, py);
1354 
1355  break; // don't want fPadSave->cd() to be executed at the end
1356 
1357  case kButton2Motion:
1358  //was empty!
1359  case kButton2Up:
1360  if (fSelected) {
1361  gPad = fSelectedPad;
1362 
1363  fSelected->ExecuteEvent(event, px, py);
1364  RunAutoExec();
1365  }
1366  break;
1367 
1368  case kButton2Double:
1369  break;
1370 
1371 //*-*----------------------------------------------------------------------
1372 
1373  case kButton3Down:
1374  // popup context menu
1375  pad = Pick(px, py, prevSelObj);
1376  if (!pad) return;
1377 
1378  if (!fDoubleBuffer) FeedbackMode(kFALSE);
1379 
1380  if (fContextMenu && fSelected && !fSelected->TestBit(kNoContextMenu) &&
1381  !pad->TestBit(kNoContextMenu) && !TestBit(kNoContextMenu))
1382  fContextMenu->Popup(px, py, fSelected, this, pad);
1383 
1384  break;
1385 
1386  case kButton3Motion:
1387  break;
1388 
1389  case kButton3Up:
1390  if (!fDoubleBuffer) FeedbackMode(kTRUE);
1391  break;
1392 
1393  case kButton3Double:
1394  break;
1395 
1396  case kKeyPress:
1397  if (!fSelectedPad || !fSelected) return;
1398  gPad = fSelectedPad; // don't use cd() because we won't draw in pad
1399  // we will only use its coordinate system
1400  fSelected->ExecuteEvent(event, px, py);
1401 
1402  RunAutoExec();
1403 
1404  break;
1405 
1406  case kButton1Shift:
1407  // Try to select
1408  pad = Pick(px, py, prevSelObj);
1409 
1410  if (!pad) return;
1411 
1412  EnterLeave(prevSelPad, prevSelObj);
1413 
1414  gPad = pad; // don't use cd() we will use the current
1415  // canvas via the GetCanvas member and not via
1416  // gPad->GetCanvas
1417  if (fSelected) {
1418  fSelected->ExecuteEvent(event, px, py);
1419  RunAutoExec();
1420  }
1421  break;
1422 
1423  case kWheelUp:
1424  case kWheelDown:
1425  pad = Pick(px, py, prevSelObj);
1426  if (!pad) return;
1427 
1428  gPad = pad;
1429  if (fSelected)
1430  fSelected->ExecuteEvent(event, px, py);
1431  break;
1432 
1433  default:
1434  break;
1435  }
1436 
1437  if (fPadSave && event != kButton2Down)
1438  fPadSave->cd();
1439 
1440  if (event != kMouseLeave) { // signal was already emitted for this event
1441  ProcessedEvent(event, px, py, fSelected); // emit signal
1442  DrawEventStatus(event, px, py, fSelected);
1443  }
1444 }
1445 
1446 ////////////////////////////////////////////////////////////////////////////////
1447 /// Is folder ?
1448 
1449 Bool_t TCanvas::IsFolder() const
1450 {
1451  return fgIsFolder;
1452 }
1453 
1454 ////////////////////////////////////////////////////////////////////////////////
1455 /// List all pads.
1456 
1457 void TCanvas::ls(Option_t *option) const
1458 {
1459  TROOT::IndentLevel();
1460  std::cout <<"Canvas Name=" <<GetName()<<" Title="<<GetTitle()<<" Option="<<option<<std::endl;
1461  TROOT::IncreaseDirLevel();
1462  TPad::ls(option);
1463  TROOT::DecreaseDirLevel();
1464 }
1465 
1466 ////////////////////////////////////////////////////////////////////////////////
1467 /// Static function to build a default canvas.
1468 
1469 TCanvas *TCanvas::MakeDefCanvas()
1470 {
1471  const char *defcanvas = gROOT->GetDefCanvasName();
1472  char *cdef;
1473 
1474  auto lc = (TList*)gROOT->GetListOfCanvases();
1475  if (lc->FindObject(defcanvas)) {
1476  Int_t n = lc->GetSize() + 1;
1477  cdef = new char[strlen(defcanvas)+15];
1478  do {
1479  strlcpy(cdef,Form("%s_n%d", defcanvas, n++),strlen(defcanvas)+15);
1480  } while (lc->FindObject(cdef));
1481  } else
1482  cdef = StrDup(Form("%s",defcanvas));
1483 
1484  TCanvas *c = new TCanvas(cdef, cdef, 1);
1485 
1486  ::Info("TCanvas::MakeDefCanvas"," created default TCanvas with name %s",cdef);
1487  delete [] cdef;
1488  return c;
1489 }
1490 
1491 ////////////////////////////////////////////////////////////////////////////////
1492 /// Set option to move objects/pads in a canvas.
1493 ///
1494 /// - set = 1 (default) graphics objects are moved in opaque mode
1495 /// - set = 0 only the outline of objects is drawn when moving them
1496 ///
1497 /// The option opaque produces the best effect. It requires however a
1498 /// a reasonably fast workstation or response time.
1499 
1500 void TCanvas::MoveOpaque(Int_t set)
1501 {
1502  SetBit(kMoveOpaque,set);
1503 }
1504 
1505 ////////////////////////////////////////////////////////////////////////////////
1506 /// Paint canvas.
1507 
1508 void TCanvas::Paint(Option_t *option)
1509 {
1510  if (fCanvas)
1511  TPad::Paint(option);
1512 }
1513 
1514 ////////////////////////////////////////////////////////////////////////////////
1515 /// Prepare for pick, call TPad::Pick() and when selected object
1516 /// is different from previous then emit Picked() signal.
1517 
1518 TPad *TCanvas::Pick(Int_t px, Int_t py, TObject *prevSelObj)
1519 {
1520  TObjLink *pickobj = 0;
1521 
1522  fSelected = 0;
1523  fSelectedOpt = "";
1524  fSelectedPad = 0;
1525 
1526  TPad *pad = Pick(px, py, pickobj);
1527  if (!pad) return 0;
1528 
1529  if (!pickobj) {
1530  fSelected = pad;
1531  fSelectedOpt = "";
1532  } else {
1533  if (!fSelected) { // can be set via TCanvas::SetSelected()
1534  fSelected = pickobj->GetObject();
1535  fSelectedOpt = pickobj->GetOption();
1536  }
1537  }
1538  fSelectedPad = pad;
1539 
1540  if (fSelected != prevSelObj)
1541  Picked(fSelectedPad, fSelected, fEvent); // emit signal
1542 
1543  if ((fEvent == kButton1Down) || (fEvent == kButton2Down) || (fEvent == kButton3Down)) {
1544  if (fSelected && !fSelected->InheritsFrom(TView::Class())) {
1545  fClickSelected = fSelected;
1546  fClickSelectedPad = fSelectedPad;
1547  Selected(fSelectedPad, fSelected, fEvent); // emit signal
1548  fSelectedX = px;
1549  fSelectedY = py;
1550  }
1551  }
1552  return pad;
1553 }
1554 
1555 ////////////////////////////////////////////////////////////////////////////////
1556 /// Emit Picked() signal.
1557 
1558 void TCanvas::Picked(TPad *pad, TObject *obj, Int_t event)
1559 {
1560  Long_t args[3];
1561 
1562  args[0] = (Long_t) pad;
1563  args[1] = (Long_t) obj;
1564  args[2] = event;
1565 
1566  Emit("Picked(TPad*,TObject*,Int_t)", args);
1567 }
1568 
1569 ////////////////////////////////////////////////////////////////////////////////
1570 /// Emit Highlighted() signal.
1571 ///
1572 /// - pad is pointer to pad with highlighted histogram or graph
1573 /// - obj is pointer to highlighted histogram or graph
1574 /// - x is highlighted x bin for 1D histogram or highlighted x-th point for graph
1575 /// - y is highlighted y bin for 2D histogram (for 1D histogram or graph not in use)
1576 
1577 void TCanvas::Highlighted(TVirtualPad *pad, TObject *obj, Int_t x, Int_t y)
1578 {
1579  Long_t args[4];
1580 
1581  args[0] = (Long_t) pad;
1582  args[1] = (Long_t) obj;
1583  args[2] = x;
1584  args[3] = y;
1585 
1586  Emit("Highlighted(TVirtualPad*,TObject*,Int_t,Int_t)", args);
1587 }
1588 
1589 ////////////////////////////////////////////////////////////////////////////////
1590 /// This is "simplification" for function TCanvas::Connect with Highlighted
1591 /// signal for specific slot.
1592 ///
1593 /// Slot has to be defined "UserFunction(TVirtualPad *pad, TObject *obj, Int_t x, Int_t y)"
1594 /// all parameters of UserFunction are taken from TCanvas::Highlighted
1595 
1596 void TCanvas::HighlightConnect(const char *slot)
1597 {
1598  Connect("Highlighted(TVirtualPad*,TObject*,Int_t,Int_t)", 0, 0, slot);
1599 }
1600 
1601 ////////////////////////////////////////////////////////////////////////////////
1602 /// Emit Selected() signal.
1603 
1604 void TCanvas::Selected(TVirtualPad *pad, TObject *obj, Int_t event)
1605 {
1606  Long_t args[3];
1607 
1608  args[0] = (Long_t) pad;
1609  args[1] = (Long_t) obj;
1610  args[2] = event;
1611 
1612  Emit("Selected(TVirtualPad*,TObject*,Int_t)", args);
1613 }
1614 
1615 ////////////////////////////////////////////////////////////////////////////////
1616 /// Emit ProcessedEvent() signal.
1617 
1618 void TCanvas::ProcessedEvent(Int_t event, Int_t x, Int_t y, TObject *obj)
1619 {
1620  Long_t args[4];
1621 
1622  args[0] = event;
1623  args[1] = x;
1624  args[2] = y;
1625  args[3] = (Long_t) obj;
1626 
1627  Emit("ProcessedEvent(Int_t,Int_t,Int_t,TObject*)", args);
1628 }
1629 
1630 ////////////////////////////////////////////////////////////////////////////////
1631 /// Recompute canvas parameters following a X11 Resize.
1632 
1633 void TCanvas::Resize(Option_t *)
1634 {
1635  if (fCanvasID == -1) return;
1636 
1637  if ((!gROOT->IsLineProcessing()) && (!gVirtualX->IsCmdThread())) {
1638  gInterpreter->Execute(this, IsA(), "Resize", "");
1639  return;
1640  }
1641 
1642  R__LOCKGUARD(gROOTMutex);
1643 
1644  TPad *padsav = (TPad*)gPad;
1645  cd();
1646 
1647  if (!IsBatch()) {
1648  gVirtualX->SelectWindow(fCanvasID); //select current canvas
1649  gVirtualX->ResizeWindow(fCanvasID); //resize canvas and off-screen buffer
1650 
1651  // Get effective window parameters including menubar and borders
1652  fCanvasImp->GetWindowGeometry(fWindowTopX, fWindowTopY,
1653  fWindowWidth, fWindowHeight);
1654 
1655  // Get effective canvas parameters without borders
1656  Int_t dum1, dum2;
1657  gVirtualX->GetGeometry(fCanvasID, dum1, dum2, fCw, fCh);
1658  }
1659 
1660  if (fXsizeUser && fYsizeUser) {
1661  UInt_t nwh = fCh;
1662  UInt_t nww = fCw;
1663  Double_t rxy = fXsizeUser/fYsizeUser;
1664  if (rxy < 1) {
1665  UInt_t twh = UInt_t(Double_t(fCw)/rxy);
1666  if (twh > fCh)
1667  nww = UInt_t(Double_t(fCh)*rxy);
1668  else
1669  nwh = twh;
1670  if (nww > fCw) {
1671  nww = fCw; nwh = twh;
1672  }
1673  if (nwh > fCh) {
1674  nwh = fCh; nww = UInt_t(Double_t(fCh)/rxy);
1675  }
1676  } else {
1677  UInt_t twh = UInt_t(Double_t(fCw)*rxy);
1678  if (twh > fCh)
1679  nwh = UInt_t(Double_t(fCw)/rxy);
1680  else
1681  nww = twh;
1682  if (nww > fCw) {
1683  nww = fCw; nwh = twh;
1684  }
1685  if (nwh > fCh) {
1686  nwh = fCh; nww = UInt_t(Double_t(fCh)*rxy);
1687  }
1688  }
1689  fCw = nww;
1690  fCh = nwh;
1691  }
1692 
1693  if (fCw < fCh) {
1694  fYsizeReal = kDefaultCanvasSize;
1695  fXsizeReal = fYsizeReal*Double_t(fCw)/Double_t(fCh);
1696  }
1697  else {
1698  fXsizeReal = kDefaultCanvasSize;
1699  fYsizeReal = fXsizeReal*Double_t(fCh)/Double_t(fCw);
1700  }
1701 
1702 //*-*- Loop on all pads to recompute conversion coefficients
1703  TPad::ResizePad();
1704 
1705  if (padsav) padsav->cd();
1706 }
1707 
1708 ////////////////////////////////////////////////////////////////////////////////
1709 /// Set option to resize objects/pads in a canvas.
1710 ///
1711 /// - set = 1 (default) graphics objects are resized in opaque mode
1712 /// - set = 0 only the outline of objects is drawn when resizing them
1713 ///
1714 /// The option opaque produces the best effect. It requires however a
1715 /// a reasonably fast workstation or response time.
1716 
1717 void TCanvas::ResizeOpaque(Int_t set)
1718 {
1719  SetBit(kResizeOpaque,set);
1720 }
1721 
1722 ////////////////////////////////////////////////////////////////////////////////
1723 /// Execute the list of TExecs in the current pad.
1724 
1725 void TCanvas::RunAutoExec()
1726 {
1727  if (!TestBit(kAutoExec)) return;
1728  if (!gPad) return;
1729  ((TPad*)gPad)->AutoExec();
1730 }
1731 
1732 
1733 ////////////////////////////////////////////////////////////////////////////////
1734 /// Save primitives in this canvas in C++ macro file with GUI.
1735 
1736 void TCanvas::SavePrimitive(std::ostream &out, Option_t *option /*= ""*/)
1737 {
1738  // Write canvas options (in $TROOT or $TStyle)
1739  if (gStyle->GetOptFit()) {
1740  out<<" gStyle->SetOptFit(1);"<<std::endl;
1741  }
1742  if (!gStyle->GetOptStat()) {
1743  out<<" gStyle->SetOptStat(0);"<<std::endl;
1744  }
1745  if (!gStyle->GetOptTitle()) {
1746  out<<" gStyle->SetOptTitle(0);"<<std::endl;
1747  }
1748  if (gROOT->GetEditHistograms()) {
1749  out<<" gROOT->SetEditHistograms();"<<std::endl;
1750  }
1751  if (GetShowEventStatus()) {
1752  out<<" "<<GetName()<<"->ToggleEventStatus();"<<std::endl;
1753  }
1754  if (GetShowToolTips()) {
1755  out<<" "<<GetName()<<"->ToggleToolTips();"<<std::endl;
1756  }
1757  if (GetShowToolBar()) {
1758  out<<" "<<GetName()<<"->ToggleToolBar();"<<std::endl;
1759  }
1760  if (GetHighLightColor() != 5) {
1761  if (GetHighLightColor() > 228) {
1762  TColor::SaveColor(out, GetHighLightColor());
1763  out<<" "<<GetName()<<"->SetHighLightColor(ci);" << std::endl;
1764  } else
1765  out<<" "<<GetName()<<"->SetHighLightColor("<<GetHighLightColor()<<");"<<std::endl;
1766  }
1767 
1768  // Now recursively scan all pads of this canvas
1769  cd();
1770  TPad::SavePrimitive(out,option);
1771 }
1772 
1773 ////////////////////////////////////////////////////////////////////////////////
1774 /// Save primitives in this canvas as a C++ macro file.
1775 /// This function loops on all the canvas primitives and for each primitive
1776 /// calls the object SavePrimitive function.
1777 /// When outputting floating point numbers, the default precision is 7 digits.
1778 /// The precision can be changed (via system.rootrc) by changing the value
1779 /// of the environment variable "Canvas.SavePrecision"
1780 
1781 void TCanvas::SaveSource(const char *filename, Option_t *option)
1782 {
1783  // reset bit TClass::kClassSaved for all classes
1784  TIter next(gROOT->GetListOfClasses());
1785  TClass *cl;
1786  while((cl = (TClass*)next())) {
1787  cl->ResetBit(TClass::kClassSaved);
1788  }
1789 
1790  char quote = '"';
1791  std::ofstream out;
1792  Int_t lenfile = strlen(filename);
1793  char * fname;
1794  char lcname[10];
1795  const char *cname = GetName();
1796  Bool_t invalid = kFALSE;
1797  // if filename is given, open this file, otherwise create a file
1798  // with a name equal to the canvasname.C
1799  if (lenfile) {
1800  fname = (char*)filename;
1801  out.open(fname, std::ios::out);
1802  } else {
1803  Int_t nch = strlen(cname);
1804  if (nch < 10) {
1805  strlcpy(lcname,cname,10);
1806  for (Int_t k=1;k<=nch;k++) {if (lcname[nch-k] == ' ') lcname[nch-k] = 0;}
1807  if (lcname[0] == 0) {invalid = kTRUE; strlcpy(lcname,"c1",10); nch = 2;}
1808  cname = lcname;
1809  }
1810  fname = new char[nch+3];
1811  strlcpy(fname,cname,nch+3);
1812  strncat(fname,".C",3);
1813  out.open(fname, std::ios::out);
1814  }
1815  if (!out.good ()) {
1816  Error("SaveSource", "Cannot open file: %s",fname);
1817  if (!lenfile) delete [] fname;
1818  return;
1819  }
1820 
1821  //set precision
1822  Int_t precision = gEnv->GetValue("Canvas.SavePrecision",7);
1823  out.precision(precision);
1824 
1825  // Write macro header and date/time stamp
1826  TDatime t;
1827  Float_t cx = gStyle->GetScreenFactor();
1828  Int_t topx,topy;
1829  UInt_t w, h;
1830  if (!fCanvasImp) {
1831  Error("SaveSource", "Cannot open TCanvas");
1832  return;
1833  }
1834  UInt_t editorWidth = fCanvasImp->GetWindowGeometry(topx,topy,w,h);
1835  w = UInt_t((fWindowWidth - editorWidth)/cx);
1836  h = UInt_t((fWindowHeight)/cx);
1837  topx = GetWindowTopX();
1838  topy = GetWindowTopY();
1839 
1840  if (w == 0) {
1841  w = GetWw()+4; h = GetWh()+4;
1842  topx = 1; topy = 1;
1843  }
1844 
1845  TString mname(fname);
1846 // out <<"#ifdef __CLING__"<<std::endl;
1847 // out <<"#pragma cling optimize(0)"<<std::endl;
1848 // out <<"#endif"<<std::endl;
1849 // out <<""<<std::endl;
1850  Int_t p = mname.Last('.');
1851  Int_t s = mname.Last('/')+1;
1852 
1853  // A named macro is generated only if the function name is valid. If not, the
1854  // macro is unnamed.
1855  TString first(mname(s,s+1));
1856  if (!first.IsDigit()) out <<"void " << mname(s,p-s) << "()" << std::endl;
1857 
1858  out <<"{"<<std::endl;
1859  out <<"//=========Macro generated from canvas: "<<GetName()<<"/"<<GetTitle()<<std::endl;
1860  out <<"//========= ("<<t.AsString()<<") by ROOT version "<<gROOT->GetVersion()<<std::endl;
1861 
1862  if (gStyle->GetCanvasPreferGL())
1863  out <<std::endl<<" gStyle->SetCanvasPreferGL(kTRUE);"<<std::endl<<std::endl;
1864 
1865  // Write canvas parameters (TDialogCanvas case)
1866  if (InheritsFrom(TDialogCanvas::Class())) {
1867  out<<" "<<ClassName()<<" *"<<cname<<" = new "<<ClassName()<<"("<<quote<<GetName()
1868  <<quote<<", "<<quote<<GetTitle()<<quote<<","<<w<<","<<h<<");"<<std::endl;
1869  } else {
1870  // Write canvas parameters (TCanvas case)
1871  out<<" TCanvas *"<<cname<<" = new TCanvas("<<quote<<GetName()<<quote<<", "<<quote<<GetTitle()
1872  <<quote;
1873  if (!HasMenuBar())
1874  out<<",-"<<topx<<","<<topy<<","<<w<<","<<h<<");"<<std::endl;
1875  else
1876  out<<","<<topx<<","<<topy<<","<<w<<","<<h<<");"<<std::endl;
1877  }
1878  // Write canvas options (in $TROOT or $TStyle)
1879  if (gStyle->GetOptFit()) {
1880  out<<" gStyle->SetOptFit(1);"<<std::endl;
1881  }
1882  if (!gStyle->GetOptStat()) {
1883  out<<" gStyle->SetOptStat(0);"<<std::endl;
1884  }
1885  if (!gStyle->GetOptTitle()) {
1886  out<<" gStyle->SetOptTitle(0);"<<std::endl;
1887  }
1888  if (gROOT->GetEditHistograms()) {
1889  out<<" gROOT->SetEditHistograms();"<<std::endl;
1890  }
1891  if (GetShowEventStatus()) {
1892  out<<" "<<GetName()<<"->ToggleEventStatus();"<<std::endl;
1893  }
1894  if (GetShowToolTips()) {
1895  out<<" "<<GetName()<<"->ToggleToolTips();"<<std::endl;
1896  }
1897  if (GetHighLightColor() != 5) {
1898  if (GetHighLightColor() > 228) {
1899  TColor::SaveColor(out, GetHighLightColor());
1900  out<<" "<<GetName()<<"->SetHighLightColor(ci);" << std::endl;
1901  } else
1902  out<<" "<<GetName()<<"->SetHighLightColor("<<GetHighLightColor()<<");"<<std::endl;
1903  }
1904 
1905  // Now recursively scan all pads of this canvas
1906  cd();
1907  if (invalid) SetName("c1");
1908  TPad::SavePrimitive(out,option);
1909  // Write canvas options related to pad editor
1910  out<<" "<<GetName()<<"->SetSelected("<<GetName()<<");"<<std::endl;
1911  if (GetShowToolBar()) {
1912  out<<" "<<GetName()<<"->ToggleToolBar();"<<std::endl;
1913  }
1914  if (invalid) SetName(" ");
1915 
1916  out <<"}"<<std::endl;
1917  out.close();
1918  Info("SaveSource","C++ Macro file: %s has been generated", fname);
1919 
1920  // reset bit TClass::kClassSaved for all classes
1921  next.Reset();
1922  while((cl = (TClass*)next())) {
1923  cl->ResetBit(TClass::kClassSaved);
1924  }
1925  if (!lenfile) delete [] fname;
1926 }
1927 
1928 ////////////////////////////////////////////////////////////////////////////////
1929 /// Toggle batch mode. However, if the canvas is created without a window
1930 /// then batch mode always stays set.
1931 
1932 void TCanvas::SetBatch(Bool_t batch)
1933 {
1934  if (gROOT->IsBatch() || IsWeb())
1935  fBatch = kTRUE;
1936  else
1937  fBatch = batch;
1938 }
1939 
1940 ////////////////////////////////////////////////////////////////////////////////
1941 /// Set Width and Height of canvas to ww and wh respectively. If ww and/or wh
1942 /// are greater than the current canvas window a scroll bar is automatically
1943 /// generated. Use this function to zoom in a canvas and navigate via
1944 /// the scroll bars. The Width and Height in this method are different from those
1945 /// given in the TCanvas constructors where these two dimension include the size
1946 /// of the window decoration whereas they do not in this method.
1947 
1948 void TCanvas::SetCanvasSize(UInt_t ww, UInt_t wh)
1949 {
1950  if (fCanvasImp) {
1951  fCanvasImp->SetCanvasSize(ww, wh);
1952  fCw = ww;
1953  fCh = wh;
1954  ResizePad();
1955  }
1956 }
1957 
1958 ////////////////////////////////////////////////////////////////////////////////
1959 /// Set cursor.
1960 
1961 void TCanvas::SetCursor(ECursor cursor)
1962 {
1963  if (IsBatch()) return;
1964  gVirtualX->SetCursor(fCanvasID, cursor);
1965 }
1966 
1967 ////////////////////////////////////////////////////////////////////////////////
1968 /// Set Double Buffer On/Off.
1969 
1970 void TCanvas::SetDoubleBuffer(Int_t mode)
1971 {
1972  if (IsBatch()) return;
1973  fDoubleBuffer = mode;
1974  gVirtualX->SetDoubleBuffer(fCanvasID, mode);
1975 
1976  // depending of the buffer mode set the drawing window to either
1977  // the canvas pixmap or to the canvas on-screen window
1978  if (fDoubleBuffer) {
1979  if (fPixmapID != -1) fPainter->SelectDrawable(fPixmapID);
1980  } else
1981  if (fCanvasID != -1) fPainter->SelectDrawable(fCanvasID);
1982 }
1983 
1984 ////////////////////////////////////////////////////////////////////////////////
1985 /// Fix canvas aspect ratio to current value if fixed is true.
1986 
1987 void TCanvas::SetFixedAspectRatio(Bool_t fixed)
1988 {
1989  if (fixed) {
1990  if (!fFixedAspectRatio) {
1991  if (fCh != 0)
1992  fAspectRatio = Double_t(fCw) / fCh;
1993  else {
1994  Error("SetAspectRatio", "cannot fix aspect ratio, height of canvas is 0");
1995  return;
1996  }
1997  fFixedAspectRatio = kTRUE;
1998  }
1999  } else {
2000  fFixedAspectRatio = kFALSE;
2001  fAspectRatio = 0;
2002  }
2003 }
2004 
2005 ////////////////////////////////////////////////////////////////////////////////
2006 /// If isfolder=kTRUE, the canvas can be browsed like a folder
2007 /// by default a canvas is not browsable.
2008 
2009 void TCanvas::SetFolder(Bool_t isfolder)
2010 {
2011  fgIsFolder = isfolder;
2012 }
2013 
2014 ////////////////////////////////////////////////////////////////////////////////
2015 /// Set canvas name. In case `name` is an empty string, a default name is set.
2016 
2017 void TCanvas::SetName(const char *name)
2018 {
2019  if (!name || !name[0]) {
2020  const char *defcanvas = gROOT->GetDefCanvasName();
2021  char *cdef;
2022  auto lc = (TList*)gROOT->GetListOfCanvases();
2023  if (lc->FindObject(defcanvas)) {
2024  cdef = Form("%s_n%d",defcanvas,lc->GetSize()+1);
2025  } else {
2026  cdef = Form("%s",defcanvas);
2027  }
2028  fName = cdef;
2029  } else {
2030  fName = name;
2031  }
2032  if (gPad && TestBit(kMustCleanup)) gPad->Modified();
2033 }
2034 
2035 ////////////////////////////////////////////////////////////////////////////////
2036 /// Set selected canvas.
2037 
2038 void TCanvas::SetSelected(TObject *obj)
2039 {
2040  fSelected = obj;
2041  if (obj) obj->SetBit(kMustCleanup);
2042 }
2043 
2044 ////////////////////////////////////////////////////////////////////////////////
2045 /// Set canvas title.
2046 
2047 void TCanvas::SetTitle(const char *title)
2048 {
2049  fTitle = title;
2050  if (fCanvasImp) fCanvasImp->SetWindowTitle(title);
2051 }
2052 
2053 ////////////////////////////////////////////////////////////////////////////////
2054 /// Set the canvas scale in centimeters.
2055 ///
2056 /// This information is used by PostScript to set the page size.
2057 ///
2058 /// \param[in] xsize size of the canvas in centimeters along X
2059 /// \param[in] ysize size of the canvas in centimeters along Y
2060 ///
2061 /// if xsize and ysize are not equal to 0, then the scale factors will
2062 /// be computed to keep the ratio ysize/xsize independently of the canvas
2063 /// size (parts of the physical canvas will be unused).
2064 ///
2065 /// if xsize = 0 and ysize is not zero, then xsize will be computed
2066 /// to fit to the current canvas scale. If the canvas is resized,
2067 /// a new value for xsize will be recomputed. In this case the aspect
2068 /// ratio is not preserved.
2069 ///
2070 /// if both xsize = 0 and ysize = 0, then the scaling is automatic.
2071 /// the largest dimension will be allocated a size of 20 centimeters.
2072 
2073 void TCanvas::Size(Float_t xsize, Float_t ysize)
2074 {
2075  fXsizeUser = xsize;
2076  fYsizeUser = ysize;
2077 
2078  Resize();
2079 }
2080 
2081 ////////////////////////////////////////////////////////////////////////////////
2082 /// Stream a class object.
2083 
2084 void TCanvas::Streamer(TBuffer &b)
2085 {
2086  UInt_t R__s, R__c;
2087  if (b.IsReading()) {
2088  Version_t v = b.ReadVersion(&R__s, &R__c);
2089  gPad = this;
2090  fCanvas = this;
2091  if (v>7) b.ClassBegin(TCanvas::IsA());
2092  if (v>7) b.ClassMember("TPad");
2093  TPad::Streamer(b);
2094  gPad = this;
2095  //restore the colors
2096  TObjArray *colors = (TObjArray*)fPrimitives->FindObject("ListOfColors");
2097  if (colors) {
2098  TIter next(colors);
2099  TColor *colold;
2100  while ((colold = (TColor*)next())) {
2101  if (colold) {
2102  Int_t cn = 0;
2103  if (colold) cn = colold->GetNumber();
2104  TColor *colcur = gROOT->GetColor(cn);
2105  if (colcur) {
2106  colcur->SetRGB(colold->GetRed(),colold->GetGreen(),colold->GetBlue());
2107  } else {
2108  colcur = new TColor(cn,colold->GetRed(),
2109  colold->GetGreen(),
2110  colold->GetBlue(),
2111  colold->GetName());
2112  if (!colcur) return;
2113  }
2114  }
2115  }
2116  //restore the palette if needed
2117  TObjArray *currentpalette = (TObjArray*)fPrimitives->FindObject("CurrentColorPalette");
2118  if (currentpalette) {
2119  TIter nextpal(currentpalette);
2120  Int_t n = currentpalette->GetEntries();
2121  TArrayI palcolors(n);
2122  TColor *col = 0;
2123  Int_t i = 0;
2124  while ((col = (TColor*)nextpal())) palcolors[i++] = col->GetNumber();
2125  gStyle->SetPalette(n,palcolors.GetArray());
2126  fPrimitives->Remove(currentpalette);
2127  delete currentpalette;
2128  }
2129  fPrimitives->Remove(colors);
2130  colors->Delete();
2131  delete colors;
2132  }
2133 
2134  if (v>7) b.ClassMember("fDISPLAY","TString");
2135  fDISPLAY.Streamer(b);
2136  if (v>7) b.ClassMember("fDoubleBuffer", "Int_t");
2137  b >> fDoubleBuffer;
2138  if (v>7) b.ClassMember("fRetained", "Bool_t");
2139  b >> fRetained;
2140  if (v>7) b.ClassMember("fXsizeUser", "Size_t");
2141  b >> fXsizeUser;
2142  if (v>7) b.ClassMember("fYsizeUser", "Size_t");
2143  b >> fYsizeUser;
2144  if (v>7) b.ClassMember("fXsizeReal", "Size_t");
2145  b >> fXsizeReal;
2146  if (v>7) b.ClassMember("fYsizeReal", "Size_t");
2147  b >> fYsizeReal;
2148  fCanvasID = -1;
2149  if (v>7) b.ClassMember("fWindowTopX", "Int_t");
2150  b >> fWindowTopX;
2151  if (v>7) b.ClassMember("fWindowTopY", "Int_t");
2152  b >> fWindowTopY;
2153  if (v > 2) {
2154  if (v>7) b.ClassMember("fWindowWidth", "UInt_t");
2155  b >> fWindowWidth;
2156  if (v>7) b.ClassMember("fWindowHeight", "UInt_t");
2157  b >> fWindowHeight;
2158  }
2159  if (v>7) b.ClassMember("fCw", "UInt_t");
2160  b >> fCw;
2161  if (v>7) b.ClassMember("fCh", "UInt_t");
2162  b >> fCh;
2163  if (v <= 2) {
2164  fWindowWidth = fCw;
2165  fWindowHeight = fCh;
2166  }
2167  if (v>7) b.ClassMember("fCatt", "TAttCanvas");
2168  fCatt.Streamer(b);
2169  Bool_t dummy;
2170  if (v>7) b.ClassMember("kMoveOpaque", "Bool_t");
2171  b >> dummy; if (dummy) MoveOpaque(1);
2172  if (v>7) b.ClassMember("kResizeOpaque", "Bool_t");
2173  b >> dummy; if (dummy) ResizeOpaque(1);
2174  if (v>7) b.ClassMember("fHighLightColor", "Color_t");
2175  b >> fHighLightColor;
2176  if (v>7) b.ClassMember("fBatch", "Bool_t");
2177  b >> dummy; //was fBatch
2178  if (v < 2) return;
2179  if (v>7) b.ClassMember("kShowEventStatus", "Bool_t");
2180  b >> dummy; if (dummy) SetBit(kShowEventStatus);
2181 
2182  if (v > 3) {
2183  if (v>7) b.ClassMember("kAutoExec", "Bool_t");
2184  b >> dummy; if (dummy) SetBit(kAutoExec);
2185  }
2186  if (v>7) b.ClassMember("kMenuBar", "Bool_t");
2187  b >> dummy; if (dummy) SetBit(kMenuBar);
2188  fBatch = gROOT->IsBatch();
2189  if (v>7) b.ClassEnd(TCanvas::IsA());
2190  b.CheckByteCount(R__s, R__c, TCanvas::IsA());
2191  } else {
2192  //save list of colors
2193  //we must protect the case when two or more canvases are saved
2194  //in the same buffer. If the list of colors has already been saved
2195  //in the buffer, do not add the list of colors to the list of primitives.
2196  TObjArray *colors = 0;
2197  TObjArray *CurrentColorPalette = 0;
2198  if (TColor::DefinedColors()) {
2199  if (!b.CheckObject(gROOT->GetListOfColors(),TObjArray::Class())) {
2200  colors = (TObjArray*)gROOT->GetListOfColors();
2201  fPrimitives->Add(colors);
2202  }
2203  //save the current palette
2204  TArrayI pal = TColor::GetPalette();
2205  Int_t palsize = pal.GetSize();
2206  CurrentColorPalette = new TObjArray();
2207  CurrentColorPalette->SetName("CurrentColorPalette");
2208  for (Int_t i=0; i<palsize; i++) CurrentColorPalette->Add(gROOT->GetColor(pal[i]));
2209  fPrimitives->Add(CurrentColorPalette);
2210  }
2211 
2212  R__c = b.WriteVersion(TCanvas::IsA(), kTRUE);
2213  b.ClassBegin(TCanvas::IsA());
2214  b.ClassMember("TPad");
2215  TPad::Streamer(b);
2216  if (colors) fPrimitives->Remove(colors);
2217  if (CurrentColorPalette) { fPrimitives->Remove(CurrentColorPalette); delete CurrentColorPalette; }
2218  b.ClassMember("fDISPLAY","TString");
2219  fDISPLAY.Streamer(b);
2220  b.ClassMember("fDoubleBuffer", "Int_t");
2221  b << fDoubleBuffer;
2222  b.ClassMember("fRetained", "Bool_t");
2223  b << fRetained;
2224  b.ClassMember("fXsizeUser", "Size_t");
2225  b << fXsizeUser;
2226  b.ClassMember("fYsizeUser", "Size_t");
2227  b << fYsizeUser;
2228  b.ClassMember("fXsizeReal", "Size_t");
2229  b << fXsizeReal;
2230  b.ClassMember("fYsizeReal", "Size_t");
2231  b << fYsizeReal;
2232  UInt_t w = fWindowWidth, h = fWindowHeight;
2233  Int_t topx = fWindowTopX, topy = fWindowTopY;
2234  UInt_t editorWidth = 0;
2235  if(fCanvasImp) editorWidth = fCanvasImp->GetWindowGeometry(topx,topy,w,h);
2236  b.ClassMember("fWindowTopX", "Int_t");
2237  b << topx;
2238  b.ClassMember("fWindowTopY", "Int_t");
2239  b << topy;
2240  b.ClassMember("fWindowWidth", "UInt_t");
2241  b << (UInt_t)(w-editorWidth);
2242  b.ClassMember("fWindowHeight", "UInt_t");
2243  b << h;
2244  b.ClassMember("fCw", "UInt_t");
2245  b << fCw;
2246  b.ClassMember("fCh", "UInt_t");
2247  b << fCh;
2248  b.ClassMember("fCatt", "TAttCanvas");
2249  fCatt.Streamer(b);
2250  b.ClassMember("kMoveOpaque", "Bool_t");
2251  b << TestBit(kMoveOpaque); //please remove in ROOT version 6
2252  b.ClassMember("kResizeOpaque", "Bool_t");
2253  b << TestBit(kResizeOpaque); //please remove in ROOT version 6
2254  b.ClassMember("fHighLightColor", "Color_t");
2255  b << fHighLightColor;
2256  b.ClassMember("fBatch", "Bool_t");
2257  b << fBatch; //please remove in ROOT version 6
2258  b.ClassMember("kShowEventStatus", "Bool_t");
2259  b << TestBit(kShowEventStatus); //please remove in ROOT version 6
2260  b.ClassMember("kAutoExec", "Bool_t");
2261  b << TestBit(kAutoExec); //please remove in ROOT version 6
2262  b.ClassMember("kMenuBar", "Bool_t");
2263  b << TestBit(kMenuBar); //please remove in ROOT version 6
2264  b.ClassEnd(TCanvas::IsA());
2265  b.SetByteCount(R__c, kTRUE);
2266  }
2267 }
2268 
2269 ////////////////////////////////////////////////////////////////////////////////
2270 /// Toggle pad auto execution of list of TExecs.
2271 
2272 void TCanvas::ToggleAutoExec()
2273 {
2274  Bool_t autoExec = TestBit(kAutoExec);
2275  SetBit(kAutoExec,!autoExec);
2276 }
2277 
2278 ////////////////////////////////////////////////////////////////////////////////
2279 /// Toggle event statusbar.
2280 
2281 void TCanvas::ToggleEventStatus()
2282 {
2283  Bool_t showEventStatus = !TestBit(kShowEventStatus);
2284  SetBit(kShowEventStatus,showEventStatus);
2285 
2286  if (fCanvasImp) fCanvasImp->ShowStatusBar(showEventStatus);
2287 }
2288 
2289 ////////////////////////////////////////////////////////////////////////////////
2290 /// Toggle toolbar.
2291 
2292 void TCanvas::ToggleToolBar()
2293 {
2294  Bool_t showToolBar = !TestBit(kShowToolBar);
2295  SetBit(kShowToolBar,showToolBar);
2296 
2297  if (fCanvasImp) fCanvasImp->ShowToolBar(showToolBar);
2298 }
2299 
2300 ////////////////////////////////////////////////////////////////////////////////
2301 /// Toggle editor.
2302 
2303 void TCanvas::ToggleEditor()
2304 {
2305  Bool_t showEditor = !TestBit(kShowEditor);
2306  SetBit(kShowEditor,showEditor);
2307 
2308  if (fCanvasImp) fCanvasImp->ShowEditor(showEditor);
2309 }
2310 
2311 ////////////////////////////////////////////////////////////////////////////////
2312 /// Toggle tooltip display.
2313 
2314 void TCanvas::ToggleToolTips()
2315 {
2316  Bool_t showToolTips = !TestBit(kShowToolTips);
2317  SetBit(kShowToolTips, showToolTips);
2318 
2319  if (fCanvasImp) fCanvasImp->ShowToolTips(showToolTips);
2320 }
2321 
2322 
2323 ////////////////////////////////////////////////////////////////////////////////
2324 /// Static function returning "true" if transparency is supported.
2325 
2326 Bool_t TCanvas::SupportAlpha()
2327 {
2328  return gPad && (gVirtualX->InheritsFrom("TGQuartz") ||
2329  gPad->GetGLDevice() != -1);
2330 }
2331 
2332 extern "C" void ROOT_TCanvas_Update(void* TheCanvas) {
2333  static_cast<TCanvas*>(TheCanvas)->Update();
2334 }
2335 
2336 ////////////////////////////////////////////////////////////////////////////////
2337 /// Update canvas pad buffers.
2338 
2339 void TCanvas::Update()
2340 {
2341  if (fUpdating) return;
2342 
2343  if (fPixmapID == -1) return;
2344 
2345  static const union CastFromFuncToVoidPtr_t {
2346  CastFromFuncToVoidPtr_t(): fFuncPtr(ROOT_TCanvas_Update) {}
2347  void (*fFuncPtr)(void*);
2348  void* fVoidPtr;
2349  } castFromFuncToVoidPtr;
2350 
2351  if (gThreadXAR) {
2352  void *arr[3];
2353  arr[1] = this;
2354  arr[2] = castFromFuncToVoidPtr.fVoidPtr;
2355  if ((*gThreadXAR)("CUPD", 3, arr, 0)) return;
2356  }
2357 
2358  if (!fCanvasImp) return;
2359 
2360  if (!gVirtualX->IsCmdThread()) {
2361  // Why do we have this (which uses the interpreter to funnel the Update()
2362  // through the main thread) when the gThreadXAR mechanism does seemingly
2363  // the same?
2364  gInterpreter->Execute(this, IsA(), "Update", "");
2365  return;
2366  }
2367 
2368  R__LOCKGUARD(gROOTMutex);
2369 
2370  fUpdating = kTRUE;
2371 
2372  if (!fCanvasImp->PerformUpdate()) {
2373 
2374  if (!IsBatch()) FeedbackMode(kFALSE); // Goto double buffer mode
2375 
2376  if (!UseGL()) PaintModified(); // Repaint all modified pad's
2377 
2378  Flush(); // Copy all pad pixmaps to the screen
2379 
2380  SetCursor(kCross);
2381  }
2382 
2383  fUpdating = kFALSE;
2384 }
2385 
2386 ////////////////////////////////////////////////////////////////////////////////
2387 /// Used by friend class TCanvasImp.
2388 
2389 void TCanvas::DisconnectWidget()
2390 {
2391  fCanvasID = 0;
2392  fContextMenu = 0;
2393 }
2394 
2395 ////////////////////////////////////////////////////////////////////////////////
2396 /// Check whether this canvas is to be drawn in grayscale mode.
2397 
2398 Bool_t TCanvas::IsGrayscale()
2399 {
2400  return TestBit(kIsGrayscale);
2401 }
2402 
2403 ////////////////////////////////////////////////////////////////////////////////
2404 /// Set whether this canvas should be painted in grayscale, and re-paint
2405 /// it if necessary.
2406 
2407 void TCanvas::SetGrayscale(Bool_t set /*= kTRUE*/)
2408 {
2409  if (IsGrayscale() == set) return;
2410  SetBit(kIsGrayscale, set);
2411  Paint(); // update canvas and all sub-pads, unconditionally!
2412 }
2413 
2414 ////////////////////////////////////////////////////////////////////////////////
2415 /// Probably, TPadPainter must be placed in a separate ROOT module -
2416 /// "padpainter" (the same as "histpainter"). But now, it's directly in a
2417 /// gpad dir, so, in case of default painter, no *.so should be loaded,
2418 /// no need in plugin managers.
2419 /// May change in future.
2420 
2421 void TCanvas::CreatePainter()
2422 {
2423  //Even for batch mode painter is still required, just to delegate
2424  //some calls to batch "virtual X".
2425  if (!UseGL() || fBatch) {
2426  fPainter = 0;
2427  if (fCanvasImp) fPainter = fCanvasImp->CreatePadPainter();
2428  if (!fPainter) fPainter = new TPadPainter; // Do not need plugin manager for this!
2429  } else {
2430  fPainter = TVirtualPadPainter::PadPainter("gl");
2431  if (!fPainter) {
2432  Error("CreatePainter", "GL Painter creation failed! Will use default!");
2433  fPainter = new TPadPainter;
2434  fUseGL = kFALSE;
2435  }
2436  }
2437 }
2438 
2439 ////////////////////////////////////////////////////////////////////////////////
2440 /// Access and (probably) creation of pad painter.
2441 
2442 TVirtualPadPainter *TCanvas::GetCanvasPainter()
2443 {
2444  if (!fPainter) CreatePainter();
2445  return fPainter;
2446 }
2447 
2448 
2449 ////////////////////////////////////////////////////////////////////////////////
2450 ///assert on IsBatch() == false?
2451 
2452 void TCanvas::DeleteCanvasPainter()
2453 {
2454  if (fGLDevice != -1) {
2455  //fPainter has a font manager.
2456  //Font manager will delete textures.
2457  //If context is wrong (we can have several canvases) -
2458  //wrong texture will be deleted, damaging some of our fonts.
2459  gGLManager->MakeCurrent(fGLDevice);
2460  }
2461 
2462  delete fPainter;
2463  fPainter = 0;
2464 
2465  if (fGLDevice != -1) {
2466  gGLManager->DeleteGLContext(fGLDevice);//?
2467  fGLDevice = -1;
2468  }
2469 }