From fcd19beb42be67cb160d90f66bd214698f7a0fc2 Mon Sep 17 00:00:00 2001
From: Sergey Linev <S.Linev@gsi.de>
Date: Wed, 15 May 2019 16:28:54 +0200
Subject: [PATCH] web fitpanel: improve TCanvas management

Search for object in sub-sub pads before creating new TCanvas.
Drawing copy of function - do not keep stale pointer as was done by
previous panel
---
 gui/fitpanelv7/inc/ROOT/RFitPanel.hxx      |  2 +-
 gui/fitpanelv7/inc/ROOT/RFitPanelModel.hxx | 11 ++-
 gui/fitpanelv7/src/RFitPanel.cxx           | 96 +++++++++++++---------
 gui/fitpanelv7/src/RFitPanelModel.cxx      | 49 ++++-------
 4 files changed, 82 insertions(+), 76 deletions(-)

diff --git a/gui/fitpanelv7/inc/ROOT/RFitPanel.hxx b/gui/fitpanelv7/inc/ROOT/RFitPanel.hxx
index 41f2f2b0ba2..7cef67e268c 100644
--- a/gui/fitpanelv7/inc/ROOT/RFitPanel.hxx
+++ b/gui/fitpanelv7/inc/ROOT/RFitPanel.hxx
@@ -43,7 +43,7 @@ class RFitPanel {
    std::unique_ptr<RFitPanelModel> fModel;
 
    std::vector<TObject*> fObjects;    ///<! objects provided directly to panel for fitting
-   std::string fCanvName{"c1"};       ///<! v6 canvas name used to display fit, will be created if not exists
+   std::string fCanvName;             ///<! v6 canvas name used to display fit, will be created if not exists
 
    std::shared_ptr<RCanvas> fCanvas; ///!< v7 canvas used to display results
    std::shared_ptr<RH1D> fFitHist;   ///!< v7 histogram for fitting
diff --git a/gui/fitpanelv7/inc/ROOT/RFitPanelModel.hxx b/gui/fitpanelv7/inc/ROOT/RFitPanelModel.hxx
index 3e93ad6a2f1..3450d0434ee 100644
--- a/gui/fitpanelv7/inc/ROOT/RFitPanelModel.hxx
+++ b/gui/fitpanelv7/inc/ROOT/RFitPanelModel.hxx
@@ -20,6 +20,7 @@
 #include "Foption.h"
 #include "Fit/DataRange.h"
 #include "Math/MinimizerOptions.h"
+#include "TString.h"
 
 #include <vector>
 #include <string>
@@ -196,13 +197,11 @@ struct RFitPanelModel {
 
    bool IsDataSelected() const { return !fSelectedData.empty(); }
 
-   void GetRanges(ROOT::Fit::DataRange &drange);
-   void GetFitOptions(Foption_t &fitOpts);
-   void GetMinimizerOptions(ROOT::Math::MinimizerOptions &minOpts);
+   ROOT::Fit::DataRange GetRanges();
+   Foption_t GetFitOptions();
+   ROOT::Math::MinimizerOptions GetMinimizerOptions();
 
-   std::string GetDrawOption();
-
-   std::string GetFitOption();
+   TString GetDrawOption();
 };
 
 } // namespace Experimental
diff --git a/gui/fitpanelv7/src/RFitPanel.cxx b/gui/fitpanelv7/src/RFitPanel.cxx
index df5514ea1cb..09126312d32 100644
--- a/gui/fitpanelv7/src/RFitPanel.cxx
+++ b/gui/fitpanelv7/src/RFitPanel.cxx
@@ -451,8 +451,7 @@ std::unique_ptr<TF1> ROOT::Experimental::RFitPanel::GetFitFunction(const std::st
 
       std::string formula = funcname.substr(6);
 
-      ROOT::Fit::DataRange drange;
-      model().GetRanges(drange);
+      ROOT::Fit::DataRange drange = model().GetRanges();
 
       double xmin, xmax, ymin, ymax, zmin, zmax;
       drange.GetRange(xmin, xmax, ymin, ymax, zmin, zmax);
@@ -537,35 +536,62 @@ void ROOT::Experimental::RFitPanel::DrawScan(const std::string &model)
    // printf("SCAN Points %d, Par %d, Min %d, Max %d\n", obj->fScanPoints, obj->fScanPar, obj->fScanMin, obj->fScanMax);
 }
 
