The interactive export always produced the classic 800x600 layout, so neither the size of the musrview window nor the proportions the user had dragged the 'Fit parameters', 'Theory' and 'RUN INFO' panels to showed up in the saved graphics. The page now measures its current view -- window size without toolbar and status bar, the height of the title and the run info, the width of the parameter/theory column, the split between the two, plus the font size of the panels -- and hands it over with the 'save:' message. A boundary which is a splitter bar on screen is reported as the bar's centre line, since the export draws the blocks edge to edge. The C++ side takes that as the new ExportGeometry, which replaces the hard wired fractions in RenderGraphics(). With a font size given, the panels keep the size the text has on screen (with the line spacing of the HTML panels) rather than TPaveText/TLegend scaling the text up to the pave: a larger window then shows more text instead of bigger text, as the HTML panels do. The text is only ever scaled down, as far as the pave needs it in height and in width, the latter measured the way TPaveText measures it. ExportGeometry's defaults are exactly the previous layout, hence the --png/--pdf/... batch export, which has no window to take anything over from, is unchanged -- bit for bit, the musrview_check reference images included. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
236 lines
11 KiB
C++
236 lines
11 KiB
C++
/***************************************************************************
|
|
|
|
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 <functional>
|
|
#include <utility>
|
|
#include <memory>
|
|
#include <string>
|
|
#include <vector>
|
|
|
|
#include <TCanvas.h>
|
|
#include <TString.h>
|
|
#include <TH1F.h>
|
|
#include <TLatex.h>
|
|
#include <TLegend.h>
|
|
#include <TMultiGraph.h>
|
|
#include <TPaveText.h>
|
|
|
|
#include <ROOT/RWebWindow.hxx>
|
|
|
|
#include "PMusrViewMode.h"
|
|
#include "PMusrViewModel.h"
|
|
|
|
namespace musrview {
|
|
|
|
//--------------------------------------------------------------------------
|
|
/**
|
|
* \brief ROOT7/web based front end of musrview.
|
|
*
|
|
* <p>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.
|
|
*
|
|
* <p>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.
|
|
*
|
|
* <p>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().
|
|
*
|
|
* <p>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<void(Int_t)> 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<PMusrViewModel> fModel; ///< the data layer
|
|
PMusrViewMode fMode{}; ///< what is currently shown
|
|
|
|
std::shared_ptr<ROOT::RWebWindow> fWindow; ///< the web window
|
|
std::function<void(Int_t)> fDoneCallback{}; ///< invoked when the user quits
|
|
|
|
std::unique_ptr<TH1F> fFrame; ///< drawing frame of the spectra
|
|
std::unique_ptr<TMultiGraph> fMultiGraph; ///< non-muSR data/theory
|
|
std::unique_ptr<TLegend> fPlotLegend; ///< legend of the non-muSR plot
|
|
std::unique_ptr<TLatex> fPhaseLatex; ///< Fourier phase label
|
|
std::unique_ptr<TLatex> 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<std::pair<TObject*, TString>> &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<std::string> &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_
|