/*************************************************************************** PMusrWebCanvas.h Author: Andreas Suter e-mail: andreas.suter@psi.ch ***************************************************************************/ /*************************************************************************** * Copyright (C) 2007-2026 by Andreas Suter * * andreas.suter@psi.ch * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the * * Free Software Foundation, Inc., * * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * ***************************************************************************/ #ifndef _PMUSRWEBCANVAS_H_ #define _PMUSRWEBCANVAS_H_ #include #include #include #include #include #include #include #include #include #include #include #include #include #include "PMusrViewMode.h" #include "PMusrViewModel.h" namespace musrview { //-------------------------------------------------------------------------- /** * \brief ROOT7/web based front end of musrview. * *

Following the ROOT7 architecture (see S. Linev et al., J. Phys. Conf. Ser. * 1525 (2020) 012092), the graphics are fully decoupled from the data: the * C++ side is the server and holds the model (PMusrViewModel), the client is a * web page which renders the spectra with JSROOT and the text blocks as plain * HTML. Both talk to each other through an ROOT::RWebWindow websocket, the * payload being JSON produced by TBufferJSON. * *

This buys three things which the former TCanvas based implementation could * not provide: * * - The parameter/theory/info blocks are HTML panels with their own scrollbar * instead of TPaveText/TLegend objects which scale their font down until the * content is no longer readable. * - Every block except the spectra can be shown and hidden individually. * - The command keys are handled by the page, which knows whether a text input * currently has the focus. Typing a 'd' or an 'f' into a text/latex label can * therefore no longer trigger the difference/Fourier command. * *

The window can either be displayed in the user's standard browser or in an * embedded Qt6 WebEngine window, in which case musrview looks and behaves like * the stand-alone application it has always been. Which one is used is decided * by the string handed to Show(). * *

