00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012 #include <stdio.h>
00013
00014 #include "TStyle.h"
00015 #include "TLatex.h"
00016 #include "TLine.h"
00017 #include "TBox.h"
00018 #include "TMarker.h"
00019 #include "TLegend.h"
00020 #include "TList.h"
00021 #include "TVirtualPad.h"
00022 #include "TMath.h"
00023 #include "TROOT.h"
00024 #include "TLegendEntry.h"
00025 #include "Riostream.h"
00026 #include "TMultiGraph.h"
00027 #include "THStack.h"
00028
00029
00030 ClassImp(TLegend)
00031
00032
00033
00034
00035
00036
00037
00038
00039
00040
00041
00042
00043
00044
00045
00046
00047
00048
00049
00050
00051
00052
00053
00054
00055
00056
00057
00058
00059
00060
00061
00062
00063
00064
00065
00066
00067
00068
00069
00070
00071
00072
00073
00074
00075
00076
00077
00078
00079
00080
00081
00082
00083
00084
00085
00086
00087
00088
00089
00090
00091
00092
00093
00094
00095
00096
00097
00098
00099
00100
00101
00102
00103
00104
00105
00106
00107
00108
00109
00110
00111
00112
00113
00114
00115
00116
00117
00118
00119
00120
00121
00122
00123
00124
00125
00126
00127
00128
00129
00130
00131
00132
00133
00134
00135
00136
00137
00138
00139 TLegend::TLegend(): TPave(), TAttText()
00140 {
00141
00142
00143
00144
00145 fPrimitives = 0;
00146 SetDefaults();
00147 }
00148
00149
00150
00151 TLegend::TLegend( Double_t x1, Double_t y1,Double_t x2, Double_t y2,
00152 const char *header, Option_t *option)
00153 :TPave(x1,y1,x2,y2,4,option), TAttText(12,0,1,gStyle->GetTextFont(),0)
00154 {
00155
00156
00157
00158
00159
00160
00161
00162
00163
00164
00165
00166
00167 fPrimitives = new TList;
00168 if ( header && strlen(header) > 0) {
00169 TLegendEntry *headerEntry = new TLegendEntry( 0, header, "h" );
00170 headerEntry->SetTextAlign(0);
00171 headerEntry->SetTextAngle(0);
00172 headerEntry->SetTextColor(0);
00173 headerEntry->SetTextFont(62);
00174 headerEntry->SetTextSize(0);
00175 fPrimitives->AddFirst(headerEntry);
00176 }
00177 SetDefaults();
00178 SetBorderSize(gStyle->GetLegendBorderSize());
00179 }
00180
00181
00182
00183 TLegend::TLegend( const TLegend &legend ) : TPave(legend), TAttText(legend),
00184 fPrimitives(0)
00185 {
00186
00187
00188
00189
00190 if (legend.fPrimitives) {
00191 fPrimitives = new TList();
00192 TListIter it(legend.fPrimitives);
00193 while (TLegendEntry *e = (TLegendEntry *)it.Next()) {
00194 TLegendEntry *newentry = new TLegendEntry(*e);
00195 fPrimitives->Add(newentry);
00196 }
00197 }
00198 ((TLegend&)legend).Copy(*this);
00199 }
00200
00201
00202
00203 TLegend& TLegend::operator=(const TLegend &lg)
00204 {
00205
00206
00207
00208
00209 if(this!=&lg) {
00210 TPave::operator=(lg);
00211 TAttText::operator=(lg);
00212 fPrimitives=lg.fPrimitives;
00213 fEntrySeparation=lg.fEntrySeparation;
00214 fMargin=lg.fMargin;
00215 fNColumns=lg.fNColumns;
00216 }
00217 return *this;
00218 }
00219
00220
00221
00222 TLegend::~TLegend()
00223 {
00224
00225
00226
00227
00228 if (fPrimitives) fPrimitives->Delete();
00229 delete fPrimitives;
00230 fPrimitives = 0;
00231 }
00232
00233
00234
00235 TLegendEntry *TLegend::AddEntry(const TObject *obj, const char *label, Option_t *option)
00236 {
00237
00238
00239
00240
00241
00242
00243
00244
00245
00246
00247
00248
00249
00250
00251 const char *lab = label;
00252
00253 if (obj && (!label || strlen(label)==0)) lab = obj->GetTitle();
00254 TLegendEntry *newentry = new TLegendEntry( obj, lab, option );
00255 if ( !fPrimitives ) fPrimitives = new TList;
00256 fPrimitives->Add(newentry);
00257 return newentry;
00258 }
00259
00260
00261
00262 TLegendEntry *TLegend::AddEntry(const char *name, const char *label, Option_t *option)
00263 {
00264
00265
00266
00267
00268
00269
00270
00271
00272
00273
00274
00275
00276
00277
00278 TObject *obj = gPad->FindObject(name);
00279
00280
00281
00282 if (!obj) {
00283 TList *lop = gPad->GetListOfPrimitives();
00284 if (lop) {
00285 TObject *o=0;
00286 TIter next(lop);
00287 while( (o=next()) ) {
00288 if ( o->InheritsFrom(TMultiGraph::Class() ) ) {
00289 TList * grlist = ((TMultiGraph *)o)->GetListOfGraphs();
00290 obj = grlist->FindObject(name);
00291 if (obj) continue;
00292 }
00293 if ( o->InheritsFrom(THStack::Class() ) ) {
00294 TList * hlist = ((THStack *)o)->GetHists();
00295 obj = hlist->FindObject(name);
00296 if (obj) continue;
00297 }
00298 }
00299 }
00300 }
00301
00302 return AddEntry( obj, label, option );
00303 }
00304
00305
00306
00307 void TLegend::Clear( Option_t *)
00308 {
00309
00310
00311
00312
00313 if (!fPrimitives) return;
00314 fPrimitives->Delete();
00315 }
00316
00317
00318
00319 void TLegend::Copy( TObject &obj ) const
00320 {
00321
00322
00323
00324
00325 TPave::Copy(obj);
00326 TAttText::Copy((TLegend&)obj);
00327 ((TLegend&)obj).fEntrySeparation = fEntrySeparation;
00328 ((TLegend&)obj).fMargin = fMargin;
00329 ((TLegend&)obj).fNColumns = fNColumns;
00330 }
00331
00332
00333
00334 void TLegend::DeleteEntry()
00335 {
00336
00337
00338
00339
00340 if ( !fPrimitives ) return;
00341 TLegendEntry* entry = GetEntry();
00342 if ( !entry ) return;
00343 fPrimitives->Remove(entry);
00344 delete entry;
00345 }
00346
00347
00348
00349 void TLegend::Draw( Option_t *option )
00350 {
00351
00352
00353
00354
00355 AppendPad(option);
00356 }
00357
00358
00359
00360 void TLegend::EditEntryAttFill()
00361 {
00362
00363
00364
00365
00366 TLegendEntry* entry = GetEntry();
00367 if ( !entry ) return;
00368 gROOT->SetSelectedPrimitive( entry );
00369 entry->SetFillAttributes();
00370 }
00371
00372
00373
00374 void TLegend::EditEntryAttLine()
00375 {
00376
00377
00378
00379
00380 TLegendEntry* entry = GetEntry();
00381 if ( !entry ) return;
00382 gROOT->SetSelectedPrimitive( entry );
00383 entry->SetLineAttributes();
00384 }
00385
00386
00387
00388 void TLegend::EditEntryAttMarker()
00389 {
00390
00391
00392
00393
00394 TLegendEntry* entry = GetEntry();
00395 if ( !entry ) return;
00396 gROOT->SetSelectedPrimitive( entry );
00397 entry->SetMarkerAttributes();
00398 }
00399
00400
00401
00402 void TLegend::EditEntryAttText()
00403 {
00404
00405
00406
00407
00408 TLegendEntry* entry = GetEntry();
00409 if ( !entry ) return;
00410 gROOT->SetSelectedPrimitive( entry );
00411 entry->SetTextAttributes();
00412 }
00413
00414
00415
00416 TLegendEntry *TLegend::GetEntry() const
00417 {
00418
00419
00420
00421
00422
00423 Int_t nRows = GetNRows();
00424 if ( nRows == 0 ) return 0;
00425
00426 Double_t ymouse = gPad->AbsPixeltoY(gPad->GetEventY());
00427 Double_t yspace = (fY2 - fY1)/nRows;
00428
00429 Double_t ybottomOfEntry = fY2;
00430 TIter next(fPrimitives);
00431 TLegendEntry *entry;
00432 while (( entry = (TLegendEntry *)next() )) {
00433 ybottomOfEntry -= yspace;
00434 if ( ybottomOfEntry < ymouse ) return entry;
00435 }
00436 return 0;
00437 }
00438
00439
00440
00441 const char *TLegend::GetHeader() const
00442 {
00443
00444
00445
00446
00447
00448 if ( !fPrimitives ) return 0;
00449 TIter next(fPrimitives);
00450 TLegendEntry *first;
00451 if (( first = (TLegendEntry*)next() )) {
00452 TString opt = first->GetOption();
00453 opt.ToLower();
00454 if ( opt.Contains("h") ) return first->GetLabel();
00455 }
00456 return 0;
00457 }
00458
00459
00460
00461 void TLegend::InsertEntry( const char* objectName, const char* label, Option_t* option)
00462 {
00463
00464
00465
00466
00467 TLegendEntry* beforeEntry = GetEntry();
00468 TObject *obj = gPad->FindObject( objectName );
00469
00470
00471
00472 TLegendEntry *newentry = new TLegendEntry( obj, label, option );
00473
00474 if ( !fPrimitives ) fPrimitives = new TList;
00475 if ( beforeEntry ) {
00476 fPrimitives->AddBefore( (TObject*)beforeEntry, (TObject*)newentry );
00477 } else {
00478 fPrimitives->Add((TObject*)newentry);
00479 }
00480 }
00481
00482
00483
00484 void TLegend::Paint( Option_t* option )
00485 {
00486
00487
00488
00489
00490 TPave::ConvertNDCtoPad();
00491 TPave::PaintPave(fX1,fY1,fX2,fY2,GetBorderSize(),option);
00492 PaintPrimitives();
00493 }
00494
00495
00496
00497 Int_t TLegend::GetNRows() const
00498 {
00499
00500
00501
00502
00503 Int_t nEntries = 0;
00504 if ( fPrimitives ) nEntries = fPrimitives->GetSize();
00505 if ( nEntries == 0 ) return 0;
00506
00507 Int_t nRows;
00508 if(GetHeader() != NULL) nRows = 1 + (Int_t) TMath::Ceil((Double_t) (nEntries-1)/fNColumns);
00509 else nRows = (Int_t) TMath::Ceil((Double_t) nEntries/fNColumns);
00510
00511 return nRows;
00512 }
00513
00514
00515
00516 void TLegend::SetNColumns(Int_t nColumns)
00517 {
00518
00519
00520
00521
00522
00523
00524
00525
00526 if(nColumns < 1) {
00527 Warning("TLegend::SetNColumns", "illegal value nColumns = %d; keeping fNColumns = %d", nColumns, fNColumns);
00528 return;
00529 }
00530 fNColumns = nColumns;
00531 }
00532
00533
00534
00535 void TLegend::PaintPrimitives()
00536 {
00537
00538
00539
00540
00541 Int_t nRows = GetNRows();
00542 if ( nRows == 0 ) return;
00543
00544
00545
00546
00547
00548
00549 Double_t x1 = fX1NDC;
00550 Double_t y1 = fY1NDC;
00551 Double_t x2 = fX2NDC;
00552 Double_t y2 = fY2NDC;
00553 Double_t margin = fMargin*( x2-x1 )/fNColumns;
00554 Double_t boxwidth = margin;
00555 Double_t boxw = boxwidth*0.35;
00556 Double_t yspace = (y2-y1)/nRows;
00557 Double_t textsize = GetTextSize();
00558 Double_t save_textsize = textsize;
00559 Double_t* columnWidths = new Double_t[fNColumns];
00560 memset(columnWidths, 0, fNColumns*sizeof(Double_t));
00561
00562 if ( textsize == 0 ) {
00563 textsize = ( 1. - fEntrySeparation ) * yspace;
00564
00565
00566 Double_t maxentrywidth = 0, maxentryheight = 0;
00567 TIter nextsize(fPrimitives);
00568 TLegendEntry *entrysize;
00569 Int_t iColumn = 0;
00570 while (( entrysize = (TLegendEntry *)nextsize() )) {
00571 TLatex entrytex( 0, 0, entrysize->GetLabel() );
00572 entrytex.SetNDC();
00573 Style_t tfont = entrysize->GetTextFont();
00574 if (tfont == 0) tfont = GetTextFont();
00575 entrytex.SetTextFont(tfont);
00576 entrytex.SetTextSize(textsize);
00577 if ( entrytex.GetYsize() > maxentryheight ) {
00578 maxentryheight = entrytex.GetYsize();
00579 }
00580 TString opt = entrysize->GetOption();
00581 opt.ToLower();
00582 if ( opt.Contains("h") ) {
00583 if ( entrytex.GetXsize() > maxentrywidth ) {
00584 maxentrywidth = entrytex.GetXsize();
00585 }
00586 } else {
00587 if ( entrytex.GetXsize() > columnWidths[iColumn] ) {
00588 columnWidths[iColumn] = entrytex.GetXsize();
00589 }
00590 iColumn++;
00591 iColumn %= fNColumns;
00592 }
00593 Double_t tmpMaxWidth = 0.0;
00594 for(int i=0; i<fNColumns; i++) tmpMaxWidth += columnWidths[i];
00595 if ( tmpMaxWidth > maxentrywidth) maxentrywidth = tmpMaxWidth;
00596 }
00597
00598 Double_t tmpsize_h = maxentryheight /(gPad->GetY2() - gPad->GetY1());
00599 textsize = TMath::Min( textsize, tmpsize_h );
00600 Double_t tmpsize_w = textsize*(fX2-fX1)*(1.0-fMargin)/maxentrywidth;
00601 if(fNColumns > 1) tmpsize_w = textsize*(fX2-fX1)*(1.0-fMargin-fColumnSeparation)/maxentrywidth;
00602 textsize = TMath::Min( textsize, tmpsize_w );
00603 SetTextSize( textsize );
00604 }
00605
00606
00607
00608
00609 {
00610 TIter next(fPrimitives);
00611 TLegendEntry *entry;
00612 Int_t iColumn = 0;
00613 memset(columnWidths, 0, fNColumns*sizeof(Double_t));
00614 while (( entry = (TLegendEntry *)next() )) {
00615 TLatex entrytex( 0, 0, entry->GetLabel() );
00616 entrytex.SetNDC();
00617 Style_t tfont = entry->GetTextFont();
00618 if (tfont == 0) tfont = GetTextFont();
00619 entrytex.SetTextFont(tfont);
00620 if(entry->GetTextSize() == 0) entrytex.SetTextSize(textsize);
00621 TString opt = entry->GetOption();
00622 opt.ToLower();
00623 if (!opt.Contains("h")) {
00624 if ( entrytex.GetXsize() > columnWidths[iColumn] ) {
00625 columnWidths[iColumn] = entrytex.GetXsize();
00626 }
00627 iColumn++;
00628 iColumn %= fNColumns;
00629 }
00630 }
00631 double totalWidth = 0.0;
00632 for(int i=0; i<fNColumns; i++) totalWidth += columnWidths[i];
00633 if(fNColumns > 1) totalWidth /= (1.0-fMargin-fColumnSeparation);
00634 else totalWidth /= (1.0 - fMargin);
00635 for(int i=0; i<fNColumns; i++) {
00636 columnWidths[i] = columnWidths[i]/totalWidth*(x2-x1) + margin;
00637 }
00638 }
00639
00640 Double_t ytext = y2 + 0.5*yspace;
00641
00642
00643 TIter next(fPrimitives);
00644 TLegendEntry *entry;
00645 Int_t iColumn = 0;
00646 while (( entry = (TLegendEntry *)next() )) {
00647 if(iColumn == 0) ytext -= yspace;
00648
00649
00650
00651 Short_t talign = entry->GetTextAlign();
00652 Float_t tangle = entry->GetTextAngle();
00653 Color_t tcolor = entry->GetTextColor();
00654 Style_t tfont = entry->GetTextFont();
00655 Size_t tsize = entry->GetTextSize();
00656
00657 if (talign == 0) entry->SetTextAlign(GetTextAlign());
00658 if (tangle == 0) entry->SetTextAngle(GetTextAngle());
00659 if (tcolor == 0) entry->SetTextColor(GetTextColor());
00660 if (tfont == 0) entry->SetTextFont(GetTextFont());
00661 if (tsize == 0) entry->SetTextSize(GetTextSize());
00662
00663 Double_t x=0,y=0;
00664 Int_t halign = entry->GetTextAlign()/10;
00665 Double_t entrymargin = margin;
00666
00667 TString opt = entry->GetOption();
00668 opt.ToLower();
00669 x1 = fX1NDC;
00670 x2 = fX2NDC;
00671 if ( opt.Contains("h") ) entrymargin = margin/10.;
00672 else if (fNColumns > 1) {
00673 for(int i=0; i<iColumn; i++) x1 += columnWidths[i] + fColumnSeparation*(fX2NDC-fX1NDC)/(fNColumns-1);
00674 x2 = x1 + columnWidths[iColumn];
00675 iColumn++;
00676 iColumn %= fNColumns;
00677 }
00678 if (halign == 1) x = x1 + entrymargin;
00679 if (halign == 2) x = 0.5*( (x1+entrymargin) + x2 );
00680 if (halign == 3) x = x2 - entrymargin/10.;
00681 Int_t valign = entry->GetTextAlign()%10;
00682 if (valign == 1) y = ytext - (1. - fEntrySeparation)* yspace/2.;
00683 if (valign == 2) y = ytext;
00684 if (valign == 3) y = ytext + (1. - fEntrySeparation)* yspace/2.;
00685
00686 TLatex entrytex( x, y, entry->GetLabel() );
00687 entrytex.SetNDC();
00688 entry->TAttText::Copy(entrytex);
00689 entrytex.Paint();
00690
00691 entry->SetTextAlign(talign);
00692 entry->SetTextAngle(tangle);
00693 entry->SetTextColor(tcolor);
00694 entry->SetTextFont(tfont);
00695 entry->SetTextSize(tsize);
00696
00697
00698 Double_t xsym = x1 + margin/2.;
00699 Double_t ysym = ytext;
00700
00701 TObject *eobj = entry->GetObject();
00702
00703
00704
00705 if ( opt.Contains("f")) {
00706 if (eobj && eobj->InheritsFrom(TAttFill::Class())) {
00707 dynamic_cast<TAttFill*>(eobj)->Copy(*entry);
00708 }
00709
00710
00711 entry->TAttFill::Modify();
00712 Double_t xf[4],yf[4];
00713 xf[0] = xsym - boxw;
00714 yf[0] = ysym - yspace*0.35;
00715 xf[1] = xsym + boxw;
00716 yf[1] = yf[0];
00717 xf[2] = xf[1];
00718 yf[2] = ysym + yspace*0.35;
00719 xf[3] = xf[0];
00720 yf[3] = yf[2];
00721 for (Int_t i=0;i<4;i++) {
00722 xf[i] = gPad->GetX1() + xf[i]*(gPad->GetX2()-gPad->GetX1());
00723 yf[i] = gPad->GetY1() + yf[i]*(gPad->GetY2()-gPad->GetY1());
00724 }
00725 gPad->PaintFillArea(4,xf,yf);
00726 }
00727
00728
00729
00730 if ( opt.Contains("l") || opt.Contains("f")) {
00731
00732 if (eobj && eobj->InheritsFrom(TAttLine::Class())) {
00733 dynamic_cast<TAttLine*>(eobj)->Copy(*entry);
00734 }
00735
00736 TLine entryline( xsym - boxw, ysym, xsym + boxw, ysym );
00737 entryline.SetBit(TLine::kLineNDC);
00738 entry->TAttLine::Copy(entryline);
00739
00740 if ( opt.Contains("f") && !opt.Contains("l")) {
00741
00742 boxwidth = yspace*
00743 (gPad->GetX2()-gPad->GetX1())/(gPad->GetY2()-gPad->GetY1());
00744 if ( boxwidth > margin ) boxwidth = margin;
00745
00746 entryline.PaintLineNDC( xsym - boxw, ysym + yspace*0.35,
00747 xsym + boxw, ysym + yspace*0.35);
00748 entryline.PaintLineNDC( xsym - boxw, ysym - yspace*0.35,
00749 xsym + boxw, ysym - yspace*0.35);
00750 entryline.PaintLineNDC( xsym + boxw, ysym - yspace*0.35,
00751 xsym + boxw, ysym + yspace*0.35);
00752 entryline.PaintLineNDC( xsym - boxw, ysym - yspace*0.35,
00753 xsym - boxw, ysym + yspace*0.35);
00754 } else {
00755 entryline.Paint();
00756 if (opt.Contains("e")) {
00757 entryline.PaintLineNDC( xsym, ysym - yspace*0.30,
00758 xsym, ysym + yspace*0.30);
00759 }
00760 }
00761 }
00762
00763
00764
00765 if ( opt.Contains("p")) {
00766
00767 if (eobj && eobj->InheritsFrom(TAttMarker::Class())) {
00768 dynamic_cast<TAttMarker*>(eobj)->Copy(*entry);
00769 }
00770 TMarker entrymarker( xsym, ysym, 0 );
00771 entrymarker.SetNDC();
00772 entry->TAttMarker::Copy(entrymarker);
00773 entrymarker.Paint();
00774 }
00775 }
00776
00777 SetTextSize(save_textsize);
00778 delete [] columnWidths;
00779 }
00780
00781
00782
00783 void TLegend::Print( Option_t* option ) const
00784 {
00785
00786
00787
00788
00789 TPave::Print( option );
00790 if (fPrimitives) fPrimitives->Print();
00791 }
00792
00793
00794
00795 void TLegend::RecursiveRemove(TObject *obj)
00796 {
00797
00798
00799
00800
00801 TIter next(fPrimitives);
00802 TLegendEntry *entry;
00803 while (( entry = (TLegendEntry *)next() )) {
00804 if (entry->GetObject() == obj) entry->SetObject((TObject*)0);
00805 }
00806 }
00807
00808
00809
00810 void TLegend::SavePrimitive(ostream &out, Option_t* )
00811 {
00812
00813
00814
00815
00816
00817 out << " " << endl;
00818 char quote = '"';
00819 if ( gROOT->ClassSaved( TLegend::Class() ) ) {
00820 out << " ";
00821 } else {
00822 out << " TLegend *";
00823 }
00824
00825 out << "leg = new TLegend("<<GetX1NDC()<<","<<GetY1NDC()<<","
00826 <<GetX2NDC()<<","<<GetY2NDC()<<","
00827 << "NULL" << "," <<quote<< fOption <<quote<<");" << endl;
00828 if (fBorderSize != 4) {
00829 out<<" leg->SetBorderSize("<<fBorderSize<<");"<<endl;
00830 }
00831 SaveTextAttributes(out,"leg",12,0,1,42,0);
00832 SaveLineAttributes(out,"leg",-1,-1,-1);
00833 SaveFillAttributes(out,"leg",-1,-1);
00834 if ( fPrimitives ) {
00835 TIter next(fPrimitives);
00836 TLegendEntry *entry;
00837 while (( entry = (TLegendEntry *)next() )) entry->SaveEntry(out,"leg");
00838 }
00839 out << " leg->Draw();"<<endl;
00840 }
00841
00842
00843
00844 void TLegend::SetEntryLabel( const char* label )
00845 {
00846
00847
00848
00849
00850 TLegendEntry* entry = GetEntry();
00851 if ( entry ) entry->SetLabel( label );
00852 }
00853
00854
00855
00856 void TLegend::SetEntryOption( Option_t* option )
00857 {
00858
00859
00860
00861
00862 TLegendEntry* entry = GetEntry();
00863 if ( entry ) entry->SetOption( option );
00864 }
00865
00866
00867
00868 void TLegend::SetHeader( const char *header )
00869 {
00870
00871
00872
00873
00874 if ( !fPrimitives ) fPrimitives = new TList;
00875 TIter next(fPrimitives);
00876 TLegendEntry *first;
00877 if (( first = (TLegendEntry*)next() )) {
00878 TString opt = first->GetOption();
00879 opt.ToLower();
00880 if ( opt.Contains("h") ) {
00881 first->SetLabel(header);
00882 return;
00883 }
00884 }
00885 first = new TLegendEntry( 0, header, "h" );
00886 first->SetTextAlign(0);
00887 first->SetTextAngle(0);
00888 first->SetTextColor(0);
00889 first->SetTextFont(GetTextFont());
00890 first->SetTextSize(0);
00891 fPrimitives->AddFirst((TObject*)first);
00892 }