-/// Returns pad where histogram should be drawn
-/// Ensure that histogram is on the first place
+///////////////////////////////////////////////////////////////////
+/// Returns pad where histogram is drawn
+/// If canvas not exists, create new one
 
 TPad *ROOT::Experimental::RFitPanel::GetDrawPad(TObject *obj)
 {
-   if (model().fNoDrawing || model().fNoStoreDraw)
+   if (!obj || model().fNoDrawing || model().fNoStoreDraw)
       return nullptr;
 
+   std::function<TPad*(TPad*)> check = [&](TPad *pad) {
+      TPad *res = nullptr;
+      if (pad) {
+         TIter next(pad->GetListOfPrimitives());
+         TObject *prim = nullptr;
+         while (!res && (prim = next())) {
+            res = (prim == obj) ? pad : check(dynamic_cast<TPad *>(prim));
+         }
+      }
 
-   if (fCanvName.empty()) {
-      gPad = nullptr;
-      return nullptr;
-   }
+      return res;
+   };
 
-   TCanvas *canv = (TCanvas *) gROOT->GetListOfCanvases()->FindObject(fCanvName.c_str());
+   if (!fCanvName.empty()) {
+      auto drawcanv = dynamic_cast<TCanvas *> (gROOT->GetListOfCanvases()->FindObject(fCanvName.c_str()));
+      auto drawpad = check(drawcanv);
+      if (drawpad) {
+         drawpad->cd();
+         return drawpad;
+      }
+      if (drawcanv) {
+         drawcanv->Clear();
+         drawcanv->cd();
+         obj->Draw();
+         return drawcanv;
+      }
+      fCanvName.clear();
+   }
 
-   if (!canv) {
-      canv = gROOT->MakeDefCanvas();
-      canv->SetName(fCanvName.c_str());
-      canv->SetTitle("Fit panel drawings");
+   TObject *c = nullptr;
+   TIter nextc(gROOT->GetListOfCanvases());
+   while ((c = nextc())) {
+      auto drawpad = check(dynamic_cast<TCanvas* >(c));
+      if (drawpad) {
+         drawpad->cd();
+         fCanvName = c->GetName();
+         return drawpad;
+      }
    }
 
-   canv->cd();
+   auto canv = gROOT->MakeDefCanvas();
+   canv->SetName("fpc");
+   canv->SetTitle("Fit panel drawings");
+   fCanvName = canv->GetName();
 
-   // TODO: provide proper draw options
-   if (obj && !canv->FindObject(obj)) {
-      canv->Clear();
-      obj->Draw();
-   }
+   canv->cd();
+   obj->Draw();
 
    return canv;
 }
@@ -705,17 +731,10 @@ bool ROOT::Experimental::RFitPanel::DoFit()
    auto f1 = GetFitFunction(m.fSelectedFunc);
    if (!f1) return false;
 
-   ROOT::Fit::DataRange drange;
-   ROOT::Math::MinimizerOptions minOption;
-   Foption_t fitOpts;
-
-   m.GetRanges(drange);
-   m.GetFitOptions(fitOpts);
-   m.GetMinimizerOptions(minOption);
-
-   // std::string drawOpts = m.GetDrawOption();
-
-   TString strDrawOpts;
+   auto drange = m.GetRanges();
+   auto minOption = m.GetMinimizerOptions();
+   auto fitOpts = m.GetFitOptions();
+   auto drawOpts = m.GetDrawOption();
 
    TVirtualPad *save = gPad;
 
@@ -726,7 +745,7 @@ bool ROOT::Experimental::RFitPanel::DoFit()
 
          TH1 *hist = dynamic_cast<TH1*>(obj);
          if (hist)
-            ROOT::Fit::FitObject(hist, f1.get(), fitOpts, minOption, strDrawOpts, drange);
+            ROOT::Fit::FitObject(hist, f1.get(), fitOpts, minOption, drawOpts, drange);
 
          break;
       }
@@ -734,14 +753,14 @@ bool ROOT::Experimental::RFitPanel::DoFit()
 
          TGraph *gr = dynamic_cast<TGraph*>(obj);
          if (gr)
-            ROOT::Fit::FitObject(gr, f1.get(), fitOpts, minOption, strDrawOpts, drange);
+            ROOT::Fit::FitObject(gr, f1.get(), fitOpts, minOption, drawOpts, drange);
          break;
       }
       case kObjectMultiGraph: {
 
          TMultiGraph *mg = dynamic_cast<TMultiGraph*>(obj);
          if (mg)
-            ROOT::Fit::FitObject(mg, f1.get(), fitOpts, minOption, strDrawOpts, drange);
+            ROOT::Fit::FitObject(mg, f1.get(), fitOpts, minOption, drawOpts, drange);
 
          break;
       }
