From 77e246726771d2f5025487ad6fdb16b8bca4dfe9 Mon Sep 17 00:00:00 2001 From: Matthias Puchner <github@mpuchner.de> Date: Thu, 30 Sep 2021 07:56:21 +0200 Subject: [PATCH] introduce descriptor class to describe properties of a double value --- GUI/Models/DoubleDescriptor.cpp | 81 ++++++++++++++++++++++++++++ GUI/Models/DoubleDescriptor.h | 94 +++++++++++++++++++++++++++++++++ GUI/Models/ModelPath.cpp | 6 +++ GUI/Models/ModelPath.h | 2 + GUI/Models/Unit.cpp | 50 ++++++++++++++++++ GUI/Models/Unit.h | 40 ++++++++++++++ 6 files changed, 273 insertions(+) create mode 100644 GUI/Models/DoubleDescriptor.cpp create mode 100644 GUI/Models/DoubleDescriptor.h create mode 100644 GUI/Models/Unit.cpp create mode 100644 GUI/Models/Unit.h diff --git a/GUI/Models/DoubleDescriptor.cpp b/GUI/Models/DoubleDescriptor.cpp new file mode 100644 index 00000000000..2c2d879fd17 --- /dev/null +++ b/GUI/Models/DoubleDescriptor.cpp @@ -0,0 +1,81 @@ +// ************************************************************************************************ +// +// BornAgain: simulate and fit reflection and scattering +// +//! @file GUI/Models/DoubleDescriptor.cpp +//! @brief Implements class DoubleDescriptor +//! +//! @homepage http://www.bornagainproject.org +//! @license GNU General Public License v3 or higher (see COPYING) +//! @copyright Forschungszentrum Jülich GmbH 2021 +//! @authors Scientific Computing Group at MLZ (see CITATION, AUTHORS) +// +// ************************************************************************************************ + +#include "GUI/Models/DoubleDescriptor.h" +#include "GUI/Models/ModelPath.h" +#include "GUI/Models/SessionItem.h" + +DoubleDescriptor::DoubleDescriptor(const QString& label, SessionItem* item, + const variant<QString, Unit>& unit) + : DoubleDescriptor( + label, item->toolTip(), item->decimals(), item->limits(), + [=](double d) { item->setValue(d); }, [=]() { return item->value().toDouble(); }, unit) +{ + path = [=] { return GUI::Model::Path::getPathFromItem(item); }; +} + +DoubleDescriptor::DoubleDescriptor(SessionItem* item, const variant<QString, Unit>& unit) + : DoubleDescriptor(item->displayName(), item, unit) +{ +} + +DoubleDescriptor::DoubleDescriptor(const QString& label, const QString& tooltip, + function<void(double)> setter, function<double()> getter, + const variant<QString, Unit>& unit) + : DoubleDescriptor(label, tooltip, 3, RealLimits::nonnegative(), setter, getter, unit) +{ +} + +DoubleDescriptor::DoubleDescriptor(const QString& label, const QString& tooltip, int decimals, + const RealLimits& limits, function<void(double)> setter, + function<double()> getter, const variant<QString, Unit>& unit) + : label(label) + , tooltip(tooltip) + , decimals(decimals) + , limits(limits) + , set(setter) + , get(getter) + , unit(unit) +{ + // #baLayerEditor the following path creation has to be implemented when SessionItem migration + // has finished + path = [] { return QString(); }; +} + +DoubleDescriptor::DoubleDescriptor() {} + +DoubleDescriptor::DoubleDescriptor(const QString& label, const QString& tooltip, double* var, + const variant<QString, Unit>& unit) + : DoubleDescriptor(label, tooltip, 3, RealLimits::nonnegative(), var, unit) + +{ +} + +DoubleDescriptor::DoubleDescriptor(const QString& label, const QString& tooltip, int decimals, + const RealLimits& limits, double* var, + const variant<QString, Unit>& unit) + : DoubleDescriptor( + label, tooltip, decimals, limits, [=](double v) { *var = v; }, [=] { return *var; }, unit) +{ +} + +void DoubleDescriptor::init(SessionItem* item, const variant<QString, Unit>& unit) +{ + operator=(DoubleDescriptor(item, unit)); +} + +DoubleDescriptor::operator double() const +{ + return get(); +} diff --git a/GUI/Models/DoubleDescriptor.h b/GUI/Models/DoubleDescriptor.h new file mode 100644 index 00000000000..34d2a87d9e4 --- /dev/null +++ b/GUI/Models/DoubleDescriptor.h @@ -0,0 +1,94 @@ +// ************************************************************************************************ +// +// BornAgain: simulate and fit reflection and scattering +// +//! @file GUI/Models/DoubleDescriptor.h +//! @brief Defines class DoubleDescriptor +//! +//! @homepage http://www.bornagainproject.org +//! @license GNU General Public License v3 or higher (see COPYING) +//! @copyright Forschungszentrum Jülich GmbH 2021 +//! @authors Scientific Computing Group at MLZ (see CITATION, AUTHORS) +// +// ************************************************************************************************ + +#ifndef BORNAGAIN_GUI_MODELS_DOUBLEDESCRIPTOR_H +#define BORNAGAIN_GUI_MODELS_DOUBLEDESCRIPTOR_H + +#include "Fit/Param/RealLimits.h" +#include "GUI/Models/Unit.h" +#include <QString> +#include <functional> +#include <variant> + +class SessionItem; + +using std::function; +using std::variant; + +//! Describes properties of a double value which are necessary to allow GUI representation, editing +//! the value, undo/redo, unit conversion. +//! +//! By using this class, the underlying data scheme is hidden from the user of the data. This e.g. +//! eases SessionItem migration. The underlying implementation can be a SessionItem, a simple double +//! member, or any other construction to hold a double value. +class DoubleDescriptor { + +public: + //! Operates on a session item. The settings (like decimals, limits) are taken from the session + //! item. + //! Only for easier migration. Should be removed after SessionItem refactoring. + DoubleDescriptor(SessionItem* item, const variant<QString, Unit>& unit); + + //! Operates on a session item. The settings (like decimals, limits) are taken from the session + //! item. + //! Only for easier migration. Should be removed after SessionItem refactoring. + DoubleDescriptor(const QString& label, SessionItem* item, const variant<QString, Unit>& unit); + +private: // private as long as path initialization is not included in params (to be done after + // SessionItem migration) + //! Operates on a double value (e.g a member variable). + DoubleDescriptor(const QString& label, const QString& tooltip, int decimals, + const RealLimits& limits, double* var, const variant<QString, Unit>& unit); + + //! Operates on a double value (e.g a member variable). + //! Decimals is set to 3, limits is set to nonnegative + DoubleDescriptor(const QString& label, const QString& tooltip, double* var, + const variant<QString, Unit>& unit); + + //! Operates on any kind of storage (e.g. session items), by using setter/getter methods + DoubleDescriptor(const QString& label, const QString& tooltip, int decimals, + const RealLimits& limits, function<void(double)> setter, + function<double()> getter, const variant<QString, Unit>& unit); + + //! Operates on any kind of storage (e.g. session items), by using setter/getter methods + //! decimals is set to 3, limits is set to nonnegative + DoubleDescriptor(const QString& label, const QString& tooltip, function<void(double)> setter, + function<double()> getter, const variant<QString, Unit>& unit); + +public: + //! For delayed initialization. + //! Call init before usage! + DoubleDescriptor(); + + //! Initialize with a session item. To be used if an initialization already in the constructor + //! is not possible. Only for easier migration. Should be removed after SessionItem refactoring. + void init(SessionItem* item, const variant<QString, Unit>& unit); + + //! Return the current value of the handled parameter. + operator double() const; + + QString label; //!< A label text (short, no trailing colon) + QString tooltip; //!< Tooltip text + int decimals = 0; //!< numbers of decimals to be shown in an edit control + RealLimits limits; //!< Limits of the value. + function<void(double)> set = nullptr; //!< function to set the value + function<double()> get = nullptr; //!< function to get the current value + variant<QString, Unit> unit = Unit::undefined; //!< Unit of the value (internal unit only!) + function<QString()> path = nullptr; //<! Path describing this value. Used e.g. for undo/redo +}; + +typedef QList<DoubleDescriptor> DoubleDescriptors; + + +#endif // BORNAGAIN_GUI_MODELS_DOUBLEDESCRIPTOR_H diff --git a/GUI/Models/ModelPath.cpp b/GUI/Models/ModelPath.cpp index 24cc43a894f..a2f1195b79a 100644 --- a/GUI/Models/ModelPath.cpp +++ b/GUI/Models/ModelPath.cpp @@ -95,3 +95,9 @@ const SessionItem* GUI::Model::Path::ancestor(const SessionItem* item, return cur; } + +QString GUI::Model::Path::getPathFromItem(SessionItem* item) +{ + ASSERT(item->model()); // if assert, item is not completely initialized + return getPathFromIndex(item->model()->indexOfItem(item)); +} diff --git a/GUI/Models/ModelPath.h b/GUI/Models/ModelPath.h index f70740cbd70..3cf7792d67b 100644 --- a/GUI/Models/ModelPath.h +++ b/GUI/Models/ModelPath.h @@ -27,6 +27,8 @@ namespace GUI::Model::Path { QString getPathFromIndex(const QModelIndex& index); +QString getPathFromItem(SessionItem* item); + QModelIndex getIndexFromPath(const SessionModel* model, const QString& path); SessionItem* getItemFromPath(const QString& relPath, const SessionItem* parent); diff --git a/GUI/Models/Unit.cpp b/GUI/Models/Unit.cpp new file mode 100644 index 00000000000..87bf0902c54 --- /dev/null +++ b/GUI/Models/Unit.cpp @@ -0,0 +1,50 @@ +// ************************************************************************************************ +// +// BornAgain: simulate and fit reflection and scattering +// +//! @file GUI/Models/Unit.cpp +//! @brief Implements class Unit +//! +//! @homepage http://www.bornagainproject.org +//! @license GNU General Public License v3 or higher (see COPYING) +//! @copyright Forschungszentrum Jülich GmbH 2021 +//! @authors Scientific Computing Group at MLZ (see CITATION, AUTHORS) +// +// ************************************************************************************************ + +#include "GUI/Models/Unit.h" +#include "Base/Const/Units.h" +#include "Base/Utils/Assert.h" + +double convert(double d, Unit from, Unit to) +{ + if (from == Unit::undefined || to == Unit::undefined || from == to) + return d; + + if (from == Unit::angstrom && to == Unit::nanometer) + return d / 10.0; + + if (from == Unit::nanometer && to == Unit::angstrom) + return d * 10.0; + + if (from == Unit::angstromPower2 && to == Unit::nanometerPower2) + return d / 100.0; + + if (from == Unit::nanometerPower2 && to == Unit::angstromPower2) + return d * 100.0; + + if (from == Unit::angstromPowerMinus2 && to == Unit::nanometerPowerMinus2) + return d * 100.0; + + if (from == Unit::nanometerPowerMinus2 && to == Unit::angstromPowerMinus2) + return d / 100.0; + + if (from == Unit::radiant && to == Unit::degree) + return Units::rad2deg(d); + + if (from == Unit::degree && to == Unit::radiant) + return Units::deg2rad(d); + + ASSERT(false); // no conversion implemented + return d; +} diff --git a/GUI/Models/Unit.h b/GUI/Models/Unit.h new file mode 100644 index 00000000000..661f6aa0a89 --- /dev/null +++ b/GUI/Models/Unit.h @@ -0,0 +1,40 @@ +// ************************************************************************************************ +// +// BornAgain: simulate and fit reflection and scattering +// +//! @file GUI/Models/Unit.h +//! @brief Defines class Unit +//! +//! @homepage http://www.bornagainproject.org +//! @license GNU General Public License v3 or higher (see COPYING) +//! @copyright Forschungszentrum Jülich GmbH 2021 +//! @authors Scientific Computing Group at MLZ (see CITATION, AUTHORS) +// +// ************************************************************************************************ + +#ifndef BORNAGAIN_GUI_MODELS_UNIT_H +#define BORNAGAIN_GUI_MODELS_UNIT_H + +//! Defines units, mainly to be able to convert between units. +//! E.g. internal unit is nanometer, displayed unit is angstrom. +//! Units which do not support conversion do not have to be +//! part of the enum, since the relevant code parts support defining a +//! unit via enum or via string +enum class Unit { + undefined, + unitless, + nanometer, + nanometerPower2, + nanometerPowerMinus2, + angstrom, + angstromPower2, + angstromPowerMinus2, + degree, + radiant +}; + +//! Convert the given value d from unit "from" to unit "to" +//! Throws an exception if no conversion possible. +double convert(double d, Unit from, Unit to); + +#endif // BORNAGAIN_GUI_MODELS_UNIT_H -- GitLab