// @(#)root/gpad:$Id: TCanvas.cxx 20882 2007-11-19 11:31:26Z rdm $
// Author: Rene Brun   12/12/94

/*************************************************************************
 * Copyright (C) 1995-2000, Rene Brun and Fons Rademakers.               *
 * All rights reserved.                                                  *
 *                                                                       *
 * For the licensing terms see $ROOTSYS/LICENSE.                         *
 * For the list of contributors see $ROOTSYS/README/CREDITS.             *
 *************************************************************************/

#include <string.h>
#include <stdlib.h>

#include "Riostream.h"
#include "TROOT.h"
#include "TCanvas.h"
#include "TClass.h"
#include "TStyle.h"
#include "TText.h"
#include "TBox.h"
#include "TCanvasImp.h"
#include "TDialogCanvas.h"
#include "TGuiFactory.h"
#include "TEnv.h"
#include "TError.h"
#include "TContextMenu.h"
#include "TControlBar.h"
#include "TInterpreter.h"
#include "TApplication.h"
#include "TColor.h"
#include "TVirtualPadEditor.h"
#include "TVirtualViewer3D.h"
#include "TVirtualGL.h"
#include "TObjectSpy.h"


class TCanvasInit {
public:
   TCanvasInit() { TApplication::NeedGraphicsLibs(); }
};
static TCanvasInit gCanvasInit;


//*-*x16 macros/layout_canvas

Bool_t TCanvas::fgIsFolder = kFALSE;

const Size_t kDefaultCanvasSize   = 20;

ClassImpQ(TCanvas)


//______________________________________________________________________________
//
//   A Canvas is an area mapped to a window directly under
//   the control of the display manager.
//   A ROOT session may have several canvases open at any given time.
//
//   A Canvas may be subdivided into independent graphical areas: the PADs
//   A canvas has a default pad which has the name of the canvas itself.
//   An example of a Canvas layout is sketched in the picture below.
//
//   ***********************************************************************
//   *          Tool Bar menus    for Canvas                               *
//   ***********************************************************************
//   *                                                                     *
//   *  ************************************    *************************  *
//   *  *                                  *    *                       *  *
//   *  *                                  *    *                       *  *
//   *  *                                  *    *                       *  *
//   *  *                                  *    *                       *  *
//   *  *                                  *    *                       *  *
//   *  *                                  *    *                       *  *
//   *  *              P1                  *    *        P2             *  *
//   *  *                                  *    *                       *  *
//   *  *                                  *    *                       *  *
//   *  *                                  *    *                       *  *
//   *  *                                  *    *                       *  *
//   *  *                                  *    *                       *  *
//   *  *                                  *    *                       *  *
//   *  ************************************    *************************  *
//   *                                                                     *
//   ***********************************************************************
//
//   This canvas contains two pads named P1 and P2.
//   Both Canvas, P1 and P2 can be moved, grown, shrinked using the
//   normal rules of the Display manager.
//   A copy of a real canvas with 4 pads is shown in the picture below.
//Begin_Html
/*
<img src="gif/canvas_layout.gif">
*/
//End_Html
//
//  Once objects have been drawn in a canvas, they can be edited/moved
//  by pointing directly to them. The cursor shape is changed
//  to suggest the type of action that one can do on this object.
//  Clicking with the right mouse button on an object pops-up
//  a contextmenu with a complete list of actions possible on this object.
//
//  A graphical editor may be started from the canvas "View" menu.
//  An interactive HELP is available by clicking on the HELP button
//  at the top right of the canvas.
//
//  A canvas may be automatically divided into pads via TPad::Divide.
//


//______________________________________________________________________________
TCanvas::TCanvas(Bool_t build) : TPad()
{
   // Canvas default constructor.

   fUseGL = kFALSE;
   if (!build || TClass::IsCallingNew()) {
      Constructor();
   } else {
      const char *defcanvas = gROOT->GetDefCanvasName();
      char *cdef;

      TList *lc = (TList*)gROOT->GetListOfCanvases();
      if (lc->FindObject(defcanvas))
         cdef = StrDup(Form("%s_n%d",defcanvas,lc->GetSize()+1));
      else
         cdef = StrDup(Form("%s",defcanvas));
      Constructor(cdef, cdef, 1);
      delete [] cdef;
   }
}


//______________________________________________________________________________
void TCanvas::Constructor()
{
   // Canvas default constructor

   if (gThreadXAR) {
      void *arr[2];
      arr[1] = this;
      if ((*gThreadXAR)("CANV", 2, arr, 0)) return;
   }

   fCanvas    = 0;
   fCanvasID  = -1;
   fCanvasImp = 0;
   fBatch     = kTRUE;
   fUpdating  = kFALSE;

   fContextMenu   = 0;
   fSelected      = 0;
   fClickSelected = 0;
   fSelectedPad   = 0;
   fClickSelectedPad = 0;
   fPadSave       = 0;
   SetBit(kAutoExec);
   SetBit(kShowEditor);
   SetBit(kShowToolBar);
}


//______________________________________________________________________________
TCanvas::TCanvas(const char *name, Int_t ww, Int_t wh, Int_t winid)
{
   // Create an embedded canvas, i.e. a canvas that is in a TGCanvas widget
   // which is placed in a TGFrame. This ctor is only called via the
   // TRootEmbeddedCanvas class.

   Init();

   fUseGL = name && strstr(name, "gl") || gStyle->GetCanvasPreferGL()? kTRUE : kFALSE;

   fCanvasID     = winid;
   fWindowTopX   = 0;
   fWindowTopY   = 0;
   fWindowWidth  = ww;
   fWindowHeight = wh;
   fCw           = ww + 4;
   fCh           = wh +28;
   fBatch        = kFALSE;
   fUpdating     = kFALSE;

   fCanvasImp    = gBatchGuiFactory->CreateCanvasImp(this, name, fCw, fCh);
   SetName(name);
   Build();
}


//_____________________________________________________________________________
TCanvas::TCanvas(const char *name, const char *title, Int_t form) : TPad()
{
   //  Create a new canvas with a predefined size form.
   //  If form < 0  the menubar is not shown.
   //
   //  form = 1    700x500 at 10,10 (set by TStyle::SetCanvasDefH,W,X,Y)
   //  form = 2    500x500 at 20,20
   //  form = 3    500x500 at 30,30
   //  form = 4    500x500 at 40,40
   //  form = 5    500x500 at 50,50
   fUseGL = name && strstr(name, "gl") || gStyle->GetCanvasPreferGL()? kTRUE : kFALSE;

   Constructor(name, title, form);
}


//_____________________________________________________________________________
void TCanvas::Constructor(const char *name, const char *title, Int_t form)
{
   //  Create a new canvas with a predefined size form.
   //  If form < 0  the menubar is not shown.
   //
   //  form = 1    700x500 at 10,10 (set by TStyle::SetCanvasDefH,W,X,Y)
   //  form = 2    500x500 at 20,20
   //  form = 3    500x500 at 30,30
   //  form = 4    500x500 at 40,40
   //  form = 5    500x500 at 50,50

   if (gThreadXAR) {
      void *arr[6];
      static Int_t ww = 500;
      static Int_t wh = 500;
      arr[1] = this; arr[2] = (void*)name; arr[3] = (void*)title; arr[4] =&ww; arr[5] = &wh;
      if ((*gThreadXAR)("CANV", 6, arr, 0)) return;
   }

   Init();
   SetBit(kMenuBar,1);
   if (form < 0) {
      form     = -form;
      SetBit(kMenuBar,0);
   }
   fCanvasID = -1;
   TCanvas *old = (TCanvas*)gROOT->GetListOfCanvases()->FindObject(name);
   if (old && old->IsOnHeap()) delete old;
   if (strlen(name) == 0 || gROOT->IsBatch()) {   //We are in Batch mode
      fWindowTopX   = fWindowTopY = 0;
      fWindowWidth  = gStyle->GetCanvasDefW()-4;
      fWindowHeight = gStyle->GetCanvasDefH()-28;
      fCw           = fWindowWidth;
      fCh           = fWindowHeight;
      fCanvasImp    = gBatchGuiFactory->CreateCanvasImp(this, name, fCw, fCh);
      fBatch        = kTRUE;
   } else {                  //normal mode with a screen window
      Float_t cx = gStyle->GetScreenFactor();
      if (form < 1 || form > 5) form = 1;
      if (form == 1) {
         UInt_t uh = UInt_t(cx*gStyle->GetCanvasDefH());
         UInt_t uw = UInt_t(cx*gStyle->GetCanvasDefW());
         Int_t  ux = Int_t(cx*gStyle->GetCanvasDefX());
         Int_t  uy = Int_t(cx*gStyle->GetCanvasDefY());
         fCanvasImp = gGuiFactory->CreateCanvasImp(this, name, ux, uy, uw, uh);
      }
      fCw = 500;
      fCh = 500;
      if (form == 2) fCanvasImp = gGuiFactory->CreateCanvasImp(this, name, 20, 20, UInt_t(cx*500), UInt_t(cx*500));
      if (form == 3) fCanvasImp = gGuiFactory->CreateCanvasImp(this, name, 30, 30, UInt_t(cx*500), UInt_t(cx*500));
      if (form == 4) fCanvasImp = gGuiFactory->CreateCanvasImp(this, name, 40, 40, UInt_t(cx*500), UInt_t(cx*500));
      if (form == 5) fCanvasImp = gGuiFactory->CreateCanvasImp(this, name, 50, 50, UInt_t(cx*500), UInt_t(cx*500));
      fCanvasImp->ShowMenuBar(TestBit(kMenuBar));
      fBatch = kFALSE;
   }
   SetName(name);
   SetTitle(title); // requires fCanvasImp set
   Build();

   // Popup canvas
   fCanvasImp->Show();
}