@@ -749,7 +768,7 @@ bool ROOT::Experimental::RFitPanel::DoFit()
 
          TGraph2D *g2d = dynamic_cast<TGraph2D*>(obj);
          if (g2d)
-            ROOT::Fit::FitObject(g2d, f1.get(), fitOpts, minOption, strDrawOpts, drange);
+            ROOT::Fit::FitObject(g2d, f1.get(), fitOpts, minOption, drawOpts, drange);
 
          break;
       }
@@ -764,8 +783,11 @@ bool ROOT::Experimental::RFitPanel::DoFit()
       }
    }
 
-   if (m.fSame && f1)
-      f1->Draw("same");
+   if (m.fSame && f1) {
+      TF1 *copy = copyTF1(f1.get());
+      copy->SetBit(kCanDelete);
+      copy->Draw("same");
+   }
 
    if (pad) {
       pad->Modified();
diff --git a/gui/fitpanelv7/src/RFitPanelModel.cxx b/gui/fitpanelv7/src/RFitPanelModel.cxx
index b13ea858a7b..acff1be268a 100644
--- a/gui/fitpanelv7/src/RFitPanelModel.cxx
+++ b/gui/fitpanelv7/src/RFitPanelModel.cxx
@@ -238,44 +238,22 @@ void ROOT::Experimental::RFitPanelModel::UpdateAdvanced(TF1 *func)
 }
 
 
-std::string ROOT::Experimental::RFitPanelModel::GetFitOption()
+ROOT::Fit::DataRange ROOT::Experimental::RFitPanelModel::GetRanges()
 {
-   std::string opt = fFitMethod;
+   ROOT::Fit::DataRange drange;
 
-   if (fIntegral) opt.append("I");
-   if (fUseRange) opt.append("R");
-   if (fBestErrors) opt.append("E");
-   if (fImproveFitResults) opt.append("M");
-   if (fAddToList) opt.append("+");
-   if (fUseGradient) opt.append("G");
-
-   if (fEmptyBins1)
-      opt.append("WW");
-   else if (fAllWeights1)
-      opt.append("W");
-
-   if (fNoStoreDraw)
-      opt.append("N");
-   else if (fNoDrawing)
-      opt.append("O");
-
-   return opt;
-}
-
-void ROOT::Experimental::RFitPanelModel::GetRanges(ROOT::Fit::DataRange &drange)
-{
-   if (fDim > 0)  {
+   if (fDim > 0)
       drange.AddRange(0, fRangeX[0], fRangeX[1]);
-   }
 
-   if ( fDim > 1 ) {
+   if ( fDim > 1 )
       drange.AddRange(1, fRangeY[0], fRangeY[1]);
-   }
 
+   return drange;
 }
 
-void ROOT::Experimental::RFitPanelModel::GetFitOptions(Foption_t &fitOpts)
+Foption_t ROOT::Experimental::RFitPanelModel::GetFitOptions()
 {
+   Foption_t fitOpts;
    fitOpts.Range    = fUseRange;
    fitOpts.Integral = fIntegral;
    fitOpts.More     = fImproveFitResults;
@@ -312,10 +290,14 @@ void ROOT::Experimental::RFitPanelModel::GetFitOptions(Foption_t &fitOpts)
       fitOpts.Robust = 1;
       fitOpts.hRobust = fRobustLevel;
    }
+
+   return fitOpts;
 }
 
-void ROOT::Experimental::RFitPanelModel::GetMinimizerOptions(ROOT::Math::MinimizerOptions &minOpts)
+ROOT::Math::MinimizerOptions ROOT::Experimental::RFitPanelModel::GetMinimizerOptions()
 {
+   ROOT::Math::MinimizerOptions minOpts;
+
    if (fLibrary == 0)
       minOpts.SetMinimizerType ( "Minuit");
    else if (fLibrary == 1)
@@ -363,11 +345,14 @@ void ROOT::Experimental::RFitPanelModel::GetMinimizerOptions(ROOT::Math::Minimiz
    minOpts.SetTolerance(fMaxTolerance);
    minOpts.SetMaxIterations(fMaxIterations);
    minOpts.SetMaxFunctionCalls(fMaxIterations);
+
+   return minOpts;
 }
 
-std::string ROOT::Experimental::RFitPanelModel::GetDrawOption()
+TString ROOT::Experimental::RFitPanelModel::GetDrawOption()
 {
-   return "";
+   TString res;
+   return res;
 }
 
 
-- 
GitLab