From 9dc62a6723d4432cf8c3b280d74acb93da0304ef Mon Sep 17 00:00:00 2001
From: sgorbuno <se.gorbunov@gsi.de>
Date: Sun, 22 Nov 2020 17:22:04 +0000
Subject: [PATCH] CbmQaHist wrapper for histograms that ensures update of the
 stat window

---
 core/qa/CMakeLists.txt     |   4 +-
 core/qa/CbmQaBaseLinkDef.h |   6 ++
 core/qa/CbmQaHist.cxx      |  14 +++++
 core/qa/CbmQaHist.h        | 125 +++++++++++++++++++++++++++++++++++++
 4 files changed, 147 insertions(+), 2 deletions(-)
 create mode 100644 core/qa/CbmQaHist.cxx
 create mode 100644 core/qa/CbmQaHist.h

diff --git a/core/qa/CMakeLists.txt b/core/qa/CMakeLists.txt
index 5ba68ecd51..7bfffef677 100644
--- a/core/qa/CMakeLists.txt
+++ b/core/qa/CMakeLists.txt
@@ -21,11 +21,11 @@ link_directories( ${LINK_DIRECTORIES})
 set(SRCS
 CbmQaCanvas.cxx
 CbmQaPie.cxx
+CbmQaHist.cxx
 )
 
 set(LINKDEF CbmQaBaseLinkDef.h)
 Set(LIBRARY_NAME CbmQaBase)
-Set(DEPENDENCIES
-)
+Set(DEPENDENCIES)
 
 GENERATE_LIBRARY()
diff --git a/core/qa/CbmQaBaseLinkDef.h b/core/qa/CbmQaBaseLinkDef.h
index 3241d06482..f013bc70d2 100644
--- a/core/qa/CbmQaBaseLinkDef.h
+++ b/core/qa/CbmQaBaseLinkDef.h
@@ -4,7 +4,13 @@
 #pragma link off all classes;
 #pragma link off all functions;
 
+#pragma link C++ nestedclasses;
+#pragma link C++ nestedtypedef;
+
 #pragma link C++ class CbmQaCanvas - ;
 #pragma link C++ class CbmQaPieSlice + ;
 #pragma link C++ class CbmQaPie - ;
+#pragma link C++ class CbmQaH1F + ;
+#pragma link C++ class CbmQaH1D + ;
+
 #endif