//_____________________________________________________________________________
TCanvas::TCanvas(const char *name, const char *title, Int_t ww, Int_t wh) : TPad()
{
   //  Create a new canvas at a random position.
   //
   //  ww is the canvas size in pixels along X
   //      (if ww < 0  the menubar is not shown)
   //  wh is the canvas size in pixels along Y
   fUseGL = name && strstr(name, "gl") || gStyle->GetCanvasPreferGL()? kTRUE : kFALSE;

   Constructor(name, title, ww, wh);
}


//_____________________________________________________________________________
void TCanvas::Constructor(const char *name, const char *title, Int_t ww, Int_t wh)
{
   //  Create a new canvas at a random position.
   //
   //  ww is the canvas size in pixels along X
   //      (if ww < 0  the menubar is not shown)
   //  wh is the canvas size in pixels along Y

   if (gThreadXAR) {
      void *arr[6];
      arr[1] = this; arr[2] = (void*)name; arr[3] = (void*)title; arr[4] =&ww; arr[5] = &wh;
      if ((*gThreadXAR)("CANV", 6, arr, 0)) return;
   }

   Init();
   SetBit(kMenuBar,1);
   if (ww < 0) {
      ww       = -ww;
      SetBit(kMenuBar,0);
   }
   fCw       = ww;
   fCh       = wh;
   fCanvasID = -1;
   TCanvas *old = (TCanvas*)gROOT->GetListOfCanvases()->FindObject(name);
   if (old && old->IsOnHeap()) delete old;
   if (strlen(name) == 0 || gROOT->IsBatch()) {   //We are in Batch mode
      fWindowTopX   = fWindowTopY = 0;
      fWindowWidth  = ww;
      fWindowHeight = wh;
      fCw           = ww;
      fCh           = wh;
      fCanvasImp    = gBatchGuiFactory->CreateCanvasImp(this, name, fCw, fCh);
      fBatch        = kTRUE;
   } else {
      Float_t cx = gStyle->GetScreenFactor();
      fCanvasImp = gGuiFactory->CreateCanvasImp(this, name, UInt_t(cx*ww), UInt_t(cx*wh));
      fCanvasImp->ShowMenuBar(TestBit(kMenuBar));
      fBatch = kFALSE;
   }
   SetName(name);
   SetTitle(title); // requires fCanvasImp set
   Build();

   // Popup canvas
   fCanvasImp->Show();
}


//_____________________________________________________________________________
TCanvas::TCanvas(const char *name, const char *title, Int_t wtopx, Int_t wtopy, Int_t ww, Int_t wh)
        : TPad()
{
   //  Create a new canvas.
   //
   //  wtopx,wtopy are the pixel coordinates of the top left corner of
   //  the canvas (if wtopx < 0) the menubar is not shown)
   //  ww is the canvas size in pixels along X
   //  wh is the canvas size in pixels along Y
   fUseGL = name && strstr(name, "gl") || gStyle->GetCanvasPreferGL()? kTRUE : kFALSE;

   Constructor(name, title, wtopx, wtopy, ww, wh);
}


//_____________________________________________________________________________
void TCanvas::Constructor(const char *name, const char *title, Int_t wtopx,
                          Int_t wtopy, Int_t ww, Int_t wh)
{
   //  Create a new canvas.
   //
   //  wtopx,wtopy are the pixel coordinates of the top left corner of
   //  the canvas (if wtopx < 0) the menubar is not shown)
   //  ww is the canvas size in pixels along X
   //  wh is the canvas size in pixels along Y

   if (gThreadXAR) {
      void *arr[8];
      arr[1] = this;   arr[2] = (void*)name;   arr[3] = (void*)title;
      arr[4] = &wtopx; arr[5] = &wtopy; arr[6] = &ww; arr[7] = &wh;
      if ((*gThreadXAR)("CANV", 8, arr, 0)) return;
   }

   Init();
   SetBit(kMenuBar,1);
   if (wtopx < 0) {
      wtopx    = -wtopx;
      SetBit(kMenuBar,0);
   }
   fCw       = ww;
   fCh       = wh;
   fCanvasID = -1;
   TCanvas *old = (TCanvas*)gROOT->GetListOfCanvases()->FindObject(name);
   if (old && old->IsOnHeap()) delete old;
   if (strlen(name) == 0 || gROOT->IsBatch()) {   //We are in Batch mode
      fWindowTopX   = fWindowTopY = 0;
      fWindowWidth  = ww;
      fWindowHeight = wh;
      fCw           = ww;
      fCh           = wh;
      fCanvasImp    = gBatchGuiFactory->CreateCanvasImp(this, name, fCw, fCh);
      fBatch        = kTRUE;
   } else {                   //normal mode with a screen window
      Float_t cx = gStyle->GetScreenFactor();
      fCanvasImp = gGuiFactory->CreateCanvasImp(this, name, Int_t(cx*wtopx), Int_t(cx*wtopy), UInt_t(cx*ww), UInt_t(cx*wh));
      fCanvasImp->ShowMenuBar(TestBit(kMenuBar));
      fBatch = kFALSE;
   }
   SetName(name);
   SetTitle(title); // requires fCanvasImp set
   Build();

   // Popup canvas
   fCanvasImp->Show();
}


//_____________________________________________________________________________
void TCanvas::Init()
{
   // Initialize the TCanvas members. Called by all constructors.

   // Make sure the application environment exists. It is need for graphics
   // (colors are initialized in the TApplication ctor).
   if (!gApplication)
      TApplication::CreateApplication();

   // Get some default from .rootrc. Used in fCanvasImp->InitWindow().
   fHighLightColor     = gEnv->GetValue("Canvas.HighLightColor", kRed);
   SetBit(kMoveOpaque,   gEnv->GetValue("Canvas.MoveOpaque", 0));
   SetBit(kResizeOpaque, gEnv->GetValue("Canvas.ResizeOpaque", 0));
   if (gEnv->GetValue("Canvas.ShowEventStatus", kFALSE)) SetBit(kShowEventStatus);
   if (gEnv->GetValue("Canvas.ShowToolBar", kFALSE)) SetBit(kShowToolBar);
   if (gEnv->GetValue("Canvas.ShowEditor", kFALSE)) SetBit(kShowEditor);
   if (gEnv->GetValue("Canvas.AutoExec", kTRUE)) SetBit(kAutoExec);

   // Fill canvas ROOT data structure
   fXsizeUser = 0;
   fYsizeUser = 0;
   fXsizeReal = kDefaultCanvasSize;
   fYsizeReal = kDefaultCanvasSize;

   fDISPLAY         = "$DISPLAY";
   fUpdating        = kFALSE;
   fRetained        = kTRUE;
   fSelected        = 0;
   fClickSelected   = 0;
   fSelectedX       = 0;
   fSelectedY       = 0;
   fSelectedPad     = 0;
   fClickSelectedPad= 0;
   fPadSave         = 0;
   fEvent           = -1;
   fEventX          = -1;
   fEventY          = -1;
   fContextMenu     = 0;
}