The graphics export (png, pdf, ...) does not go through the browser but * builds a plain TCanvas with the classic layout, so that batch operation stays * independent of any browser installation. */ class PMusrWebCanvas { public: PMusrWebCanvas(Int_t plotNumber, const std::string &title, Int_t ww, Int_t wh, PMsrFourierStructure fourierDefault, const PIntVector &markerList, const PIntVector &colorList, Bool_t batch, Bool_t fourier, Bool_t avg, Bool_t theoAsData); virtual ~PMusrWebCanvas(); PMusrWebCanvas(const PMusrWebCanvas &) = delete; PMusrWebCanvas &operator=(const PMusrWebCanvas &) = delete; #ifndef __MAKECLING__ /// Hands the msr-file handler to the model. void SetMsrHandler(PMsrHandler *msrHandler); /// Hands the run collection to the model. void SetRunListCollection(PRunListCollection *runList); #endif // __MAKECLING__ /// Builds the data of this plot block. Has to be called before anything else. Bool_t Build(); /// True if everything is in a usable state. Bool_t IsValid() const { return fValid; } /// Last error message. const std::string &GetLastError() const { return fLastError; } /// Seconds after which the window closes by itself; <= 0 means no timeout. void SetTimeout(Int_t timeout) { fTimeout = timeout; } /// Opens the window. \p where is "" (standard browser), "qt6", "chrome", ... Bool_t Show(const std::string &where); /// True once the user has closed the window. Bool_t IsDone() const { return fDone; } /// Closes the window and drops the connection. Needed so that musrview can /// terminate: an open RWebWindow keeps the process alive. void Close(); /// Called when the user quits; used to terminate the application. void SetDoneCallback(std::function cb) { fDoneCallback = std::move(cb); } /// Which of the title/parameters/theory/run-info blocks to include in the /// exported layout; mirrors the interactive view's panel visibility. struct PanelVisibility { Bool_t title{true}; Bool_t params{true}; Bool_t theory{true}; Bool_t info{true}; }; /// Size and proportions of the exported layout. The interactive view fills /// it in from its window, so that "Save graphics" reproduces what is on /// screen: the window size as well as how much of it the user has given to /// the title, to the 'Fit parameters'/'Theory' column and to the run info /// by dragging the splitters. The defaults are the classic 800x600 layout /// and are what the --png/--pdf/... batch export uses. struct ExportGeometry { Int_t width{800}; ///< canvas width [pixel] Int_t height{600}; ///< canvas height [pixel] Double_t titleFrac{0.05}; ///< height fraction of the title block Double_t infoFrac{0.10}; ///< height fraction of the run-info block Double_t sideFrac{0.25}; ///< width fraction of the parameter/theory column Double_t splitFrac{0.50}; ///< height fraction, measured from the bottom, at ///< which 'Fit parameters' and 'Theory' are split Double_t fontFrac{0.0}; ///< on-screen panel font height as a fraction of ///< the window height; <= 0 lets ROOT scale the text /// Clips everything into a range which still gives a usable layout. void Sanitize(); }; /// Writes the classic canvas layout into a graphics file named after the /// msr-file (batch export, e.g. --png). All panels are included and the /// default geometry is used, since there is no interactive view whose /// state could be mirrored. Bool_t SaveGraphics(const std::string &graphicsFormat); /// Writes the classic canvas layout into the current working directory and /// returns the URL (relative to the web window) it can be downloaded from; /// used by the interactive "Save graphics" toolbar entry. \p panels and /// \p geom mirror which blocks the current view has shown/hidden and how /// large the window and its panels currently are. Bool_t SaveGraphicsForDownload(const std::string &graphicsFormat, const PanelVisibility &panels, const ExportGeometry &geom, std::string &relUrl); /// The name/location that graphics files are derived from by default, /// without extension. std::string DefaultGraphicsBaseName() const; /// The graphics base name (without extension) carrying the given index. std::string GraphicsBaseName(Int_t plotNumber) const; /// Writes the currently shown data as ascii. Bool_t ExportData(const std::string &fileName); /// The current view mode. const PMusrViewMode &GetMode() const { return fMode; } /// The underlying model. PMusrViewModel *GetModel() { return fModel.get(); } private: Int_t fPlotNumber{-1}; ///< plot block number std::string fTitle{}; ///< msr-file title Int_t fWidth{800}; ///< window width Int_t fHeight{600}; ///< window height Bool_t fBatchMode{false}; ///< no window is opened Bool_t fStartWithFourier{false}; ///< start with the Fourier representation Bool_t fStartWithAvg{false}; ///< start with the averaged representation Bool_t fValid{false}; ///< true if usable Bool_t fDone{false}; ///< true once the user quit Int_t fTimeout{0}; ///< timeout in seconds std::string fLastError{}; ///< last error message std::string fMsrFileName{}; ///< msr-file name, used to derive graphics/export file names std::unique_ptr fModel; ///< the data layer PMusrViewMode fMode{}; ///< what is currently shown std::shared_ptr fWindow; ///< the web window std::function fDoneCallback{}; ///< invoked when the user quits std::unique_ptr fFrame; ///< drawing frame of the spectra std::unique_ptr fMultiGraph; ///< non-muSR data/theory std::unique_ptr fPlotLegend; ///< legend of the non-muSR plot std::unique_ptr fPhaseLatex; ///< Fourier phase label std::unique_ptr fRRFLatex; ///< RRF label //-- web communication ------------------------------------------------- void ProcessMessage(unsigned connid, const std::string &msg); void SendState(unsigned connid); void SendPlot(unsigned connid); void SendAll(unsigned connid); std::string BuildStateJson() const; /// Describes each run by its info line and its legend symbol. std::string BuildRunsJson() const; //-- plotting ---------------------------------------------------------- /// Collects the objects of the current view, each with its draw option. Bool_t CollectDrawables(std::vector> &out); /// Draws the spectra of the current mode into the given pad (graphics export). Bool_t FillPlotPad(TVirtualPad *pad); /// Builds the classic layout and writes it into the given graphics file, /// including only the panels \p panels marks visible, sized and split /// according to \p geom. Bool_t RenderGraphics(const std::string &fileName, const PanelVisibility &panels, const ExportGeometry &geom); /// Serializes the objects of the current view for JSROOT. Bool_t BuildPlotJson(TString &json); //-- helper ------------------------------------------------------------ static std::string JsonEscape(const std::string &str); static std::string JsonArray(const std::vector &vec); /// Applies a command coming from the page. Returns true if a redraw is due. Bool_t ApplyCommand(const std::string &cmd); }; } // namespace musrview #endif // _PMUSRWEBCANVAS_H_