// @(#)root/graf:$Id$ // Author: Matthew.Adam.Dobbs 06/09/99 /************************************************************************* * 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 #include "TStyle.h" #include "TLatex.h" #include "TLine.h" #include "TBox.h" #include "TMarker.h" #include "TLegend.h" #include "TList.h" #include "TVirtualPad.h" #include "TMath.h" #include "TROOT.h" #include "TLegendEntry.h" #include "Riostream.h" #include "TMultiGraph.h" #include "THStack.h" ClassImp(TLegend) /** \class TLegend \ingroup BasicGraphics This class displays a legend box (TPaveText) containing several legend entries. Each legend entry is made of a reference to a ROOT object, a text label and an option specifying which graphical attributes (marker/line/fill) should be displayed. The following example shows how to create a legend. In this example the legend contains a histogram, a function and a graph. The histogram is put in the legend using its reference pointer whereas the graph and the function are added using their names. Note that, because `TGraph` constructors do not have the `TGraph` name as parameter, the graph name should be specified using the `SetName` method. When an object is added by name, a scan is performed on the list of objects contained in the current pad (`gPad`) and also in the possible `TMultiGraph` and `THStack` present in the pad. If a matching name is found, the corresponding object is added in the legend using its pointer. Begin_Macro(source) { TCanvas *c1 = new TCanvas("c1","c1",600,500); gStyle->SetOptStat(0); TH1F *h1 = new TH1F("h1","TLegend Example",200,-10,10); h1->FillRandom("gaus",30000); h1->SetFillColor(kGreen); h1->SetFillStyle(3003); h1->Draw(); TF1 *f1=new TF1("f1","1000*TMath::Abs(sin(x)/x)",-10,10); f1->SetLineColor(kBlue); f1->SetLineWidth(4); f1->Draw("same"); const Int_t n = 20; Double_t x[n], y[n], ex[n], ey[n]; for (Int_t i=0;iSetName("gr"); gr->SetLineColor(kRed); gr->SetLineWidth(2); gr->SetMarkerStyle(21); gr->SetMarkerSize(1.3); gr->SetMarkerColor(7); gr->Draw("P"); leg = new TLegend(0.1,0.7,0.48,0.9); leg->SetHeader("The Legend Title"); leg->AddEntry(h1,"Histogram filled with random numbers","f"); leg->AddEntry("f1","Function abs(#frac{sin(x)}{x})","l"); leg->AddEntry("gr","Graph with error bars","lep"); leg->Draw(); return c1; } End_Macro `TLegend` inherits from `TAttText` therefore changing any text attributes (text alignment, font, color...) on a legend will changed the text attributes on each line. In particular it can be interesting to change the text alignement that way. In order to have a base-line vertical alignment instead of a centered one simply do: ~~~ {.cpp} leg->SetTextAlign(13); ~~~ or ~~~ {.cpp} leg->SetTextAlign(11); ~~~ The default value of some `TLegend` attributes can be changed using `gStyle`. The default settings are: ~~~ {.cpp} SetLegendBorderSize(1); SetLegendFillColor(0); SetLegendFont(42); SetLegendTextSize(0.); ~~~ The global attributes change the default values for the next created legends. Text attributes can be also changed individually on each legend entry: ~~~ {.cpp} TLegendEntry *le = leg->AddEntry(h1,"Histogram filled with random numbers","f"); le->SetTextColor(kBlue);; ~~~ Note that the `TPad` class has a method to build automatically a legend for all objects in the pad. It is called `TPad::BuildLegend()`. Each item in the legend is added using the `AddEntry` method. This method defines the object to be added (by reference or name), the label associated to this object and an option which a combination of: - L: draw line associated with TAttLine if obj inherits from TAttLine - P: draw polymarker associated with TAttMarker if obj inherits from TAttMarker - F: draw a box with fill associated wit TAttFill if obj inherits TAttFill - E: draw vertical error bar As shown in the following example, passing a NULL pointer as first parameter in `AddEntry` is also valid. This allows to add text or blank lines in a legend. Begin_Macro(source) { TCanvas *c2 = new TCanvas("c2","c2",500,300); TLegend* leg = new TLegend(0.2, 0.2, .8, .8); TH1* h = new TH1F("", "", 1, 0, 1); leg->AddEntry(h, "Histogram \"h\"", "l"); leg->AddEntry((TObject*)0, "", ""); leg->AddEntry((TObject*)0, "Some text", ""); leg->AddEntry((TObject*)0, "", ""); leg->AddEntry(h, "Histogram \"h\" again", "l"); leg->Draw(); return c2; } End_Macro It is possible to draw the legend entries over several columns using the method `SetNColumns()` like in the following example. Begin_Macro(source) { TCanvas *c3 = new TCanvas("c2","c2",500,300); TLegend* leg = new TLegend(0.2, 0.2, .8, .8); TH1* h = new TH1F("", "", 1, 0, 1); leg-> SetNColumns(2); leg->AddEntry(h, "Column 1 line 1", "l"); leg->AddEntry(h, "Column 2 line 1", "l"); leg->AddEntry(h, "Column 1 line 2", "l"); leg->AddEntry(h, "Column 2 line 2", "l"); leg->Draw(); return c3; } End_Macro */ //////////////////////////////////////////////////////////////////////////////// /// Default constructor. TLegend::TLegend(): TPave(), TAttText(12,0,1,gStyle->GetLegendFont(),0) { fPrimitives = 0; SetDefaults(); SetBorderSize(gStyle->GetLegendBorderSize()); SetFillColor(gStyle->GetLegendFillColor()); } //////////////////////////////////////////////////////////////////////////////// /// Normal constructor. /// /// A TLegend is a Pave with several TLegendEntry(s). /// x1,y1,x2,y2 are the coordinates of the Legend in the current pad /// (in normalised coordinates by default) /// "header" is the title that will be displayed at the top of the legend /// it is treated like a regular entry and supports TLatex. The default /// is no header (header = 0). /// The options are the same as for TPave Default = "brNDC" TLegend::TLegend( Double_t x1, Double_t y1,Double_t x2, Double_t y2, const char *header, Option_t *option) :TPave(x1,y1,x2,y2,4,option), TAttText(12,0,1,gStyle->GetLegendFont(),0) { fPrimitives = new TList; if ( header && strlen(header) > 0) { TLegendEntry *headerEntry = new TLegendEntry( 0, header, "h" ); headerEntry->SetTextAlign(0); headerEntry->SetTextAngle(0); headerEntry->SetTextColor(0); headerEntry->SetTextFont(gStyle->GetLegendFont()); headerEntry->SetTextSize(0); fPrimitives->AddFirst(headerEntry); } SetDefaults(); SetBorderSize(gStyle->GetLegendBorderSize()); SetFillColor(gStyle->GetLegendFillColor()); } //////////////////////////////////////////////////////////////////////////////// /// Copy constructor. TLegend::TLegend( const TLegend &legend ) : TPave(legend), TAttText(legend), fPrimitives(0) { if (legend.fPrimitives) { fPrimitives = new TList(); TListIter it(legend.fPrimitives); while (TLegendEntry *e = (TLegendEntry *)it.Next()) { TLegendEntry *newentry = new TLegendEntry(*e); fPrimitives->Add(newentry); } } ((TLegend&)legend).Copy(*this); } //////////////////////////////////////////////////////////////////////////////// /// Assignment operator. TLegend& TLegend::operator=(const TLegend &lg) { if(this!=&lg) { TPave::operator=(lg); TAttText::operator=(lg); fPrimitives=lg.fPrimitives; fEntrySeparation=lg.fEntrySeparation; fMargin=lg.fMargin; fNColumns=lg.fNColumns; } return *this; } //////////////////////////////////////////////////////////////////////////////// /// Default destructor. TLegend::~TLegend() { if (fPrimitives) fPrimitives->Delete(); delete fPrimitives; fPrimitives = 0; } //////////////////////////////////////////////////////////////////////////////// /// Add a new entry to this legend. "obj" is the object to be represented. /// "label" is the text you wish to associate with obj in the legend. /// If "label" is null or empty, the title of the object will be used. /// /// Options are: /// /// - L: draw line associated with TAttLine if obj inherits from TAttLine /// - P: draw polymarker associated with TAttMarker if obj inherits from TAttMarker /// - F: draw a box with fill associated wit TAttFill if obj inherits TAttFill /// - E: draw vertical error bar if option "L" is also specified TLegendEntry *TLegend::AddEntry(const TObject *obj, const char *label, Option_t *option) { const char *lab = label; if (obj && (!label || strlen(label)==0)) lab = obj->GetTitle(); TLegendEntry *newentry = new TLegendEntry( obj, lab, option ); if ( !fPrimitives ) fPrimitives = new TList; fPrimitives->Add(newentry); return newentry; } //////////////////////////////////////////////////////////////////////////////// /// Add a new entry to this legend. "name" is the name of an object in the pad to /// be represented label is the text you wish to associate with obj in the legend /// if label is null or empty, the title of the object will be used. /// /// Options are: /// /// - L: draw line associated with TAttLine if obj inherits from TAttLine /// - P: draw polymarker associated with TAttMarker if obj inherits from TAttMarker /// - F: draw a box with fill associated wit TAttFill if obj inherits TAttFill /// - E: draw vertical error bar if option "L" is also specified TLegendEntry *TLegend::AddEntry(const char *name, const char *label, Option_t *option) { if (!gPad) { Error("AddEntry", "need to create a canvas first"); return 0; } TObject *obj = gPad->FindObject(name); // If the object "name" has not been found, the following code tries to // find it in TMultiGraph or THStack possibly present in the current pad. if (!obj) { TList *lop = gPad->GetListOfPrimitives(); if (lop) { TObject *o=0; TIter next(lop); while( (o=next()) ) { if ( o->InheritsFrom(TMultiGraph::Class() ) ) { TList * grlist = ((TMultiGraph *)o)->GetListOfGraphs(); obj = grlist->FindObject(name); if (obj) break; } if ( o->InheritsFrom(THStack::Class() ) ) { TList * hlist = ((THStack *)o)->GetHists(); obj = hlist->FindObject(name); if (obj) break; } } } } return AddEntry( obj, label, option ); } //////////////////////////////////////////////////////////////////////////////// /// Clear all entries in this legend, including the header. void TLegend::Clear( Option_t *) { if (!fPrimitives) return; fPrimitives->Delete(); } //////////////////////////////////////////////////////////////////////////////// /// Copy this legend into "obj". void TLegend::Copy( TObject &obj ) const { TPave::Copy(obj); TAttText::Copy((TLegend&)obj); ((TLegend&)obj).fEntrySeparation = fEntrySeparation; ((TLegend&)obj).fMargin = fMargin; ((TLegend&)obj).fNColumns = fNColumns; } //////////////////////////////////////////////////////////////////////////////// /// Delete entry at the mouse position. void TLegend::DeleteEntry() { if ( !fPrimitives ) return; TLegendEntry* entry = GetEntry(); // get entry pointed by the mouse if ( !entry ) return; fPrimitives->Remove(entry); delete entry; } //////////////////////////////////////////////////////////////////////////////// /// Draw this legend with its current attributes. void TLegend::Draw( Option_t *option ) { AppendPad(option); } //////////////////////////////////////////////////////////////////////////////// /// Edit the fill attributes for the entry pointed by the mouse. void TLegend::EditEntryAttFill() { TLegendEntry* entry = GetEntry(); // get entry pointed by the mouse if ( !entry ) return; gROOT->SetSelectedPrimitive( entry ); entry->SetFillAttributes(); } //////////////////////////////////////////////////////////////////////////////// /// Edit the line attributes for the entry pointed by the mouse. void TLegend::EditEntryAttLine() { TLegendEntry* entry = GetEntry(); // get entry pointed by the mouse if ( !entry ) return; gROOT->SetSelectedPrimitive( entry ); entry->SetLineAttributes(); } //////////////////////////////////////////////////////////////////////////////// /// Edit the marker attributes for the entry pointed by the mouse. void TLegend::EditEntryAttMarker() { TLegendEntry* entry = GetEntry(); // get entry pointed by the mouse if ( !entry ) return; gROOT->SetSelectedPrimitive( entry ); entry->SetMarkerAttributes(); } //////////////////////////////////////////////////////////////////////////////// /// Edit the text attributes for the entry pointed by the mouse. void TLegend::EditEntryAttText() { TLegendEntry* entry = GetEntry(); // get entry pointed by the mouse if ( !entry ) return; gROOT->SetSelectedPrimitive( entry ); entry->SetTextAttributes(); } //////////////////////////////////////////////////////////////////////////////// /// Get entry pointed to by the mouse. /// This method is mostly a tool for other methods inside this class. TLegendEntry *TLegend::GetEntry() const { if (!gPad) { Error("GetEntry", "need to create a canvas first"); return 0; } Int_t nRows = GetNRows(); if ( nRows == 0 ) return 0; Double_t ymouse = gPad->AbsPixeltoY(gPad->GetEventY())-fY1; Double_t yspace = (fY2 - fY1)/nRows; Int_t nColumns = GetNColumns(); Double_t xmouse = gPad->AbsPixeltoX(gPad->GetEventX())-fX1; Double_t xspace = 0.; if (nColumns > 0) xspace = (fX2 - fX1)/nColumns; Int_t ix = 1; if (xspace > 0.) ix = (Int_t)(xmouse/xspace)+1; if (ix > nColumns) ix = nColumns; if (ix < 1) ix = 1; Int_t iy = nRows-(Int_t)(ymouse/yspace); if (iy > nRows) iy = nRows; if (iy < 1) iy = 1; Int_t nloops = TMath::Min(ix+(nColumns*(iy-1)), fPrimitives->GetSize()); TIter next(fPrimitives); TLegendEntry *entry = 0; for (Int_t i=1; i<= nloops; i++) entry = (TLegendEntry *)next(); return entry; } //////////////////////////////////////////////////////////////////////////////// /// Returns the header, which is the title that appears at the top /// of the legend. const char *TLegend::GetHeader() const { if ( !fPrimitives ) return 0; TIter next(fPrimitives); TLegendEntry *first; // header is always the first entry if (( first = (TLegendEntry*)next() )) { TString opt = first->GetOption(); opt.ToLower(); if ( opt.Contains("h") ) return first->GetLabel(); } return 0; } //////////////////////////////////////////////////////////////////////////////// /// Add a new entry before the entry at the mouse position. void TLegend::InsertEntry( const char* objectName, const char* label, Option_t* option) { if (!gPad) { Error("InsertEntry", "need to create a canvas first"); return; } TLegendEntry* beforeEntry = GetEntry(); // get entry pointed by the mouse TObject *obj = gPad->FindObject( objectName ); // note either obj OR beforeEntry may be zero at this point TLegendEntry *newentry = new TLegendEntry( obj, label, option ); if ( !fPrimitives ) fPrimitives = new TList; if ( beforeEntry ) { fPrimitives->AddBefore( (TObject*)beforeEntry, (TObject*)newentry ); } else { fPrimitives->Add((TObject*)newentry); } } //////////////////////////////////////////////////////////////////////////////// /// Paint this legend with its current attributes. void TLegend::Paint( Option_t* option ) { TPave::ConvertNDCtoPad(); TPave::PaintPave(fX1,fY1,fX2,fY2,GetBorderSize(),option); PaintPrimitives(); } //////////////////////////////////////////////////////////////////////////////// /// Get the number of rows. Int_t TLegend::GetNRows() const { Int_t nEntries = 0; if ( fPrimitives ) nEntries = fPrimitives->GetSize(); if ( nEntries == 0 ) return 0; Int_t nRows; if(GetHeader() != NULL) nRows = 1 + (Int_t) TMath::Ceil((Double_t) (nEntries-1)/fNColumns); else nRows = (Int_t) TMath::Ceil((Double_t) nEntries/fNColumns); return nRows; } //////////////////////////////////////////////////////////////////////////////// /// Set the number of columns for the legend. The header, if set, is given /// its own row. After that, every nColumns entries are inserted into the /// same row. For example, if one calls legend.SetNColumns(2), and there /// is no header, then the first two TObjects added to the legend will be /// in the first row, the next two will appear in the second row, and so on. void TLegend::SetNColumns(Int_t nColumns) { if(nColumns < 1) { Warning("TLegend::SetNColumns", "illegal value nColumns = %d; keeping fNColumns = %d", nColumns, fNColumns); return; } fNColumns = nColumns; } //////////////////////////////////////////////////////////////////////////////// /// Paint the entries (list of primitives) for this legend. void TLegend::PaintPrimitives() { Int_t nRows = GetNRows(); if ( nRows == 0 ) return; // Evaluate text size as a function of the number of entries // taking into account their real size after drawing latex // Note: in pixel coords y1 > y2=0, but x2 > x1=0 // in NDC y2 > y1, and x2 > x1 Double_t x1 = fX1NDC; Double_t y1 = fY1NDC; Double_t x2 = fX2NDC; Double_t y2 = fY2NDC; Double_t margin = fMargin*( x2-x1 )/fNColumns; Double_t boxwidth = margin; Double_t boxw = boxwidth*0.35; Double_t yspace = (y2-y1)/nRows; Double_t yspace2 = yspace/2.; Double_t textsize = GetTextSize(); Double_t save_textsize = textsize; if (textsize==0.) { SetTextSize(gStyle->GetLegendTextSize()); textsize = GetTextSize(); } Bool_t autosize = kFALSE; Double_t* columnWidths = new Double_t[fNColumns]; memset(columnWidths, 0, fNColumns*sizeof(Double_t)); if ( textsize == 0 ) { autosize = kTRUE; textsize = ( 1. - fEntrySeparation ) * yspace; // find the max width and height (in pad coords) of one latex entry label Double_t maxentrywidth = 0, maxentryheight = 0; TIter nextsize(fPrimitives); TLegendEntry *entrysize; Int_t iColumn = 0; while (( entrysize = (TLegendEntry *)nextsize() )) { TLatex entrytex( 0, 0, entrysize->GetLabel() ); entrytex.SetNDC(); Style_t tfont = entrysize->GetTextFont(); if (tfont == 0) tfont = GetTextFont(); if (tfont%10 == 3) --tfont; entrytex.SetTextFont(tfont); entrytex.SetTextSize(textsize); if ( entrytex.GetYsize() > maxentryheight ) { maxentryheight = entrytex.GetYsize(); } TString opt = entrysize->GetOption(); opt.ToLower(); if ( opt.Contains("h") ) { if ( entrytex.GetXsize() > maxentrywidth ) { maxentrywidth = entrytex.GetXsize(); } } else { if ( entrytex.GetXsize() > columnWidths[iColumn] ) { columnWidths[iColumn] = entrytex.GetXsize(); } iColumn++; iColumn %= fNColumns; } Double_t tmpMaxWidth = 0.0; for(int i=0; i maxentrywidth) maxentrywidth = tmpMaxWidth; } // make sure all labels fit in the allotted space Double_t tmpsize_h = maxentryheight /(gPad->GetY2() - gPad->GetY1()); textsize = TMath::Min( textsize, tmpsize_h ); Double_t tmpsize_w = textsize*(fX2-fX1)*(1.0-fMargin)/maxentrywidth; if(fNColumns > 1) tmpsize_w = textsize*(fX2-fX1)*(1.0-fMargin-fColumnSeparation)/maxentrywidth; textsize = TMath::Min( textsize, tmpsize_w ); SetTextSize( textsize ); } // Update column widths, put into NDC units // block off this section of code to make sure all variables are local: // don't want to ruin initialisation of these variables later on { TIter next(fPrimitives); TLegendEntry *entry; Int_t iColumn = 0; memset(columnWidths, 0, fNColumns*sizeof(Double_t)); while (( entry = (TLegendEntry *)next() )) { TLatex entrytex( 0, 0, entry->GetLabel() ); entrytex.SetNDC(); Style_t tfont = entry->GetTextFont(); if (tfont == 0) tfont = GetTextFont(); if (autosize && tfont%10 == 3) --tfont; entrytex.SetTextFont(tfont); if(entry->GetTextSize() == 0) entrytex.SetTextSize(textsize); TString opt = entry->GetOption(); opt.ToLower(); if (!opt.Contains("h")) { if ( entrytex.GetXsize() > columnWidths[iColumn] ) { columnWidths[iColumn] = entrytex.GetXsize(); } iColumn++; iColumn %= fNColumns; } } double totalWidth = 0.0; for(int i=0; i 1) totalWidth /= (1.0-fMargin-fColumnSeparation); else totalWidth /= (1.0 - fMargin); for(int i=0; iGetTextAlign(); Float_t tangle = entry->GetTextAngle(); Color_t tcolor = entry->GetTextColor(); Style_t tfont = entry->GetTextFont(); Size_t tsize = entry->GetTextSize(); // if the user hasn't set a parameter, then set it to the TLegend value if (talign == 0) entry->SetTextAlign(GetTextAlign()); if (tangle == 0) entry->SetTextAngle(GetTextAngle()); if (tcolor == 0) entry->SetTextColor(GetTextColor()); if (tfont == 0) { tfont = GetTextFont(); if (autosize && tfont%10 == 3) --tfont; entry->SetTextFont(tfont); } if (tsize == 0) entry->SetTextSize(GetTextSize()); // set x,y according to the requested alignment Double_t x=0,y=0; Int_t halign = entry->GetTextAlign()/10; Double_t entrymargin = margin; // for the header the margin is near zero TString opt = entry->GetOption(); opt.ToLower(); x1 = fX1NDC; x2 = fX2NDC; if ( opt.Contains("h") ) entrymargin = margin/10.; else if (fNColumns > 1) { for(int i=0; iGetTextAlign()%10; if (valign == 1) y = ytext - (1. - fEntrySeparation)* yspace2; if (valign == 3) y = ytext + (1. - fEntrySeparation)* yspace2; // The vertical alignment "centered" is treated in a special way // to ensure a better spacing between lines. if (valign == 2) { Float_t tsizepad = textsize; if (tfont%10 == 3) tsizepad = (gPad->AbsPixeltoY(0) - gPad->AbsPixeltoY(textsize))/(gPad->GetY2() - gPad->GetY1()); if (yspace2 < tsizepad) { entry->SetTextAlign(10*halign+1); y = ytext - (1. - fEntrySeparation)* yspace2/2.; } else { y = ytext; } } TLatex entrytex( x, y, entry->GetLabel() ); entrytex.SetNDC(); entry->TAttText::Copy(entrytex); entrytex.Paint(); // reset attributes back to their original values entry->SetTextAlign(talign); entry->SetTextAngle(tangle); entry->SetTextColor(tcolor); entry->SetTextFont(tfont); entry->SetTextSize(tsize); // define x,y as the center of the symbol for this entry Double_t xsym = x1 + margin/2.; Double_t ysym = ytext; TObject *eobj = entry->GetObject(); // Draw fill pattern (in a box) if ( opt.Contains("f")) { if (eobj && eobj->InheritsFrom(TAttFill::Class())) { dynamic_cast(eobj)->Copy(*entry); } // box total height is yspace*0.7 entry->TAttFill::Modify(); Double_t xf[4],yf[4]; xf[0] = xsym - boxw; yf[0] = ysym - yspace*0.35; xf[1] = xsym + boxw; yf[1] = yf[0]; xf[2] = xf[1]; yf[2] = ysym + yspace*0.35; xf[3] = xf[0]; yf[3] = yf[2]; for (Int_t i=0;i<4;i++) { xf[i] = gPad->GetX1() + xf[i]*(gPad->GetX2()-gPad->GetX1()); yf[i] = gPad->GetY1() + yf[i]*(gPad->GetY2()-gPad->GetY1()); } gPad->PaintFillArea(4,xf,yf); } // Draw line if ( opt.Contains("l") || opt.Contains("f")) { if (eobj && eobj->InheritsFrom(TAttLine::Class())) { dynamic_cast(eobj)->Copy(*entry); } // line total length (in x) is margin*0.8 TLine entryline( xsym - boxw, ysym, xsym + boxw, ysym ); entryline.SetBit(TLine::kLineNDC); entry->TAttLine::Copy(entryline); // if the entry is filled, then surround the box with the line instead if ( opt.Contains("f") && !opt.Contains("l")) { // box total height is yspace*0.7 boxwidth = yspace* (gPad->GetX2()-gPad->GetX1())/(gPad->GetY2()-gPad->GetY1()); if ( boxwidth > margin ) boxwidth = margin; entryline.PaintLineNDC( xsym - boxw, ysym + yspace*0.35, xsym + boxw, ysym + yspace*0.35); entryline.PaintLineNDC( xsym - boxw, ysym - yspace*0.35, xsym + boxw, ysym - yspace*0.35); entryline.PaintLineNDC( xsym + boxw, ysym - yspace*0.35, xsym + boxw, ysym + yspace*0.35); entryline.PaintLineNDC( xsym - boxw, ysym - yspace*0.35, xsym - boxw, ysym + yspace*0.35); } else { entryline.Paint(); if (opt.Contains("e")) { entryline.PaintLineNDC( xsym, ysym - yspace*0.30, xsym, ysym + yspace*0.30); } } } // Draw error only if (opt.Contains("e") && !(opt.Contains("l") || opt.Contains("f"))) { if (eobj && eobj->InheritsFrom(TAttLine::Class())) { dynamic_cast(eobj)->Copy(*entry); } TLine entryline(xsym, ysym - yspace*0.30, xsym, ysym + yspace*0.30); entryline.SetBit(TLine::kLineNDC); entry->TAttLine::Copy(entryline); entryline.Paint(); } // Draw Polymarker if ( opt.Contains("p")) { if (eobj && eobj->InheritsFrom(TAttMarker::Class())) { dynamic_cast(eobj)->Copy(*entry); } TMarker entrymarker( xsym, ysym, 0 ); entrymarker.SetNDC(); entry->TAttMarker::Copy(entrymarker); entrymarker.Paint(); } } SetTextSize(save_textsize); delete [] columnWidths; } //////////////////////////////////////////////////////////////////////////////// /// Dump this TLegend and its contents. void TLegend::Print( Option_t* option ) const { TPave::Print( option ); if (fPrimitives) fPrimitives->Print(); } //////////////////////////////////////////////////////////////////////////////// /// Reset the legend entries pointing to "obj". void TLegend::RecursiveRemove(TObject *obj) { TIter next(fPrimitives); TLegendEntry *entry; while (( entry = (TLegendEntry *)next() )) { if (entry->GetObject() == obj) entry->SetObject((TObject*)0); } } //////////////////////////////////////////////////////////////////////////////// /// Save this legend as C++ statements on output stream out /// to be used with the SaveAs .C option. void TLegend::SavePrimitive(std::ostream &out, Option_t* ) { out << " " << std::endl; char quote = '"'; if ( gROOT->ClassSaved( TLegend::Class() ) ) { out << " "; } else { out << " TLegend *"; } // note, we can always use NULL header, since its included in primitives out << "leg = new TLegend("<SetBorderSize("<SaveEntry(out,"leg"); } out << " leg->Draw();"<SetLabel( label ); } //////////////////////////////////////////////////////////////////////////////// /// Edit the option of the entry pointed to by the mouse. void TLegend::SetEntryOption( Option_t* option ) { TLegendEntry* entry = GetEntry(); // get entry pointed by the mouse if ( entry ) entry->SetOption( option ); } //////////////////////////////////////////////////////////////////////////////// /// Sets the header, which is the "title" that appears at the top of the legend. void TLegend::SetHeader( const char *header ) { if ( !fPrimitives ) fPrimitives = new TList; TIter next(fPrimitives); TLegendEntry *first; // header is always the first entry if (( first = (TLegendEntry*)next() )) { TString opt = first->GetOption(); opt.ToLower(); if ( opt.Contains("h") ) { first->SetLabel(header); return; } } first = new TLegendEntry( 0, header, "h" ); first->SetTextAlign(0); first->SetTextAngle(0); first->SetTextColor(0); first->SetTextFont(GetTextFont()); // default font is TLegend font for the header first->SetTextSize(0); fPrimitives->AddFirst((TObject*)first); }