//_____________________________________________________________________________
void TCanvas::Build()
{
   // Build a canvas. Called by all constructors.

   // Get window identifier
   if (fCanvasID == -1 && fCanvasImp)
      fCanvasID = fCanvasImp->InitWindow();
   if (fCanvasID == -1) return;

   if (fCw < fCh) fXsizeReal = fYsizeReal*Float_t(fCw)/Float_t(fCh);
   else           fYsizeReal = fXsizeReal*Float_t(fCh)/Float_t(fCw);

   // Set Pad parameters
   gPad            = this;
   fCanvas         = this;
   fMother         = (TPad*)gPad;

   if (!IsBatch()) {    //normal mode with a screen window
      // Set default physical canvas attributes
      gVirtualX->SelectWindow(fCanvasID);
      gVirtualX->SetFillColor(1);         //Set color index for fill area
      gVirtualX->SetLineColor(1);         //Set color index for lines
      gVirtualX->SetMarkerColor(1);       //Set color index for markers
      gVirtualX->SetTextColor(1);         //Set color index for text

      // Clear workstation
      gVirtualX->ClearWindow();

      // Set Double Buffer on by default
      SetDoubleBuffer(1);

      // Get effective window parameters (with borders and menubar)
      fCanvasImp->GetWindowGeometry(fWindowTopX, fWindowTopY,
                                    fWindowWidth, fWindowHeight);

      // Get effective canvas parameters without borders
      Int_t dum1, dum2;
      gVirtualX->GetGeometry(fCanvasID, dum1, dum2, fCw, fCh);

      fContextMenu = new TContextMenu("ContextMenu");
   } else {
      // Make sure that batch interactive canvas sizes are the same
      fCw -= 4;
      fCh -= 28;
   }
   gROOT->GetListOfCanvases()->Add(this);

   if (!fPrimitives) {
      fPrimitives     = new TList;
      SetFillColor(gStyle->GetCanvasColor());
      SetFillStyle(1001);
      SetGrid(gStyle->GetPadGridX(),gStyle->GetPadGridY());
      SetTicks(gStyle->GetPadTickX(),gStyle->GetPadTickY());
      SetLogx(gStyle->GetOptLogx());
      SetLogy(gStyle->GetOptLogy());
      SetLogz(gStyle->GetOptLogz());
      SetBottomMargin(gStyle->GetPadBottomMargin());
      SetTopMargin(gStyle->GetPadTopMargin());
      SetLeftMargin(gStyle->GetPadLeftMargin());
      SetRightMargin(gStyle->GetPadRightMargin());
      SetBorderSize(gStyle->GetCanvasBorderSize());
      SetBorderMode(gStyle->GetCanvasBorderMode());
      fBorderMode=gStyle->GetCanvasBorderMode(); // do not call SetBorderMode (function redefined in TCanvas)
      SetPad(0, 0, 1, 1);
      Range(0, 0, 1, 1);   //pad range is set by default to [0,1] in x and y
      gVirtualX->SelectPixmap(fPixmapID);    //pixmap must be selected
      PaintBorder(GetFillColor(), kTRUE);    //paint background
   }

   // transient canvases have typically no menubar and should not get
   // by default the event status bar (if set by default)
   if (TestBit(kMenuBar) && fCanvasImp) {
      if (TestBit(kShowEventStatus)) fCanvasImp->ShowStatusBar(kTRUE);
      // ... and toolbar + editor
      if (TestBit(kShowToolBar))     fCanvasImp->ShowToolBar(kTRUE);
      if (TestBit(kShowEditor))      fCanvasImp->ShowEditor(kTRUE);
   }
}


//______________________________________________________________________________
TCanvas::TCanvas(const TCanvas &) : TPad()
{
   // Intentionally not implemented
}


//______________________________________________________________________________
TCanvas::~TCanvas()
{
   // Canvas destructor

   Destructor();
}


//______________________________________________________________________________
void TCanvas::Browse(TBrowser *b)
{
   // Browse.

   Draw();
   cd();
   if (fgIsFolder) fPrimitives->Browse(b);
}


//______________________________________________________________________________
void TCanvas::Destructor()
{
   // Actual canvas destructor.

   if (gThreadXAR) {
      void *arr[2];
      arr[1] = this;
      if ((*gThreadXAR)("CDEL", 2, arr, 0)) return;
   }

   if (!TestBit(kNotDeleted)) return;

   if (fContextMenu) { delete fContextMenu; fContextMenu = 0; }
   if (!gPad) return;

   Close();
}


//______________________________________________________________________________
TVirtualPad *TCanvas::cd(Int_t subpadnumber)
{
   // Set current canvas & pad. Returns the new current pad,
   // or 0 in case of failure.
   // See TPad::cd() for an explanation of the parameter.

   if (fCanvasID == -1) return 0;

   TPad::cd(subpadnumber);

   // in case doublebuffer is off, draw directly onto display window
   if (!IsBatch()) {
      if (!fDoubleBuffer)
         gVirtualX->SelectWindow(fCanvasID);
   }
   return gPad;
}


//______________________________________________________________________________
void TCanvas::Clear(Option_t *option)
{
   // Remove all primitives from the canvas.
   // If option "D" is specified, direct subpads are cleared but not deleted.
   // This option is not recursive, i.e. pads in direct subpads are deleted.

   if (fCanvasID == -1) return;

   if ((!gROOT->IsLineProcessing()) && (!gVirtualX->IsCmdThread())) {
      gInterpreter->Execute(this, IsA(), "Clear", option);
      return;
   }

   TString opt = option;
   opt.ToLower();
   if (opt.Contains("d")) {
      // clear subpads, but do not delete pads in case the canvas
      // has been divided (note: option "D" is propagated so could cause
      // conflicts for primitives using option "D" for something else)
      if (fPrimitives) {
         TIter next(fPrimitives);
         TObject *obj;
         while ((obj=next())) {
            obj->Clear(option);
         }
      }
   } else {
      //default, clear everything in the canvas. Subpads are deleted
      TPad::Clear(option);   //Remove primitives from pad
   }

   fSelected      = 0;
   fClickSelected = 0;
   fSelectedPad   = 0;
   fClickSelectedPad = 0;
}


//______________________________________________________________________________
void TCanvas::Cleared(TVirtualPad *pad)
{
   // emit pad Cleared signal

   Emit("Cleared(TVirtualPad*)", (Long_t)pad);
}


//______________________________________________________________________________
void TCanvas::Closed()
{
   // emit Closed signal

   Emit("Closed()");
}


//______________________________________________________________________________
void TCanvas::Close(Option_t *option)
{
   // Close canvas.
   //
   //  Delete window/pads data structure

   TPad    *padsave = (TPad*)gPad;
   TCanvas *cansave = 0;
   if (padsave) cansave = (TCanvas*)gPad->GetCanvas();

   if (fCanvasID == -1) goto deletepad;

   if ((!gROOT->IsLineProcessing()) && (!gVirtualX->IsCmdThread())) {
      gInterpreter->Execute(this, IsA(), "Close", option);
      return;
   }

   FeedbackMode(kFALSE);

   TPad::Close(option);

   if (!IsBatch()) {
      gVirtualX->SelectWindow(fCanvasID);    //select current canvas
      if (fCanvasImp) fCanvasImp->Close();
   }
   fCanvasID = -1;
   fBatch    = kTRUE;

   gROOT->GetListOfCanvases()->Remove(this);

   // Close actual window on screen
   SafeDelete(fCanvasImp);

deletepad:
   if (cansave == this) {
      gPad = (TCanvas *) gROOT->GetListOfCanvases()->First();
   } else {
      gPad = padsave;
   }

   Closed();
}


//______________________________________________________________________________
void TCanvas::CopyPixmaps()
{
   // Copy the canvas pixmap of the pad to the canvas.

   if (!IsBatch()) {
      CopyPixmap();
      TPad::CopyPixmaps();
   }
}