diff --git a/core/qa/CbmQaHist.cxx b/core/qa/CbmQaHist.cxx
new file mode 100644
index 0000000000..c080c12f24
--- /dev/null
+++ b/core/qa/CbmQaHist.cxx
@@ -0,0 +1,14 @@
+/// \file   CbmQaHist.cxx
+/// \brief  Implementation of the CbmQaHist class
+/// \author Sergey Gorbunov <se.gorbunov@gsi.de>
+/// \date   22.11.2020
+
+#include "CbmQaHist.h"
+
+templateClassImp(CbmQaHist);
+
+// create definitions of specific CbmQaHist classes,
+// otherwise they will not be linked by the ROOT linker
+//
+template class CbmQaHist<TH1F>;
+template class CbmQaHist<TH1D>;
diff --git a/core/qa/CbmQaHist.h b/core/qa/CbmQaHist.h
new file mode 100644
index 0000000000..a64de60d65
--- /dev/null
+++ b/core/qa/CbmQaHist.h
@@ -0,0 +1,125 @@
+/// \file   CbmQaHist.h
+/// \brief  Definition of the CbmQaHist class
+/// \author Sergey Gorbunov <se.gorbunov@gsi.de>
+/// \date   22.11.2020
+
+#ifndef CbmQaHist_H
+#define CbmQaHist_H
+
+#include "CbmQaCanvas.h"
+#include "TFitResultPtr.h"
+#include "TH1D.h"
+#include "TH1F.h"
+#include "TStyle.h"
+#include "TVirtualPad.h"
+/// A modification of TH* classes that keeps statistics & fit drawing options
+/// and resizes the stat window accordingly without actual drawing.
+/// In the original classes, hist->Draw() & canv->Update() must be called
+/// for resetting Stat/Fit window.
+///
+template<class HistTypeT>
+class CbmQaHist : public HistTypeT {
+public:
+  /// Default constructor only for the streamer
+  CbmQaHist() : HistTypeT() {
+    // we don't call SetOptStatFit() here since it will call Clone()
+    // which calls this default constructor in an endless recursion
+    if (gStyle) {
+      fOptStat = gStyle->GetOptStat();
+      fOptFit  = gStyle->GetOptFit();
+    }
+  }
+
+  /// Copy constructor
+  CbmQaHist(const CbmQaHist& h) : HistTypeT(h) {
+    SetOptStatFit(h.fOptStat, h.fOptFit);
+  }
+
+  /// Reimplementation of all other HistTypeT constructors
+  /// that creates a stat window with current gStyle options.
+  template<typename... Types>
+  CbmQaHist(Types... args) : HistTypeT(args...) {
+    if (gStyle) { SetOptStatFit(gStyle->GetOptStat(), gStyle->GetOptFit()); }
+  }
+
+  /// Destructor
+  ~CbmQaHist() {}
+
+  /// Reimplementation of Fit()
+  /// that suppresses an immediate drawing in the active window
+  ///
+  template<typename... Types>
+  TFitResultPtr Fit(Types... args) {
+    TVirtualPad* padsav = gPad;
+    GetCanvas().cd();
+    auto ret = HistTypeT::Fit(args...);
+    GetCanvas().Clear();
+    if (padsav) padsav->cd();
+    auto* f = this->GetFunction("gaus");
+    if (f) {
+      f->SetParName(0, "Peak");
+      f->SetParName(1, "#mu");
+      f->SetParName(2, "#sigma");
+      f->SetLineColor(kRed);
+      f->SetLineWidth(3);
+    }
+    return ret;
+  }
+
+  /// Set stat drawing options and resize the stat window
+  void SetOptStat(Int_t stat = 1) { SetOptStatFit(stat, fOptFit); }
+
+  /// Set fit drawing options and resize the stat window
+  void SetOptFit(Int_t fit = 1) { SetOptStatFit(fOptStat, fit); }
+
+  /// Set stat & fit drawing options and resize the stat window
+  void SetOptStatFit(int stat, int fit) {
+    fOptStat = stat;
+    fOptFit  = fit;
+    if (!gStyle) { return; }
+    TVirtualPad* savePad = gPad;
+    int saveStat         = gStyle->GetOptStat();
+    int saveFit          = gStyle->GetOptFit();
+
+    this->SetStats(0);  // remove the old stat window
+    this->SetStats(1);  // set the flag to create thes stat window during Draw()
+    CbmQaHist* tmp = (CbmQaHist*) this->Clone("myClone");
+    GetCanvas().cd();
+    gStyle->SetOptStat(fOptStat);
+    gStyle->SetOptFit(fOptFit);
+    // the only way to create and auto-size the stat window
+    tmp->Draw();
+    GetCanvas().Update();
+    // move the stat window to *this
+    TObject* obj = tmp->FindObject("stats");
+    // the list of functions seems always to exist, but let's check it
+    if (obj && this->GetListOfFunctions()) {
+      tmp->GetListOfFunctions()->Remove(obj);
+      this->GetListOfFunctions()->Add(obj);
+    }
+    GetCanvas().Clear();
+    gStyle->SetOptStat(saveStat);
+    gStyle->SetOptFit(saveFit);
+    if (savePad) savePad->cd();
+  }
+
+private:
+  /// a static canvas for temporary drawing
+  static CbmQaCanvas& GetCanvas() {
+    /// the static variable will be initialised at the first call;
+    /// deleted at the application end (c++11)
+    static CbmQaCanvas tmp("CbmQaTempCanvas", "CbmQaTempCanvas", 1, 1);
+    return tmp;
+  }
+
+  int fOptStat = 1;
+  int fOptFit  = 0;
+
+  ClassDefNV(CbmQaHist, 1);
+};
+
+// shortcuts
+typedef CbmQaHist<TH1F> CbmQaH1F;
+typedef CbmQaHist<TH1D> CbmQaH1D;
+
+#endif
-- 
GitLab