//______________________________________________________________________________
void TCanvas::Draw(Option_t *)
{
   //  Draw a canvas.
   //  If a canvas with the name is already on the screen, the canvas is repainted.
   //  This function is useful when a canvas object has been saved in a Root file.
   //  One can then do:
   //     Root > Tfile f("file.root");
   //     Root > canvas.Draw();

   TCanvas *old = (TCanvas*)gROOT->GetListOfCanvases()->FindObject(GetName());
   if (old == this) {
      Paint();
      return;
   }
   if (old) { gROOT->GetListOfCanvases()->Remove(old); delete old;}

   if (fWindowWidth  == 0) fWindowWidth  = 800;
   if (fWindowHeight == 0) fWindowHeight = 600;
   fCanvasImp = gGuiFactory->CreateCanvasImp(this, GetName(), fWindowTopX, fWindowTopY,
                                             fWindowWidth, fWindowHeight);
   fCanvasImp->ShowMenuBar(TestBit(kMenuBar));

   Build();
   ResizePad();
   fCanvasImp->Show();
   Modified();
}


//______________________________________________________________________________
TObject *TCanvas::DrawClone(Option_t *option) const
{
   // Draw a clone of this canvas
   // A new canvas is created that is a clone of this canvas

   const char *defcanvas = gROOT->GetDefCanvasName();
   char *cdef;

   TList *lc = (TList*)gROOT->GetListOfCanvases();
   if (lc->FindObject(defcanvas))
      cdef = Form("%s_n%d",defcanvas,lc->GetSize()+1);
   else
      cdef = Form("%s",defcanvas);

   TCanvas *newCanvas = (TCanvas*)Clone();
   newCanvas->SetName(cdef);

   newCanvas->Draw(option);
   newCanvas->Update();
   return newCanvas;
}


//______________________________________________________________________________
TObject *TCanvas::DrawClonePad()
{
   // Draw a clone of this canvas into the current pad
   // In an interactive session, select the destination/current pad
   // with the middle mouse button, then point to the canvas area to select
   // the canvas context menu item DrawClonePad.
   // Note that the original canvas may have subpads.

   TPad *padsav = (TPad*)gPad;
   TPad *selpad = (TPad*)gROOT->GetSelectedPad();
   TPad *pad = padsav;
   if (pad == this) pad = selpad;
   if (padsav == 0 || pad == 0 || pad == this) {
      return DrawClone();
   }
   if (fCanvasID == -1) {
      fCanvasImp = gGuiFactory->CreateCanvasImp(this, GetName(), fWindowTopX, fWindowTopY,
                                             fWindowWidth, fWindowHeight);
      fCanvasImp->ShowMenuBar(TestBit(kMenuBar));
      fCanvasID = fCanvasImp->InitWindow();
   }
   this->cd();
   TObject *obj, *clone;
   //copy pad attributes
   pad->Range(fX1,fY1,fX2,fY2);
   pad->SetTickx(GetTickx());
   pad->SetTicky(GetTicky());
   pad->SetGridx(GetGridx());
   pad->SetGridy(GetGridy());
   pad->SetLogx(GetLogx());
   pad->SetLogy(GetLogy());
   pad->SetLogz(GetLogz());
   pad->SetBorderSize(GetBorderSize());
   pad->SetBorderMode(GetBorderMode());
   TAttLine::Copy((TAttLine&)*pad);
   TAttFill::Copy((TAttFill&)*pad);
   TAttPad::Copy((TAttPad&)*pad);

   //copy primitives
   TIter next(GetListOfPrimitives());
   while ((obj=next())) {
      pad->cd();
      clone = obj->Clone();
      pad->GetListOfPrimitives()->Add(clone,next.GetOption());
   }
   pad->ResizePad();
   pad->Modified();
   pad->Update();
   if (padsav) padsav->cd();
   return 0;
}


//______________________________________________________________________________
void TCanvas::DrawEventStatus(Int_t event, Int_t px, Int_t py, TObject *selected)
{
   // Report name and title of primitive below the cursor.
   //
   //    This function is called when the option "Event Status"
   //    in the canvas menu "Options" is selected.

   const Int_t kTMAX=256;
   static char atext[kTMAX];

   if (!TestBit(kShowEventStatus) || !selected) return;

   if (!fCanvasImp) return; //this may happen when closing a TAttCanvas

   TVirtualPad* savepad;
   savepad = gPad;
   gPad = GetSelectedPad();

   fCanvasImp->SetStatusText(selected->GetTitle(),0);
   fCanvasImp->SetStatusText(selected->GetName(),1);
   if (event == kKeyPress)
      sprintf(atext, "%c", (char) px);
   else
      sprintf(atext, "%d,%d", px, py);
   fCanvasImp->SetStatusText(atext,2);
   fCanvasImp->SetStatusText(selected->GetObjectInfo(px,py),3);
   gPad = savepad;
}


//______________________________________________________________________________
void TCanvas::EditorBar()
{
   // Get editor bar.

   TVirtualPadEditor::GetPadEditor();
}


//______________________________________________________________________________
void TCanvas::EmbedInto(Int_t winid, Int_t ww, Int_t wh)
{
   // Embedded a canvas into a TRootEmbeddedCanvas. This method is only called
   // via TRootEmbeddedCanvas::AdoptCanvas.

   // If fCanvasImp already exists, no need to go further.
   if(fCanvasImp) return;

   fCanvasID     = winid;
   fWindowTopX   = 0;
   fWindowTopY   = 0;
   fWindowWidth  = ww;
   fWindowHeight = wh;
   fCw           = ww;
   fCh           = wh;
   fBatch        = kFALSE;
   fUpdating     = kFALSE;

   fCanvasImp    = gBatchGuiFactory->CreateCanvasImp(this, GetName(), fCw, fCh);
   Build();
   Resize();
}


//______________________________________________________________________________
void TCanvas::EnterLeave(TPad *prevSelPad, TObject *prevSelObj)
{
   // Generate kMouseEnter and kMouseLeave events depending on the previously
   // selected object and the currently selected object. Does nothing if the
   // selected object does not change.

   if (prevSelObj == fSelected) return;

   TPad *padsav = (TPad *)gPad;
   Int_t sevent = fEvent;

   if (prevSelObj) {
      gPad = prevSelPad;
      prevSelObj->ExecuteEvent(kMouseLeave, fEventX, fEventY);
      fEvent = kMouseLeave;
      RunAutoExec();
      ProcessedEvent(kMouseLeave, fEventX, fEventY, prevSelObj);  // emit signal
   }

   gPad = fSelectedPad;

   if (fSelected) {
      fSelected->ExecuteEvent(kMouseEnter, fEventX, fEventY);
      fEvent = kMouseEnter;
      RunAutoExec();
      ProcessedEvent(kMouseEnter, fEventX, fEventY, fSelected);  // emit signal
   }

   fEvent = sevent;
   gPad   = padsav;
}


//______________________________________________________________________________
void TCanvas::ExecuteEvent(Int_t event, Int_t px, Int_t py)
{
   // Execute action corresponding to one event.
   //
   //  This member function must be implemented to realize the action
   //  corresponding to the mouse click on the object in the canvas
   //
   //  Only handle mouse motion events in TCanvas, all other events are
   //  ignored for the time being

   if (gROOT->GetEditorMode()) {
      TPad::ExecuteEvent(event,px,py);
      return;
   }

   switch (event) {

   case kMouseMotion:
      SetCursor(kCross);
      break;
   }
}


//______________________________________________________________________________
void TCanvas::FeedbackMode(Bool_t set)
{
   // Turn rubberband feedback mode on or off.

   if (set) {
      SetDoubleBuffer(0);             // turn off double buffer mode
      gVirtualX->SetDrawMode(TVirtualX::kInvert);  // set the drawing mode to XOR mode
   } else {
      SetDoubleBuffer(1);             // turn on double buffer mode
      gVirtualX->SetDrawMode(TVirtualX::kCopy); // set drawing mode back to normal (copy) mode
   }
}


//______________________________________________________________________________
void TCanvas::Flush()
{
   // Flush canvas buffers.

   if (fCanvasID == -1) return;

   TPad *padsav = (TPad*)gPad;
   cd();
   if (!IsBatch()) {
      gVirtualX->SelectWindow(fCanvasID);
      gPad = padsav; //don't do cd() because than also the pixmap is changed
      CopyPixmaps();
      gVirtualX->UpdateWindow(1);
   }
   if (padsav) padsav->cd();
}


//______________________________________________________________________________
void TCanvas::UseCurrentStyle()
{
   // Force a copy of current style for all objects in canvas.

   if ((!gROOT->IsLineProcessing()) && (!gVirtualX->IsCmdThread())) {
      gInterpreter->Execute(this, IsA(), "UseCurrentStyle", "");
      return;
   }
   TPad::UseCurrentStyle();

   if (gStyle->IsReading()) {
      SetFillColor(gStyle->GetCanvasColor());
      fBorderSize = gStyle->GetCanvasBorderSize();
      fBorderMode = gStyle->GetCanvasBorderMode();
   } else {
      gStyle->SetCanvasColor(GetFillColor());
      gStyle->SetCanvasBorderSize(fBorderSize);
      gStyle->SetCanvasBorderMode(fBorderMode);
   }
}


//______________________________________________________________________________
Int_t TCanvas::GetWindowTopX()
{
   // Returns current top x position of window on screen.

   if (fCanvasImp) fCanvasImp->GetWindowGeometry(fWindowTopX, fWindowTopY,
                                                 fWindowWidth,fWindowHeight);

   return fWindowTopX;
}


//______________________________________________________________________________
Int_t TCanvas::GetWindowTopY()
{
   // Returns current top y position of window on screen.

   if (fCanvasImp) fCanvasImp->GetWindowGeometry(fWindowTopX, fWindowTopY,
                                                 fWindowWidth,fWindowHeight);

   return fWindowTopY;
}


//______________________________________________________________________________
void TCanvas::HandleInput(EEventType event, Int_t px, Int_t py)
{
   // Handle Input Events.
   //
   //  Handle input events, like button up/down in current canvas.

   TPad    *pad;
   TPad    *prevSelPad = (TPad*) fSelectedPad;
   TObject *prevSelObj = fSelected;

   fPadSave = (TPad*)gPad;
   cd();        // make sure this canvas is the current canvas

   fEvent  = event;
   fEventX = px;
   fEventY = py;

   switch (event) {

   case kMouseMotion:
      // highlight object tracked over
      pad = Pick(px, py, prevSelObj);
      if (!pad) return;

      EnterLeave(prevSelPad, prevSelObj);

      gPad = pad;   // don't use cd() we will use the current
                    // canvas via the GetCanvas member and not via
                    // gPad->GetCanvas

      fSelected->ExecuteEvent(event, px, py);

      RunAutoExec();

      break;

   case kMouseEnter:
      // mouse enters canvas
      if (!fDoubleBuffer) FeedbackMode(kTRUE);
      break;

   case kMouseLeave:
      // mouse leaves canvas
      {
         // force popdown of tooltips
         TObject *sobj = fSelected;
         TPad    *spad = fSelectedPad;
         fSelected     = 0;
         fSelectedPad  = 0;
         EnterLeave(prevSelPad, prevSelObj);
         fSelected     = sobj;
         fSelectedPad  = spad;
         if (!fDoubleBuffer) FeedbackMode(kFALSE);
      }
      break;

   case kButton1Double:
      // triggered on the second button down within 350ms and within
      // 3x3 pixels of the first button down, button up finishes action

   case kButton1Down:
      // find pad in which input occured
      pad = Pick(px, py, prevSelObj);
      if (!pad) return;

      gPad = pad;   // don't use cd() because we won't draw in pad
                    // we will only use its coordinate system

      if (fSelected) {
         FeedbackMode(kTRUE);   // to draw in rubberband mode
         fSelected->ExecuteEvent(event, px, py);

         RunAutoExec();
      }

      break;

   case kButton1Motion:
   case 8://8 == kButton1Motion + shift modifier
      if (fSelected) {
         gPad = fSelectedPad;

         fSelected->ExecuteEvent(event, px, py);
         gVirtualX->Update();

         {
            Bool_t resize = kFALSE;
            if (fSelected->InheritsFrom(TBox::Class()))
               resize = ((TBox*)fSelected)->IsBeingResized();
            if (fSelected->InheritsFrom(TVirtualPad::Class()))
               resize = ((TVirtualPad*)fSelected)->IsBeingResized();

            if ((!resize && TestBit(kMoveOpaque)) || (resize && TestBit(kResizeOpaque))) {
               gPad = fPadSave;
               Update();
               FeedbackMode(kTRUE);
            }
         }

         RunAutoExec();
      }

      break;

   case kButton1Up:

      if (fSelected) {
         gPad = fSelectedPad;

         fSelected->ExecuteEvent(event, px, py);

         RunAutoExec();

         if (fPadSave)
            gPad = fPadSave;
         else {
            gPad     = this;
            fPadSave = this;
         }

         Update();    // before calling update make sure gPad is reset
      }
      break;

//*-*----------------------------------------------------------------------

   case kButton2Down:
      // find pad in which input occured
      pad = Pick(px, py, prevSelObj);
      if (!pad) return;

      gPad = pad;   // don't use cd() because we won't draw in pad
                    // we will only use its coordinate system

      FeedbackMode(kTRUE);

      fSelected->Pop();           // pop object to foreground
      pad->cd();                  // and make its pad the current pad
      if (gDebug)
         printf("Current Pad: %s / %s\n", pad->GetName(), pad->GetTitle());

      // loop over all canvases to make sure that only one pad is highlighted
      {
         TIter next(gROOT->GetListOfCanvases());
         TCanvas *tc;
         while ((tc = (TCanvas *)next()))
            tc->Update();
      }

      if (pad->GetGLDevice() != -1)
         fSelected->ExecuteEvent(event, px, py);

      break;   // don't want fPadSave->cd() to be executed at the end

   case kButton2Motion:
      //was empty!
   case kButton2Up:
      if (fSelected) {
         gPad = fSelectedPad;

         fSelected->ExecuteEvent(event, px, py);
         RunAutoExec();
      }
      break;

   case kButton2Double:
      break;

//*-*----------------------------------------------------------------------

   case kButton3Down:
      // popup context menu
      pad = Pick(px, py, prevSelObj);
      if (!pad) return;

      if (!fDoubleBuffer) FeedbackMode(kFALSE);

      if (fContextMenu && !fSelected->TestBit(kNoContextMenu) &&
         !pad->TestBit(kNoContextMenu) && !TestBit(kNoContextMenu))
         fContextMenu->Popup(px, py, fSelected, this, pad);

      break;

   case kButton3Motion:
      break;

   case kButton3Up:
      if (!fDoubleBuffer) FeedbackMode(kTRUE);
      break;

   case kButton3Double:
      break;

   case kKeyPress:
      if (!fSelectedPad || !fSelected) return;
      gPad = fSelectedPad;   // don't use cd() because we won't draw in pad
                    // we will only use its coordinate system
      fSelected->ExecuteEvent(event, px, py);

      RunAutoExec();

      break;
   case 7:
      // Try to select
      pad = Pick(px, py, prevSelObj);

      if (!pad) return;

      EnterLeave(prevSelPad, prevSelObj);

      gPad = pad;   // don't use cd() we will use the current
                    // canvas via the GetCanvas member and not via
                    // gPad->GetCanvas
      fSelected->ExecuteEvent(event, px, py);
      RunAutoExec();

      break;
   default:
      //kButton4/kButton5 for embedded gl/ glhistpainter
      //5 and 6
      if (event == 5 || event == 6)
      {
         pad = Pick(px, py, prevSelObj);
         if (!pad) return;

         gPad = pad;
         fSelected->ExecuteEvent(event, px, py);
      }
   }

   if (fPadSave && event != kButton2Down)
      fPadSave->cd();

   if (event != kMouseLeave) { // signal was already emitted for this event
      ProcessedEvent(event, px, py, fSelected);  // emit signal
      DrawEventStatus(event, px, py, fSelected);
   }
}


//______________________________________________________________________________
Bool_t TCanvas::IsFolder() const
{
   // Is folder ?

   return fgIsFolder;
}


//______________________________________________________________________________
void TCanvas::ls(Option_t *option) const
{
   // List all pads.

   TROOT::IndentLevel();
   cout <<"Canvas Name=" <<GetName()<<" Title="<<GetTitle()<<" Option="<<option<<endl;
   TROOT::IncreaseDirLevel();
   TPad::ls(option);
   TROOT::DecreaseDirLevel();
}


//______________________________________________________________________________
TCanvas *TCanvas::MakeDefCanvas()
{
   // Static function to build a default canvas.

   const char *defcanvas = gROOT->GetDefCanvasName();
   char *cdef;

   TList *lc = (TList*)gROOT->GetListOfCanvases();
   if (lc->FindObject(defcanvas)) {
      Int_t n = lc->GetSize() + 1;
      cdef = new char[strlen(defcanvas)+15];
      do {
         strcpy(cdef, Form("%s_n%d", defcanvas, n++));
      } while (lc->FindObject(cdef));
   } else
      cdef = StrDup(Form("%s",defcanvas));

   TCanvas *c = new TCanvas(cdef, cdef, 1);

   Printf("<TCanvas::MakeDefCanvas>: created default TCanvas with name %s",cdef);
   delete [] cdef;
   return c;
}


//______________________________________________________________________________
void TCanvas::MoveOpaque(Int_t set)
{
   // Set option to move objects/pads in a canvas.
   //
   //  if set = 1 (default) graphics objects are moved in opaque mode
   //         = 0 only the outline of objects is drawn when moving them
   //  The option opaque produces the best effect. It requires however a
   //  a reasonably fast workstation or response time.

   SetBit(kMoveOpaque,set);
}


//______________________________________________________________________________
void TCanvas::Paint(Option_t *option)
{
   // Paint canvas.

   if (fCanvas) TPad::Paint(option);
}


//______________________________________________________________________________
TPad *TCanvas::Pick(Int_t px, Int_t py, TObject *prevSelObj)
{
   // Prepare for pick, call TPad::Pick() and when selected object
   // is different from previous then emit Picked() signal.

   TObjLink *pickobj = 0;

   fSelected    = 0;
   fSelectedOpt = "";
   fSelectedPad = 0;

   TPad *pad = Pick(px, py, pickobj);
   if (!pad) return 0;

   if (!pickobj) {
      fSelected    = pad;
      fSelectedOpt = "";
   } else {
      if (!fSelected) {   // can be set via TCanvas::SetSelected()
         fSelected    = pickobj->GetObject();
         fSelectedOpt = pickobj->GetOption();
      }
   }
   fSelectedPad = pad;

   if (fSelected != prevSelObj)
      Picked(fSelectedPad, fSelected, fEvent);  // emit signal

   if ((fEvent == kButton1Down) || (fEvent == kButton2Down) || (fEvent == kButton3Down)) {
      if (fSelected && !fSelected->InheritsFrom("TView")) {
         fClickSelected = fSelected;
         fClickSelectedPad = fSelectedPad;
         Selected(fSelectedPad, fSelected, fEvent);  // emit signal
         fSelectedX = px;
         fSelectedY = py;
      }
   }
   return pad;
}


//______________________________________________________________________________
void TCanvas::Picked(TPad *pad, TObject *obj, Int_t event)
{
   // Emit Picked() signal.

   Long_t args[3];

   args[0] = (Long_t) pad;
   args[1] = (Long_t) obj;
   args[2] = event;

   Emit("Picked(TPad*,TObject*,Int_t)", args);
}


//______________________________________________________________________________
void TCanvas::Selected(TVirtualPad *pad, TObject *obj, Int_t event)
{
   // Emit Selected() signal.

   Long_t args[3];

   args[0] = (Long_t) pad;
   args[1] = (Long_t) obj;
   args[2] = event;

   Emit("Selected(TVirtualPad*,TObject*,Int_t)", args);
}


//______________________________________________________________________________
void TCanvas::ProcessedEvent(Int_t event, Int_t x, Int_t y, TObject *obj)
{
   // Emit ProcessedEvent() signal.

   Long_t args[4];

   args[0] = event;
   args[1] = x;
   args[2] = y;
   args[3] = (Long_t) obj;

   Emit("ProcessedEvent(Int_t,Int_t,Int_t,TObject*)", args);
}


//______________________________________________________________________________
void TCanvas::Resize(Option_t *)
{
   // Recompute canvas parameters following a X11 Resize.

   if (fCanvasID == -1) return;

   if ((!gROOT->IsLineProcessing()) && (!gVirtualX->IsCmdThread())) {
      gInterpreter->Execute(this, IsA(), "Resize", "");
      return;
   }

   TPad *padsav  = (TPad*)gPad;
   cd();

   if (!IsBatch()) {
      gVirtualX->SelectWindow(fCanvasID);      //select current canvas
      gVirtualX->ResizeWindow(fCanvasID);      //resize canvas and off-screen buffer

      // Get effective window parameters including menubar and borders
      fCanvasImp->GetWindowGeometry(fWindowTopX, fWindowTopY,
                                    fWindowWidth, fWindowHeight);

      // Get effective canvas parameters without borders
      Int_t dum1, dum2;
      gVirtualX->GetGeometry(fCanvasID, dum1, dum2, fCw, fCh);
   }

   if (fXsizeUser && fYsizeUser) {
      UInt_t nwh = fCh;
      UInt_t nww = fCw;
      Double_t rxy = fXsizeUser/fYsizeUser;
      if (rxy < 1) {
         UInt_t twh = UInt_t(Double_t(fCw)/rxy);
         if (twh > fCh)
            nww = UInt_t(Double_t(fCh)*rxy);
         else
            nwh = twh;
         if (nww > fCw) {
            nww = fCw; nwh = twh;
         }
         if (nwh > fCh) {
            nwh = fCh; nww = UInt_t(Double_t(fCh)/rxy);
         }
      } else {
         UInt_t twh = UInt_t(Double_t(fCw)*rxy);
         if (twh > fCh)
            nwh = UInt_t(Double_t(fCw)/rxy);
         else
            nww = twh;
         if (nww > fCw) {
            nww = fCw; nwh = twh;
         }
         if (nwh > fCh) {
            nwh = fCh; nww = UInt_t(Double_t(fCh)*rxy);
         }
      }
      fCw = nww;
      fCh = nwh;
   }

   if (fCw < fCh) {
      fYsizeReal = kDefaultCanvasSize;
      fXsizeReal = fYsizeReal*Double_t(fCw)/Double_t(fCh);
   }
   else {
      fXsizeReal = kDefaultCanvasSize;
      fYsizeReal = fXsizeReal*Double_t(fCh)/Double_t(fCw);
   }

//*-*- Loop on all pads to recompute conversion coefficients
   TPad::ResizePad();

   if (padsav) padsav->cd();
}


//______________________________________________________________________________
void TCanvas::ResizeOpaque(Int_t set)
{
   // Set option to resize objects/pads in a canvas.
   //
   //  if set = 1 (default) graphics objects are resized in opaque mode
   //         = 0 only the outline of objects is drawn when resizing them
   //  The option opaque produces the best effect. It requires however a
   //  a reasonably fast workstation or response time.

   SetBit(kResizeOpaque,set);
}


//______________________________________________________________________________
void TCanvas::RunAutoExec()
{
   // Execute the list of TExecs in the current pad.

   if (!TestBit(kAutoExec)) return;
   if (!gPad) return;
   ((TPad*)gPad)->AutoExec();
}


//______________________________________________________________________________
void TCanvas::SavePrimitive(ostream &out, Option_t *option /*= ""*/)
{
   // Save primitives in this canvas in C++ macro file with GUI

   Bool_t invalid = kFALSE;

   // Write canvas options (in $TROOT or $TStyle)
   if (gStyle->GetOptFit()) {
      out<<"   gStyle->SetOptFit(1);"<<endl;
   }
   if (!gStyle->GetOptStat()) {
      out<<"   gStyle->SetOptStat(0);"<<endl;
   }
   if (gROOT->GetEditHistograms()) {
      out<<"   gROOT->SetEditHistograms();"<<endl;
   }
   if (GetShowEventStatus()) {
      out<<"   "<<GetName()<<"->ToggleEventStatus();"<<endl;
   }
   if (GetShowToolBar()) {
      out<<"   "<<GetName()<<"->ToggleToolBar();"<<endl;
   }
   if (GetHighLightColor() != 5) {
      if (GetHighLightColor() > 228) {
         TColor::SaveColor(out, GetHighLightColor());
         out<<"   "<<GetName()<<"->SetHighLightColor(ci);" << endl;
      } else
         out<<"   "<<GetName()<<"->SetHighLightColor("<<GetHighLightColor()<<");"<<endl;
   }

   // Now recursively scan all pads of this canvas
   cd();
   if (invalid) SetName("c1");
   TPad::SavePrimitive(out,option);
   if (invalid) SetName(" ");
}


//______________________________________________________________________________
void TCanvas::SaveSource(const char *filename, Option_t *option)
{
   // Save primitives in this canvas as a C++ macro file.
   // This function loops on all the canvas primitives and for each primitive
   // calls the object SavePrimitive function.
   // When outputing floating point numbers, the default precision is 7 digits.
   // The precision can be changed (via system.rootrc) by changing the value
   // of the environment variable "Canvas.SavePrecision"
   
   //    reset bit TClass::kClassSaved for all classes
   TIter next(gROOT->GetListOfClasses());
   TClass *cl;
   while((cl = (TClass*)next())) {
      cl->ResetBit(TClass::kClassSaved);
   }

   char quote = '"';
   ofstream out;
   Int_t lenfile = strlen(filename);
   char * fname;
   char lcname[10];
   const char *cname = GetName();
   Bool_t invalid = kFALSE;
   //    if filename is given, open this file, otherwise create a file
   //    with a name equal to the canvasname.C
   if (lenfile) {
      fname = (char*)filename;
      out.open(fname, ios::out);
   } else {
      Int_t nch = strlen(cname);
      if (nch < 10) {
         strcpy(lcname,cname);
         for (Int_t k=1;k<=nch;k++) {if (lcname[nch-k] == ' ') lcname[nch-k] = 0;}
         if (lcname[0] == 0) {invalid = kTRUE; strcpy(lcname,"c1"); nch = 2;}
         cname = lcname;
      }
      fname = new char[nch+3];
      strcpy(fname,cname);
      strcat(fname,".C");
      out.open(fname, ios::out);
   }
   if (!out.good ()) {
      Printf("SaveSource cannot open file: %s",fname);
      if (!lenfile) delete [] fname;
      return;
   }
   
   //set precision
   Int_t precision = gEnv->GetValue("Canvas.SavePrecision",7);
   out.precision(precision);

   //   Write macro header and date/time stamp
   TDatime t;
   Float_t cx = gStyle->GetScreenFactor();
   Int_t topx,topy;
   UInt_t w, h;
   UInt_t editorWidth = fCanvasImp->GetWindowGeometry(topx,topy,w,h);
   w = UInt_t((fWindowWidth - editorWidth)/cx);
   h = UInt_t((fWindowHeight)/cx);
   topx = GetWindowTopX();
   topy = GetWindowTopY();

   if (w == 0) {
      w = GetWw()+4; h = GetWh()+4;
      topx = 1;    topy = 1;
   }

   out <<"{"<<endl;
   out <<"//=========Macro generated from canvas: "<<GetName()<<"/"<<GetTitle()<<endl;
   out <<"//=========  ("<<t.AsString()<<") by ROOT version"<<gROOT->GetVersion()<<endl;

   if (gStyle->GetCanvasPreferGL())
      out <<endl<<"   gStyle->SetCanvasPreferGL(kTRUE);"<<endl<<endl;
       
   //   Write canvas parameters (TDialogCanvas case)
   if (InheritsFrom(TDialogCanvas::Class())) {
      out<<"   "<<ClassName()<<" *"<<cname<<" = new "<<ClassName()<<"("<<quote<<GetName()
         <<quote<<", "<<quote<<GetTitle()<<quote<<","<<w<<","<<h<<");"<<endl;
   } else {
   //   Write canvas parameters (TCanvas case)
      out<<"   TCanvas *"<<cname<<" = new TCanvas("<<quote<<GetName()<<quote<<", "<<quote<<GetTitle()
         <<quote;
      if (!HasMenuBar())
         out<<",-"<<topx<<","<<topy<<","<<w<<","<<h<<");"<<endl;
      else
         out<<","<<topx<<","<<topy<<","<<w<<","<<h<<");"<<endl;
   }
   //   Write canvas options (in $TROOT or $TStyle)
   if (gStyle->GetOptFit()) {
      out<<"   gStyle->SetOptFit(1);"<<endl;
   }
   if (!gStyle->GetOptStat()) {
      out<<"   gStyle->SetOptStat(0);"<<endl;
   }
   if (gROOT->GetEditHistograms()) {
      out<<"   gROOT->SetEditHistograms();"<<endl;
   }
   if (GetShowEventStatus()) {
      out<<"   "<<GetName()<<"->ToggleEventStatus();"<<endl;
   }
   if (GetHighLightColor() != 5) {
      if (GetHighLightColor() > 228) {
         TColor::SaveColor(out, GetHighLightColor());
         out<<"   "<<GetName()<<"->SetHighLightColor(ci);" << endl;
      } else
         out<<"   "<<GetName()<<"->SetHighLightColor("<<GetHighLightColor()<<");"<<endl;
   }

   //   Now recursively scan all pads of this canvas
   cd();
   if (invalid) SetName("c1");
   TPad::SavePrimitive(out,option);
   //   Write canvas options related to pad editor
   out<<"   "<<GetName()<<"->SetSelected("<<GetName()<<");"<<endl;
   if (GetShowToolBar()) {
      out<<"   "<<GetName()<<"->ToggleToolBar();"<<endl;
   }
   if (invalid) SetName(" ");

   out <<"}"<<endl;
   out.close();
   Info("SaveSource","C++ Macro file: %s has been generated", fname);

   //    reset bit TClass::kClassSaved for all classes
   next.Reset();
   while((cl = (TClass*)next())) {
      cl->ResetBit(TClass::kClassSaved);
   }
   if (!lenfile) delete [] fname;
}


//______________________________________________________________________________
void TCanvas::SetBatch(Bool_t batch)
{
   // Toggle batch mode. However, if the canvas is created without a window
   // then batch mode always stays set.

   if (gROOT->IsBatch())
      fBatch = kTRUE;
   else
      fBatch = batch;
}


//______________________________________________________________________________
void TCanvas::SetCanvasSize(UInt_t ww, UInt_t wh)
{
   // Set Width and Height of canvas to ww and wh respectively
   // If ww and/or wh are greater than the current canvas window
   // a scroll bar is automatically generated.
   // Use this function to zoom in a canvas and naviguate via
   // the scroll bars.

   if (fCanvasImp) {
      fCanvasImp->SetCanvasSize(ww, wh);
      fCw = ww;
      fCh = wh;
      ResizePad();
   }
}


//______________________________________________________________________________
void TCanvas::SetCursor(ECursor cursor)
{
   // Set cursor.

   if (IsBatch()) return;
   gVirtualX->SetCursor(fCanvasID, cursor);
}


//______________________________________________________________________________
void TCanvas::SetDoubleBuffer(Int_t mode)
{
   // Set Double Buffer On/Off.

   if (IsBatch()) return;
   fDoubleBuffer = mode;
   gVirtualX->SetDoubleBuffer(fCanvasID, mode);

   // depending of the buffer mode set the drawing window to either
   // the canvas pixmap or to the canvas on-screen window
   if (fDoubleBuffer) {
      if (fPixmapID != -1) gVirtualX->SelectWindow(fPixmapID);
   } else
      if (fCanvasID != -1) gVirtualX->SelectWindow(fCanvasID);
}


//______________________________________________________________________________
void TCanvas::SetFixedAspectRatio(Bool_t fixed)
{
   // Fix canvas aspect ratio to current value if fixed is true.

   if (fixed) {
      if (!fFixedAspectRatio) {
         if (fCh != 0)
            fAspectRatio = Double_t(fCw) / fCh;
         else {
            Error("SetAspectRatio", "cannot fix aspect ratio, height of canvas is 0");
            return;
         }
         fFixedAspectRatio = kTRUE;
      }
   } else {
      fFixedAspectRatio = kFALSE;
      fAspectRatio = 0;
   }
}


//______________________________________________________________________________
void TCanvas::SetFolder(Bool_t isfolder)
{
   // if isfolder=kTRUE, the canvas can be browsed like a folder
   // by default a canvas is not browsable

   fgIsFolder = isfolder;
}


//______________________________________________________________________________
void TCanvas::SetSelected(TObject *obj)
{
   // Set selectd canvas.

   fSelected = obj;
   if (obj) obj->SetBit(kMustCleanup);
}


//______________________________________________________________________________
void TCanvas::SetTitle(const char *title)
{
   // Set Canvas title.

   fTitle = title;
   if (fCanvasImp) fCanvasImp->SetWindowTitle(title);
}


//______________________________________________________________________________
void TCanvas::Size(Float_t xsize, Float_t ysize)
{
   // Set the canvas scale in centimeters.
   //
   //  This information is used by PostScript to set the page size.
   //  xsize  = size of the canvas in centimeters along X
   //  ysize  = size of the canvas in centimeters along Y
   //   if xsize and ysize are not equal to 0, then the scale factors will
   //   be computed to keep the ratio ysize/xsize independently of the canvas
   //   size (parts of the physical canvas will be unused).
   //
   //   if xsize = 0 and ysize is not zero, then xsize will be computed
   //      to fit to the current canvas scale. If the canvas is resized,
   //      a new value for xsize will be recomputed. In this case the aspect
   //      ratio is not preserved.
   //
   //   if both xsize = 0 and ysize = 0, then the scaling is automatic.
   //   the largest dimension will be allocated a size of 20 centimeters.

   fXsizeUser = xsize;
   fYsizeUser = ysize;

   Resize();
}


//_______________________________________________________________________
void TCanvas::Streamer(TBuffer &b)
{
   // Stream a class object.

   UInt_t R__s, R__c;
   if (b.IsReading()) {
      Version_t v = b.ReadVersion(&R__s, &R__c);
      gPad    = this;
      fCanvas = this;
      TPad::Streamer(b);
      gPad    = this;
      //restore the colors
      TObjArray *colors = (TObjArray*)fPrimitives->FindObject("ListOfColors");
      if (colors) {
         TIter next(colors);
         TColor *colold;
         while ((colold = (TColor*)next())) {
            if (colold) {
               Int_t cn = 0;
               if (colold) cn = colold->GetNumber();
               TColor *colcur = gROOT->GetColor(cn);
               if (colcur) {
                  colcur->SetRGB(colold->GetRed(),colold->GetGreen(),colold->GetBlue());
               } else {
                  colcur = new TColor(cn,colold->GetRed(),
                                        colold->GetGreen(),
                                        colold->GetBlue(),
                                        colold->GetName());
               }
            }
         }
         fPrimitives->Remove(colors);
         colors->Delete();
         delete colors;
      }

      fDISPLAY.Streamer(b);
      b >> fDoubleBuffer;
      b >> fRetained;
      b >> fXsizeUser;
      b >> fYsizeUser;
      b >> fXsizeReal;
      b >> fYsizeReal;
      fCanvasID = -1;
      b >> fWindowTopX;
      b >> fWindowTopY;
      if (v > 2) {
         b >> fWindowWidth;
         b >> fWindowHeight;
      }
      b >> fCw;
      b >> fCh;
      if (v <= 2) {
         fWindowWidth  = fCw;
         fWindowHeight = fCh;
      }
      fCatt.Streamer(b);
      Bool_t dummy;
      b >> dummy; if (dummy) MoveOpaque(1);
      b >> dummy; if (dummy) ResizeOpaque(1);
      b >> fHighLightColor;
      b >> dummy; //was fBatch
      if (v < 2) return;
      b >> dummy; if (dummy) SetBit(kShowEventStatus);
      if (v > 3) {b >> dummy; if (dummy) SetBit(kAutoExec);}
      b >> dummy; if (dummy) SetBit(kMenuBar);
      fBatch = gROOT->IsBatch();
      b.CheckByteCount(R__s, R__c, TCanvas::IsA());
   } else {
      //save list of colors
      //we must protect the case when two or more canvases are saved
      //in the same buffer. If the list of colors has already been saved
      //in the buffer, do not add the list of colors to the list of primitives.
      TObjArray *colors = 0;
      if (!b.CheckObject(gROOT->GetListOfColors(),TObjArray::Class())) {
         colors = (TObjArray*)gROOT->GetListOfColors();
         fPrimitives->Add(colors);
      }
      R__c = b.WriteVersion(TCanvas::IsA(), kTRUE);
      TPad::Streamer(b);
      if(colors) fPrimitives->Remove(colors);
      fDISPLAY.Streamer(b);
      b << fDoubleBuffer;
      b << fRetained;
      b << fXsizeUser;
      b << fYsizeUser;
      b << fXsizeReal;
      b << fYsizeReal;
      UInt_t w   = fWindowWidth,  h    = fWindowHeight;
      Int_t topx = fWindowTopX,   topy = fWindowTopY;
      UInt_t editorWidth = 0;
      if(fCanvasImp) editorWidth = fCanvasImp->GetWindowGeometry(topx,topy,w,h);
      b << topx;
      b << topy;
      b << (UInt_t)(w-editorWidth);
      b << h;
      b << fCw;
      b << fCh;
      fCatt.Streamer(b);
      b << TestBit(kMoveOpaque);      //please remove in ROOT version 6
      b << TestBit(kResizeOpaque);    //please remove in ROOT version 6
      b << fHighLightColor;
      b << fBatch;                    //please remove in ROOT version 6
      b << TestBit(kShowEventStatus); //please remove in ROOT version 6
      b << TestBit(kAutoExec);        //please remove in ROOT version 6
      b << TestBit(kMenuBar);         //please remove in ROOT version 6
      b.SetByteCount(R__c, kTRUE);
   }
}


//______________________________________________________________________________
void TCanvas::ToggleAutoExec()
{
   // Toggle pad auto execution of list of TExecs.

   Bool_t autoExec = TestBit(kAutoExec);
   SetBit(kAutoExec,!autoExec);
}


//______________________________________________________________________________
void TCanvas::ToggleEventStatus()
{
   // Toggle event statusbar.

   Bool_t showEventStatus = !TestBit(kShowEventStatus);
   SetBit(kShowEventStatus,showEventStatus);

   if (fCanvasImp) fCanvasImp->ShowStatusBar(showEventStatus);
}


//______________________________________________________________________________
void TCanvas::ToggleToolBar()
{
   // Toggle toolbar.
   Bool_t showToolBar = !TestBit(kShowToolBar);
   SetBit(kShowToolBar,showToolBar);

   if (fCanvasImp) fCanvasImp->ShowToolBar(showToolBar);
}


//______________________________________________________________________________
void TCanvas::ToggleEditor()
{
   // Toggle editor.
   Bool_t showEditor = !TestBit(kShowEditor);
   SetBit(kShowEditor,showEditor);

   if (fCanvasImp) fCanvasImp->ShowEditor(showEditor);
}


//______________________________________________________________________________
void TCanvas::Update()
{
   // Update canvas pad buffers

   if (fUpdating) return;

   if (gThreadXAR) {
      void *arr[2];
      arr[1] = this;
      if ((*gThreadXAR)("CUPD", 2, arr, 0)) return;
   }

   if (!gVirtualX->IsCmdThread()) {
      gInterpreter->Execute(this, IsA(), "Update", "");
      return;
   }
   fUpdating = kTRUE;

   if (!IsBatch()) FeedbackMode(kFALSE);      // Goto double buffer mode

   PaintModified();           // Repaint all modified pad's

   Flush();                   // Copy all pad pixmaps to the screen

   SetCursor(kCross);
   fUpdating = kFALSE;
}


//______________________________________________________________________________
void TCanvas::DisconnectWidget()
{
   // Used by friend class TCanvasImp.

   fCanvasID    = 0;
   fContextMenu = 0;
}

//______________________________________________________________________________
Bool_t TCanvas::IsGrayscale()
{
   // Check whether this canvas is to be drawn in grayscale mode.
   return TestBit(kIsGrayscale);
}

//______________________________________________________________________________
void TCanvas::SetGrayscale(Bool_t set /*= kTRUE*/)
{
   // Set whether this canvas should be painted in grayscale, and re-paint
   // it if necessary.
   if (IsGrayscale() == set) return;
   SetBit(kIsGrayscale, set);
   Paint(); // update canvas and all sub-pads, unconditionally!
}

Last update: Thu Jan 17 08:47:11 2008

This page has been automatically generated. If you have any comments or suggestions about the page layout send a mail to ROOT support, or contact the developers with any questions or problems regarding ROOT.