diff --git a/GUI/Application/ApplicationSettings.cpp b/GUI/Application/ApplicationSettings.cpp index d80fa29769ca6d3aa1394595891a65fbe4cf9007..172db4ab03793a636cef29b981f0bb524d882a9c 100644 --- a/GUI/Application/ApplicationSettings.cpp +++ b/GUI/Application/ApplicationSettings.cpp @@ -25,6 +25,7 @@ const QString S_POS = "Pos"; const QString S_DEFAULT_FUNCTIONALITIES = "DefaultFunctionalities"; const QString S_SINGLE_INSTRUMENT_MODE = "SingleInstrumentMode"; const QString S_SINGLE_SAMPLE_MODE = "SingleSampleMode"; +const QString S_DEFAULT_UNIT_IS_ANGSTROM = "DefaultUnitIsAngstrom"; } // namespace bool ApplicationSettings::useNativeFileDialog() const @@ -86,6 +87,16 @@ void ApplicationSettings::setDefaultIsSingleSampleMode(bool b) QSettings().setValue(S_SINGLE_SAMPLE_MODE, b); } +bool ApplicationSettings::defaultUnitIsAngstrom() const +{ + return QSettings().value(S_DEFAULT_UNIT_IS_ANGSTROM, false).toBool(); +} + +void ApplicationSettings::setDefaultUnitIsAngstrom(bool b) const +{ + QSettings().setValue(S_DEFAULT_UNIT_IS_ANGSTROM, b); +} + void ApplicationSettings::saveWindowSizeAndPos(const QWidget* w) { ASSERT(!w->objectName().isEmpty()); diff --git a/GUI/Application/ApplicationSettings.h b/GUI/Application/ApplicationSettings.h index eb9cee0167ee8e7bbf1da4aaa3240348ce6b9bfa..d224b1f199cb855bfe09acfdc9045e3e3a864590 100644 --- a/GUI/Application/ApplicationSettings.h +++ b/GUI/Application/ApplicationSettings.h @@ -41,6 +41,9 @@ public: bool defaultIsSingleSampleMode() const; void setDefaultIsSingleSampleMode(bool b); + bool defaultUnitIsAngstrom() const; + void setDefaultUnitIsAngstrom(bool b) const; + void saveWindowSizeAndPos(const QWidget* w); void loadWindowSizeAndPos(QWidget* w); }; diff --git a/GUI/Models/ItemWithParticles.cpp b/GUI/Models/ItemWithParticles.cpp index 2955bb49b23d2177fbccdc60b1788f54a1130206..84bd20420e0baa42fc322d83ed552e4e01cb11bc 100644 --- a/GUI/Models/ItemWithParticles.cpp +++ b/GUI/Models/ItemWithParticles.cpp @@ -103,14 +103,14 @@ SelectionDescriptor<RotationItem*> ItemWithParticles::rotationMethod() d.currentItem = [=]() -> RotationItem* { return rotationItem(); }; - d.setCurrentIndex = [=](int current) { + d.currentIndexSetter = [=](int current) { if (auto item = getItem(T_TRANSFORMATION)) model()->removeItem(item); if (current > 0) createTransformationItem()->setRotationType(map[current].second); }; - d.currentIndex = [=]() { + d.currentIndexGetter = [=]() { auto item = rotationItem(); if (item == nullptr) return 0; diff --git a/GUI/Models/ParticleLayoutItem.cpp b/GUI/Models/ParticleLayoutItem.cpp index b1babb1589cb61854e05c6761b1900698e28e4ff..de0d5f97debdf16120859dc7acda84c523cd5621 100644 --- a/GUI/Models/ParticleLayoutItem.cpp +++ b/GUI/Models/ParticleLayoutItem.cpp @@ -129,7 +129,7 @@ SelectionDescriptor<InterferenceItem*> ParticleLayoutItem::interference() const d.currentItem = [=] { return dynamic_cast<InterferenceItem*>(getItem(T_INTERFERENCE)); }; - d.setCurrentIndex = [=](int current) { + d.currentIndexSetter = [=](int current) { if (auto item = getItem(T_INTERFERENCE)) model()->removeItem(item); if (current > 0) @@ -137,7 +137,7 @@ SelectionDescriptor<InterferenceItem*> ParticleLayoutItem::interference() const T_INTERFERENCE); }; - d.currentIndex = [=]() { + d.currentIndexGetter = [=]() { if (auto item = dynamic_cast<InterferenceItem*>(getItem(T_INTERFERENCE))) for (int i = 1; i < map.size(); i++) if (map[i].second == item->modelType()) diff --git a/GUI/Models/SelectionDescriptor.h b/GUI/Models/SelectionDescriptor.h index abd9a9b76a02ebc099daa72310f120e84034999f..43f7a283ce91f197f13765f2fcfe70d252ff0798 100644 --- a/GUI/Models/SelectionDescriptor.h +++ b/GUI/Models/SelectionDescriptor.h @@ -23,6 +23,18 @@ using std::function; +//! Abstract base class for SelectionDescriptor to ease referencing. +class AbstractSelectionDescriptor { +public: + virtual ~AbstractSelectionDescriptor() = default; + + //! Set currently selected option + virtual void setCurrentIndex(int newIndex) const = 0; + + //! Get currently selected option + virtual int currentIndex() const = 0; +}; + //! Describes a selection (various possibilities and the current one). //! //! Usually a selection is presented as a combo box. @@ -38,7 +50,7 @@ using std::function; //! 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 GroupItem, a simple pointer //! member, a std::variant or any other construction to define a selection. -template <typename T> class SelectionDescriptor { +template <typename T> class SelectionDescriptor : public AbstractSelectionDescriptor { public: SelectionDescriptor() = default; @@ -51,7 +63,7 @@ public: { label = item->displayName(); options = item->value().value<ComboProperty>().getValues(); - setCurrentIndex = [=](int index) { + currentIndexSetter = [=](int index) { ComboProperty comboProperty = item->value().value<ComboProperty>(); if (comboProperty.currentIndex() != index) { @@ -59,18 +71,22 @@ public: item->setValue(QVariant::fromValue<ComboProperty>(comboProperty)); } }; - currentIndex = [=] { return item->value().value<ComboProperty>().currentIndex(); }; + currentIndexGetter = [=] { return item->value().value<ComboProperty>().currentIndex(); }; if constexpr (std::is_pointer<T>::value) currentItem = [=] { return dynamic_cast<T>(item->currentItem()); }; } - QString label; //!< A label text (short, no trailing colon) - QString tooltip; //!< Tooltip text - QStringList options; //!< List of options, usually presented as combo entries - function<void(int)> setCurrentIndex; //!< Function to set currently selected option - function<int()> currentIndex; //!< Function to get currently selected option - function<T()> currentItem; //!< Function to get currently selected item + virtual void setCurrentIndex(int newIndex) const override { currentIndexSetter(newIndex); } + + virtual int currentIndex() const override { return currentIndexGetter(); } + + QString label; //!< A label text (short, no trailing colon) + QString tooltip; //!< Tooltip text + QStringList options; //!< List of options, usually presented as combo entries + function<void(int)> currentIndexSetter; //!< Function to set currently selected option + function<int()> currentIndexGetter; //!< Function to get currently selected option + function<T()> currentItem; //!< Function to get currently selected item }; #endif // BORNAGAIN_GUI_MODELS_SELECTIONDESCRIPTOR_H diff --git a/GUI/Models/Unit.cpp b/GUI/Models/Unit.cpp index e49eab8d544d687fb0cc4ecb907f8cf2559dcb54..d40ed2da388572194d6d30bd51bab1fb8a74c767 100644 --- a/GUI/Models/Unit.cpp +++ b/GUI/Models/Unit.cpp @@ -63,15 +63,15 @@ QString unitAsString(const Unit& unit) case Unit::nanometer: return "nm"; case Unit::nanometerPower2: - return "nm²"; + return u8"nm\u00B2"; case Unit::nanometerPowerMinus2: - return "1/nm²"; + return u8"1/nm\u00B2"; case Unit::angstrom: - return "\303\205"; + return u8"\u00c5"; case Unit::angstromPower2: - return "\303\205²"; + return u8"\u00c5\u00B2"; case Unit::angstromPowerMinus2: - return "1/\303\205²"; + return u8"1/\u00c5\u00B2"; case Unit::degree: return "°"; case Unit::radiant: diff --git a/GUI/Views/SampleDesigner/LayerOrientedSampleEditor.cpp b/GUI/Views/SampleDesigner/LayerOrientedSampleEditor.cpp index 0767aa78945d373e3be802336c1cc5b0809d385c..3e26358008601339ce04c40389c4554328033baa 100644 --- a/GUI/Views/SampleDesigner/LayerOrientedSampleEditor.cpp +++ b/GUI/Views/SampleDesigner/LayerOrientedSampleEditor.cpp @@ -20,6 +20,7 @@ #include "GUI/Views/SampleDesigner/MultiLayerForm.h" #include "GUI/Views/SampleDesigner/SampleEditorController.h" +#include "GUI/Application/Application.h" #include <QBoxLayout> #include <QScrollArea> @@ -29,7 +30,7 @@ LayerOrientedSampleEditor::LayerOrientedSampleEditor(QWidget* parent) , m_undoAction(nullptr) , m_redoAction(nullptr) , m_showInlineEditButtonsAction(nullptr) - , m_asAngstrom(nullptr) + , m_asAngstromAction(nullptr) , m_currentMultiLayerItem(nullptr) { setAttribute(Qt::WA_StyledBackground, true); @@ -55,11 +56,29 @@ LayerOrientedSampleEditor::LayerOrientedSampleEditor(QWidget* parent) m_showInlineEditButtonsAction->setChecked(false); m_toolbar->addAction(m_showInlineEditButtonsAction); - m_asAngstrom = new QAction("A", this); - connect(m_asAngstrom, &QAction::toggled, this, &LayerOrientedSampleEditor::onAsAngstromToggled); - m_asAngstrom->setCheckable(true); - m_asAngstrom->setChecked(false); - m_toolbar->addAction(m_asAngstrom); + m_asAngstromAction = new QAction(this); + m_asAngstromAction->setIcon(QIcon(":/images/unit_angstrom.svg")); + m_asAngstromAction->setToolTip(u8"Use \u00c5ngstrom as unit (where applicable)"); + connect(m_asAngstromAction, &QAction::toggled, this, + &LayerOrientedSampleEditor::onUnitActionToggled); + m_asAngstromAction->setCheckable(true); + + auto* asNanometerAction = new QAction(this); + asNanometerAction->setIcon(QIcon(":/images/unit_nm.svg")); + asNanometerAction->setToolTip("Use nanometer as unit (where applicable)"); + connect(asNanometerAction, &QAction::toggled, this, + &LayerOrientedSampleEditor::onUnitActionToggled); + asNanometerAction->setCheckable(true); + + auto* ag = new QActionGroup(this); + ag->addAction(asNanometerAction); + ag->addAction(m_asAngstromAction); + if (baApp->settings().defaultUnitIsAngstrom()) + m_asAngstromAction->setChecked(true); + else + asNanometerAction->setChecked(true); + + m_toolbar->addActions(ag->actions()); } LayerOrientedSampleEditor::~LayerOrientedSampleEditor() @@ -108,6 +127,7 @@ void LayerOrientedSampleEditor::setCurrentSample(MultiLayerItem* multiLayerItem) m_currentMultiLayerWidget->setSizePolicy(QSizePolicy::Minimum, QSizePolicy::Minimum); m_scrollArea->setWidget(m_currentMultiLayerWidget); m_currentMultiLayerWidget->showInlineEditButtons(m_showInlineEditButtonsAction->isChecked()); + m_currentMultiLayerWidget->setUseAngstrom(m_asAngstromAction->isChecked()); updateActionEnabling(); } @@ -123,10 +143,10 @@ void LayerOrientedSampleEditor::onShowInlineEditButtonsToggled(bool checked) m_currentMultiLayerWidget->showInlineEditButtons(checked); } -void LayerOrientedSampleEditor::onAsAngstromToggled() +void LayerOrientedSampleEditor::onUnitActionToggled() { if (m_currentMultiLayerWidget) - m_currentMultiLayerWidget->useAngstrom(m_asAngstrom->isChecked()); + m_currentMultiLayerWidget->setUseAngstrom(m_asAngstromAction->isChecked()); } void LayerOrientedSampleEditor::createLayerColors() // #baLayerEditor move to better place diff --git a/GUI/Views/SampleDesigner/LayerOrientedSampleEditor.h b/GUI/Views/SampleDesigner/LayerOrientedSampleEditor.h index 96c2d368edca59a2d4f1c0feadb48364077278ab..431faafe8af2b20e4f5f079fd9ec68bca8f500f6 100644 --- a/GUI/Views/SampleDesigner/LayerOrientedSampleEditor.h +++ b/GUI/Views/SampleDesigner/LayerOrientedSampleEditor.h @@ -36,7 +36,7 @@ public: private: void updateActionEnabling(); void onShowInlineEditButtonsToggled(bool checked); - void onAsAngstromToggled(); + void onUnitActionToggled(); void createLayerColors(); QWidget* createEmptyWidget(); @@ -48,7 +48,7 @@ private: QAction* m_undoAction; // dedicated to the current sample QAction* m_redoAction; QAction* m_showInlineEditButtonsAction; - QAction* m_asAngstrom; // #baLayerEditor better two autoexclusive actions? + QAction* m_asAngstromAction; MultiLayerItem* m_currentMultiLayerItem = nullptr; QMap<MultiLayerItem*, SampleEditorController*> m_editControllers; }; diff --git a/GUI/Views/SampleDesigner/MesoCrystalForm.cpp b/GUI/Views/SampleDesigner/MesoCrystalForm.cpp index df6d312e82b50a5e9013c239f238b44baf225280..d1e8a2e58a909d40fe142deb212c0a62d82cc2fc 100644 --- a/GUI/Views/SampleDesigner/MesoCrystalForm.cpp +++ b/GUI/Views/SampleDesigner/MesoCrystalForm.cpp @@ -94,7 +94,6 @@ void MesoCrystalForm::onBasisComboChanged() const QString newClassName = m_basisCombo->currentData().toString(); m_ec->setMesoCrystalBasis(this, newClassName); - createBasisWidgets(); } void MesoCrystalForm::createBasisWidgets() diff --git a/GUI/Views/SampleDesigner/MesoCrystalForm.h b/GUI/Views/SampleDesigner/MesoCrystalForm.h index f66afb3de814e781b9bf7c77f636eb5b67a4df5f..19da6e376c0b10f247d2465861162f6866e71609 100644 --- a/GUI/Views/SampleDesigner/MesoCrystalForm.h +++ b/GUI/Views/SampleDesigner/MesoCrystalForm.h @@ -32,12 +32,12 @@ public: void enableStructureEditing(bool b); MesoCrystalItem* mesoCrystalItem() const; + void createBasisWidgets(); private: QComboBox* createBasisCombo(QWidget* parent, ItemWithParticles* current); void onBasisComboChanged(); - void createBasisWidgets(); QFormLayout* m_layout; MesoCrystalItem* m_item; diff --git a/GUI/Views/SampleDesigner/MultiLayerForm.cpp b/GUI/Views/SampleDesigner/MultiLayerForm.cpp index 06bc3d7b03432e802c1d53bc29e8c9b43e8edd2b..6fa7bc1186eca844c2b71eacd2a99afa0dfc3a1e 100644 --- a/GUI/Views/SampleDesigner/MultiLayerForm.cpp +++ b/GUI/Views/SampleDesigner/MultiLayerForm.cpp @@ -55,7 +55,11 @@ public: MultiLayerForm::MultiLayerForm(QWidget* parent, MultiLayerItem* multiLayerItem, SampleEditorController* ec) - : QWidget(parent), m_multiLayerItem(multiLayerItem), m_ec(ec) + : QWidget(parent) + , m_multiLayerItem(multiLayerItem) + , m_ec(ec) + , m_useAngstrom(false) + , m_useRadiant(false) { setObjectName("MultiLayerForm"); // important for style sheet addressing setAttribute(Qt::WA_StyledBackground, true); @@ -187,12 +191,8 @@ void MultiLayerForm::updateRowVisibilities() c->updateLayerPositionDependentElements(); } -void MultiLayerForm::ensureVisible(QWidget* /*w*/) -{ - // #baLayerEditor implement ensureVisible -} -void MultiLayerForm::useAngstrom(bool angstrom) +void MultiLayerForm::updateUnits() { const auto set = [](DoubleSpinBox* spinbox, Unit valueUnit, Unit displayUnit) { if (spinbox->baseUnit() == valueUnit) @@ -200,7 +200,7 @@ void MultiLayerForm::useAngstrom(bool angstrom) }; for (auto* editor : findChildren<DoubleSpinBox*>()) { - if (angstrom) { + if (m_useAngstrom) { set(editor, Unit::nanometer, Unit::angstrom); set(editor, Unit::angstrom, Unit::angstrom); set(editor, Unit::nanometerPower2, Unit::angstromPower2); @@ -215,20 +215,8 @@ void MultiLayerForm::useAngstrom(bool angstrom) set(editor, Unit::nanometerPowerMinus2, Unit::nanometerPowerMinus2); set(editor, Unit::angstromPowerMinus2, Unit::nanometerPowerMinus2); } - } - for (auto* label : findChildren<QLabel*>()) - LayerEditorUtils::updateLabelUnit(label); -} -void MultiLayerForm::useRadiant(bool radiant) -{ - const auto set = [](DoubleSpinBox* spinbox, Unit valueUnit, Unit displayUnit) { - if (spinbox->baseUnit() == valueUnit) - spinbox->setDisplayUnit(displayUnit); - }; - - for (auto* editor : findChildren<DoubleSpinBox*>()) { - if (radiant) { + if (m_useRadiant) { set(editor, Unit::degree, Unit::radiant); set(editor, Unit::radiant, Unit::radiant); } else { @@ -236,6 +224,35 @@ void MultiLayerForm::useRadiant(bool radiant) set(editor, Unit::radiant, Unit::degree); } } + for (auto* label : findChildren<QLabel*>()) + LayerEditorUtils::updateLabelUnit(label); +} + +void MultiLayerForm::ensureVisible(QWidget* /*w*/) +{ + // #baLayerEditor implement ensureVisible +} + +void MultiLayerForm::setUseAngstrom(bool angstrom) +{ + m_useAngstrom = angstrom; + updateUnits(); +} + +bool MultiLayerForm::useAngstrom() const +{ + return m_useAngstrom; +} + +void MultiLayerForm::setUseRadiant(bool radiant) +{ + m_useRadiant = radiant; + updateUnits(); +} + +bool MultiLayerForm::useRadiant() const +{ + return m_useRadiant; } void MultiLayerForm::showAddLayerButtons(bool show) diff --git a/GUI/Views/SampleDesigner/MultiLayerForm.h b/GUI/Views/SampleDesigner/MultiLayerForm.h index a680af25e21a1815427798737d234cd4d61daaa8..da122e8af2c5003018126f514bf8a640cde3d40d 100644 --- a/GUI/Views/SampleDesigner/MultiLayerForm.h +++ b/GUI/Views/SampleDesigner/MultiLayerForm.h @@ -48,13 +48,18 @@ public: void updateRowVisibilities(); + //! Update the presented units in all contained widgets according to current settings. + void updateUnits(); + void ensureVisible(QWidget* w); //! Show values in Angstrom or nanometers - void useAngstrom(bool angstrom); + void setUseAngstrom(bool angstrom); + bool useAngstrom() const; //! Show values in radiants or degrees - void useRadiant(bool radiant); + void setUseRadiant(bool radiant); + bool useRadiant() const; //! Shows or hides the "Add Layer" buttons. void showAddLayerButtons(bool show); @@ -70,6 +75,8 @@ private: MultiLayerItem* m_multiLayerItem; //!< Ptr is borrowed, don't delete SampleEditorController* m_ec; //!< Ptr is borrowed, don't delete bool m_showInlineEditButtons = false; + bool m_useAngstrom; + bool m_useRadiant; QList<QPushButton*> m_addLayerButtons; }; diff --git a/GUI/Views/SampleDesigner/ParticleCoreShellForm.cpp b/GUI/Views/SampleDesigner/ParticleCoreShellForm.cpp index 9fa4711a55cc0dd8842652fd6e3a6d11a4bd32d5..edd3341eec28f96d2bcbff91e7ebd11ba1070ec5 100644 --- a/GUI/Views/SampleDesigner/ParticleCoreShellForm.cpp +++ b/GUI/Views/SampleDesigner/ParticleCoreShellForm.cpp @@ -113,7 +113,6 @@ void ParticleCoreShellForm::onCoreComboChanged() const QString newClassName = core.formFactorCombo->currentData().toString(); m_ec->setCoreFormFactor(this, newClassName); - createCoreWidgets(); } void ParticleCoreShellForm::onShellComboChanged() @@ -123,7 +122,6 @@ void ParticleCoreShellForm::onShellComboChanged() const QString newClassName = shell.formFactorCombo->currentData().toString(); m_ec->setShellFormFactor(this, newClassName); - createShellWidgets(); } void ParticleCoreShellForm::createCoreWidgets() diff --git a/GUI/Views/SampleDesigner/ParticleCoreShellForm.h b/GUI/Views/SampleDesigner/ParticleCoreShellForm.h index 3733663084998b4ae7e647d1e62415f6605bfffe..98132b1bb2156f00b0befcd6b01eab5748b490fb 100644 --- a/GUI/Views/SampleDesigner/ParticleCoreShellForm.h +++ b/GUI/Views/SampleDesigner/ParticleCoreShellForm.h @@ -34,11 +34,12 @@ public: void enableStructureEditing(bool b); ParticleCoreShellItem* coreShellItem() const; + void createCoreWidgets(); + void createShellWidgets(); + private: void onCoreComboChanged(); void onShellComboChanged(); - void createCoreWidgets(); - void createShellWidgets(); private: ParticleCoreShellItem* m_item; diff --git a/GUI/Views/SampleDesigner/SampleEditorController.cpp b/GUI/Views/SampleDesigner/SampleEditorController.cpp index 1f281a688b8a9e2ede55d66067184d156e86fe17..db16be1d3dc719a89d5787baf37dd733123f47ab 100644 --- a/GUI/Views/SampleDesigner/SampleEditorController.cpp +++ b/GUI/Views/SampleDesigner/SampleEditorController.cpp @@ -60,6 +60,7 @@ void SampleEditorController::addLayer(LayerItem* before) ASSERT(m_multiLayerForm); m_multiLayerForm->onLayerAdded(layer); + m_multiLayerForm->updateUnits(); } void SampleEditorController::addLayout(LayerForm* layerItemWidget) @@ -68,6 +69,7 @@ void SampleEditorController::addLayout(LayerForm* layerItemWidget) layerItemWidget->layerItem()->model()->insertItem<ParticleLayoutItem>( layerItemWidget->layerItem()); layerItemWidget->onLayoutAdded(newLayoutItem); + m_multiLayerForm->updateUnits(); } void SampleEditorController::removeLayer(LayerItem* layerItem) @@ -101,6 +103,7 @@ void SampleEditorController::addParticle(ParticleLayoutItem* layoutItem, const Q for (auto w : m_multiLayerForm->findChildren<ParticleLayoutForm*>()) if (w->layoutItem() == layoutItem) w->onParticleAdded(newItem); + m_multiLayerForm->updateUnits(); } void SampleEditorController::addParticle(ParticleCompositionItem* compositionItem, @@ -125,6 +128,7 @@ void SampleEditorController::addParticle(ParticleCompositionItem* compositionIte for (auto c : m_multiLayerForm->findChildren<ParticleCompositionForm*>()) if (c->compositionItem() == compositionItem) c->onParticleAdded(newItem); + m_multiLayerForm->updateUnits(); } void SampleEditorController::setCoreFormFactor(ParticleCoreShellForm* widget, @@ -141,6 +145,8 @@ void SampleEditorController::setCoreFormFactor(ParticleCoreShellForm* widget, particleCoreShell->createCore(); particleCoreShell->core()->setFormFactor(formFactorModelType); + widget->createCoreWidgets(); + m_multiLayerForm->updateUnits(); } void SampleEditorController::setShellFormFactor(ParticleCoreShellForm* widget, @@ -157,6 +163,8 @@ void SampleEditorController::setShellFormFactor(ParticleCoreShellForm* widget, particleCoreShell->createShell(); particleCoreShell->shell()->setFormFactor(formFactorModelType); + widget->createShellWidgets(); + m_multiLayerForm->updateUnits(); } void SampleEditorController::removeParticle(ItemWithParticles* item) @@ -226,6 +234,14 @@ void SampleEditorController::setInt(int newValue, UIntDescriptor d) d.set(newValue); } +void SampleEditorController::setCurrentIndex(SelectionContainerForm* widget, int index, + const AbstractSelectionDescriptor& d) +{ + d.setCurrentIndex(index); + widget->createDoubleEdits(); + m_multiLayerForm->updateUnits(); +} + QUndoStack* SampleEditorController::undoStack() { return &m_undoStack; @@ -284,30 +300,22 @@ void SampleEditorController::setMesoCrystalBasis(MesoCrystalForm* widget, const return; } - if (classname == ParticleCompositionItem::M_TYPE) { + if (classname == ParticleCompositionItem::M_TYPE) meso->createBasis<ParticleCompositionItem>(); - return; - } - - if (classname == MesoCrystalItem::M_TYPE) { + else if (classname == MesoCrystalItem::M_TYPE) meso->createBasis<MesoCrystalItem>(); - return; - } - - if (classname == ParticleCoreShellItem::M_TYPE) { + else if (classname == ParticleCoreShellItem::M_TYPE) meso->createBasis<ParticleCoreShellItem>(); - return; - } - - if (ItemCatalog::isFormFactorModelType(classname)) { + else if (ItemCatalog::isFormFactorModelType(classname)) { auto* particle = dynamic_cast<ParticleItem*>(meso->basisParticle()); if (particle == nullptr) particle = meso->createBasis<ParticleItem>(); particle->setFormFactor(classname); - return; } + widget->createBasisWidgets(); + m_multiLayerForm->updateUnits(); } void SampleEditorController::selectInterference(ParticleLayoutItem* layoutItem, int newIndex) @@ -315,4 +323,5 @@ void SampleEditorController::selectInterference(ParticleLayoutItem* layoutItem, // #baLayerEditor ++ change the visibility of particle density (compare to // ParticleLayoutItem::updateDensityAppearance() and ParticleLayoutItem::updateDensityValue()) layoutItem->interference().setCurrentIndex(newIndex); + m_multiLayerForm->updateUnits(); } diff --git a/GUI/Views/SampleDesigner/SampleEditorController.h b/GUI/Views/SampleDesigner/SampleEditorController.h index 8cc63bb025f9c2e2d1b1abeba6efdf0b5384df9b..5abe2d465f101d32da2e9b0d6ce305eae7c53dac 100644 --- a/GUI/Views/SampleDesigner/SampleEditorController.h +++ b/GUI/Views/SampleDesigner/SampleEditorController.h @@ -29,6 +29,8 @@ class ParticleCompositionItem; class DoubleDescriptor; class UIntDescriptor; class ItemWithMaterial; +class SelectionContainerForm; +class AbstractSelectionDescriptor; //! Class to modify a sample from the layer oriented sample editor. //! @@ -72,11 +74,8 @@ public: void setDoubleFromUndo(double newValue, const QString& path); void setInt(int newValue, UIntDescriptor d); - template <typename SelectionDescriptorClass> - void setCurrentIndex(int index, SelectionDescriptorClass d) - { - d.setCurrentIndex(index); - } + void setCurrentIndex(SelectionContainerForm* widget, int index, + const AbstractSelectionDescriptor& d); void selectMaterial(ItemWithMaterial* item, const QString& newMaterialIdentifier); void setMaterialValue(ItemWithMaterial* item, double newValue, DoubleDescriptor d); diff --git a/GUI/Views/SampleDesigner/SelectionContainerForm.h b/GUI/Views/SampleDesigner/SelectionContainerForm.h index c1892e9fb2890d85c88f61feae56927d6774a691..698103dd521490f1eccb543e3408f471ef359066 100644 --- a/GUI/Views/SampleDesigner/SelectionContainerForm.h +++ b/GUI/Views/SampleDesigner/SelectionContainerForm.h @@ -67,12 +67,15 @@ public: QObject::connect(m_combo, QOverload<int>::of(&QComboBox::currentIndexChanged), [=](int current) { clear(); - ec->setCurrentIndex(current, d); - LayerEditorUtils::addMultiPropertyToGrid(m_gridLayout, 1, - currentValues(), m_ec, true); + ec->setCurrentIndex(this, current, d); }); m_gridLayout->addWidget(m_combo, 1, 0); + createDoubleEdits(); + } + + void createDoubleEdits() + { LayerEditorUtils::addMultiPropertyToGrid(m_gridLayout, 1, currentValues(), m_ec, true); } diff --git a/GUI/gui.qrc b/GUI/gui.qrc index 4d17cd1a7e55ef77fd09203fa05125517e2174e0..f0a2219bcc5e338a422ac186ba3e56d41443bd2c 100644 --- a/GUI/gui.qrc +++ b/GUI/gui.qrc @@ -67,6 +67,8 @@ <file>images/1D_OK.png</file> <file>images/2D_OK.png</file> <file>images/warning_16x16.png</file> + <file>images/unit_nm.svg</file> + <file>images/unit_angstrom.svg</file> <file>styles/Native.stylesheet</file> <file>styles/Base.stylesheet</file> <file>styles/Dark.stylesheet</file> diff --git a/GUI/images/unit_angstrom.svg b/GUI/images/unit_angstrom.svg new file mode 100644 index 0000000000000000000000000000000000000000..d275342a7be3b2178f57233abe6ddec6a0f24258 --- /dev/null +++ b/GUI/images/unit_angstrom.svg @@ -0,0 +1,105 @@ +<?xml version="1.0" encoding="UTF-8" standalone="no"?> +<svg + inkscape:version="1.1 (c68e22c387, 2021-05-23)" + sodipodi:docname="unit_angstrom.svg" + id="svg4" + viewBox="0 0 24 24" + height="24" + width="24" + version="1.1" + xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" + xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" + xmlns="http://www.w3.org/2000/svg" + xmlns:svg="http://www.w3.org/2000/svg" + xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" + xmlns:cc="http://creativecommons.org/ns#" + xmlns:dc="http://purl.org/dc/elements/1.1/"> + <metadata + id="metadata10"> + <rdf:RDF> + <cc:Work + rdf:about=""> + <dc:format>image/svg+xml</dc:format> + <dc:type + rdf:resource="http://purl.org/dc/dcmitype/StillImage" /> + </cc:Work> + </rdf:RDF> + </metadata> + <defs + id="defs8" /> + <sodipodi:namedview + inkscape:current-layer="svg4" + inkscape:window-maximized="0" + inkscape:window-y="0" + inkscape:window-x="571" + inkscape:cy="8.9136878" + inkscape:cx="-11.340889" + inkscape:zoom="23.895834" + showgrid="false" + id="namedview6" + inkscape:window-height="1561" + inkscape:window-width="2637" + inkscape:pageshadow="2" + inkscape:pageopacity="0" + guidetolerance="10" + gridtolerance="10" + objecttolerance="10" + borderopacity="1" + bordercolor="#666666" + pagecolor="#ffffff" + inkscape:pagecheckerboard="0" /> + <g + id="g25714" + transform="rotate(-90,11.950788,12.329164)"> + <path + style="fill:#838686;fill-opacity:1;stroke-width:0.196516" + id="path2" + d="M 3.9822142,4.1255449 H 3.3643168 c -0.042657,0 -0.092715,-0.1089236 -0.091571,0.9956408 l 0.014333,13.8413253 c 0.00114,1.104564 0.03458,1.163034 0.077237,1.163034 h 0.6178974 c 0.042657,0 0.062904,0.06708 0.062904,-1.037489 V 5.2885789 c 0,-1.1045695 -0.020247,-1.163034 -0.062904,-1.163034" + sodipodi:nodetypes="csssssssc" /> + <path + style="fill:#838686;fill-opacity:1;stroke-width:0.110498" + id="path2-9" + d="M 8.2962914,4.1342801 H 4.3102157 c -0.275181,0 -0.5981043,-0.00534 -0.5907253,0.048796 l 0.092465,0.678357 c 0.00738,0.054134 0.2230785,0.057 0.4982594,0.057 h 3.9860757 c 0.2751801,0 0.4057931,0.00329 0.4057931,-0.050847 v -0.676306 c 0,-0.054134 -0.1306064,-0.057 -0.4057931,-0.057" + sodipodi:nodetypes="csssssssc" /> + <path + style="fill:#838686;fill-opacity:1;stroke-width:0.110498" + id="path2-9-9" + d="M 7.885445,19.374909 H 3.8993691 c -0.275181,0 -0.5981043,-0.0053 -0.5907253,0.0488 l 0.092465,0.678357 c 0.00738,0.05413 0.2230785,0.057 0.4982594,0.057 H 7.885444 c 0.27518,0 0.405793,0.0033 0.405793,-0.05085 V 19.43191 c 0,-0.05413 -0.130606,-0.057 -0.405793,-0.057" + sodipodi:nodetypes="csssssssc" /> + <path + style="fill:#838686;fill-opacity:1;stroke-width:0.110498" + id="path2-9-3" + d="M 8.0629922,11.326098 H 4.0769165 c -0.275181,0 -0.5981043,-0.0053 -0.5907253,0.0488 l 0.092465,0.678357 c 0.00738,0.05413 0.2230785,0.057 0.4982594,0.057 h 3.9860757 c 0.2751799,0 0.4057929,0.0033 0.4057929,-0.05085 v -0.676306 c 0,-0.05413 -0.130606,-0.057 -0.4057929,-0.057" + sodipodi:nodetypes="csssssssc" /> + <path + style="fill:#838686;fill-opacity:1;stroke-width:0.0689405" + id="path2-5" + d="M 6.0347219,6.4005264 H 4.2306985 c -0.124542,0 -0.270691,-0.00459 -0.267351,0.041969 l 0.04185,0.5834502 c 0.0033,0.046561 0.100961,0.049025 0.225503,0.049025 h 1.8040234 c 0.124541,0 0.183654,0.00283 0.183654,-0.043733 V 6.4495515 c 0,-0.046561 -0.05911,-0.049025 -0.183654,-0.049025" + sodipodi:nodetypes="csssssssc" /> + <path + style="fill:#838686;fill-opacity:1;stroke-width:0.0689405" + id="path2-5-6" + d="M 5.9953181,8.8086125 H 4.1912947 c -0.124542,0 -0.270691,-0.0046 -0.267351,0.04197 l 0.04185,0.58345 c 0.0033,0.04656 0.100961,0.04903 0.225503,0.04903 h 1.8040234 c 0.124541,0 0.183654,0.0028 0.183654,-0.04373 v -0.581686 c 0,-0.04656 -0.05911,-0.04903 -0.183654,-0.04903" + sodipodi:nodetypes="csssssssc" /> + <path + style="fill:#838686;fill-opacity:1;stroke-width:0.0689405" + id="path2-5-5" + d="M 6.0371665,13.894711 H 4.2331431 c -0.124542,0 -0.270691,-0.0046 -0.267351,0.04197 l 0.04185,0.583451 c 0.0033,0.04656 0.100961,0.04903 0.225503,0.04903 h 1.8040234 c 0.124541,0 0.183654,0.0028 0.183654,-0.04373 v -0.581694 c 0,-0.04656 -0.05911,-0.04903 -0.183654,-0.04903" + sodipodi:nodetypes="csssssssc" /> + <path + style="fill:#838686;fill-opacity:1;stroke-width:0.0689405" + id="path2-5-66" + d="M 5.9743941,16.481405 H 4.1703707 c -0.124542,0 -0.270691,-0.0046 -0.267351,0.04197 l 0.04185,0.58345 c 0.0033,0.04656 0.100961,0.04903 0.225503,0.04903 h 1.8040234 c 0.124541,0 0.183654,0.0028 0.183654,-0.04373 v -0.581686 c 0,-0.04656 -0.05911,-0.04902 -0.183654,-0.04902" + sodipodi:nodetypes="csssssssc" /> + </g> + <text + xml:space="preserve" + style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-size:10.6667px;line-height:1.25;font-family:sans-serif;-inkscape-font-specification:'sans-serif Bold';fill:#000000;fill-opacity:1;stroke:none" + x="7.323452" + y="12.721884" + id="text1686"><tspan + sodipodi:role="line" + id="tspan1684" + x="7.323452" + y="12.721884">Å</tspan></text> +</svg> diff --git a/GUI/images/unit_nm.svg b/GUI/images/unit_nm.svg new file mode 100644 index 0000000000000000000000000000000000000000..d7b483ce2379a09e3525b5888a7f166e1174221f --- /dev/null +++ b/GUI/images/unit_nm.svg @@ -0,0 +1,105 @@ +<?xml version="1.0" encoding="UTF-8" standalone="no"?> +<svg + inkscape:version="1.1 (c68e22c387, 2021-05-23)" + sodipodi:docname="unit_nm.svg" + id="svg4" + viewBox="0 0 24 24" + height="24" + width="24" + version="1.1" + xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" + xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" + xmlns="http://www.w3.org/2000/svg" + xmlns:svg="http://www.w3.org/2000/svg" + xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" + xmlns:cc="http://creativecommons.org/ns#" + xmlns:dc="http://purl.org/dc/elements/1.1/"> + <metadata + id="metadata10"> + <rdf:RDF> + <cc:Work + rdf:about=""> + <dc:format>image/svg+xml</dc:format> + <dc:type + rdf:resource="http://purl.org/dc/dcmitype/StillImage" /> + </cc:Work> + </rdf:RDF> + </metadata> + <defs + id="defs8" /> + <sodipodi:namedview + inkscape:current-layer="svg4" + inkscape:window-maximized="0" + inkscape:window-y="0" + inkscape:window-x="571" + inkscape:cy="20.840453" + inkscape:cx="27.034001" + inkscape:zoom="23.895834" + showgrid="false" + id="namedview6" + inkscape:window-height="1561" + inkscape:window-width="2637" + inkscape:pageshadow="2" + inkscape:pageopacity="0" + guidetolerance="10" + gridtolerance="10" + objecttolerance="10" + borderopacity="1" + bordercolor="#666666" + pagecolor="#ffffff" + inkscape:pagecheckerboard="0" /> + <g + id="g25714" + transform="rotate(-90,11.950788,12.329164)"> + <path + style="fill:#838686;fill-opacity:1;stroke-width:0.196516" + id="path2" + d="M 3.9822142,4.1255449 H 3.3643168 c -0.042657,0 -0.092715,-0.1089236 -0.091571,0.9956408 l 0.014333,13.8413253 c 0.00114,1.104564 0.03458,1.163034 0.077237,1.163034 h 0.6178974 c 0.042657,0 0.062904,0.06708 0.062904,-1.037489 V 5.2885789 c 0,-1.1045695 -0.020247,-1.163034 -0.062904,-1.163034" + sodipodi:nodetypes="csssssssc" /> + <path + style="fill:#838686;fill-opacity:1;stroke-width:0.110498" + id="path2-9" + d="M 8.2962914,4.1342801 H 4.3102157 c -0.275181,0 -0.5981043,-0.00534 -0.5907253,0.048796 l 0.092465,0.678357 c 0.00738,0.054134 0.2230785,0.057 0.4982594,0.057 h 3.9860757 c 0.2751801,0 0.4057931,0.00329 0.4057931,-0.050847 v -0.676306 c 0,-0.054134 -0.1306064,-0.057 -0.4057931,-0.057" + sodipodi:nodetypes="csssssssc" /> + <path + style="fill:#838686;fill-opacity:1;stroke-width:0.110498" + id="path2-9-9" + d="M 7.885445,19.374909 H 3.8993691 c -0.275181,0 -0.5981043,-0.0053 -0.5907253,0.0488 l 0.092465,0.678357 c 0.00738,0.05413 0.2230785,0.057 0.4982594,0.057 H 7.885444 c 0.27518,0 0.405793,0.0033 0.405793,-0.05085 V 19.43191 c 0,-0.05413 -0.130606,-0.057 -0.405793,-0.057" + sodipodi:nodetypes="csssssssc" /> + <path + style="fill:#838686;fill-opacity:1;stroke-width:0.110498" + id="path2-9-3" + d="M 8.0629922,11.326098 H 4.0769165 c -0.275181,0 -0.5981043,-0.0053 -0.5907253,0.0488 l 0.092465,0.678357 c 0.00738,0.05413 0.2230785,0.057 0.4982594,0.057 h 3.9860757 c 0.2751799,0 0.4057929,0.0033 0.4057929,-0.05085 v -0.676306 c 0,-0.05413 -0.130606,-0.057 -0.4057929,-0.057" + sodipodi:nodetypes="csssssssc" /> + <path + style="fill:#838686;fill-opacity:1;stroke-width:0.0689405" + id="path2-5" + d="M 6.0347219,6.4005264 H 4.2306985 c -0.124542,0 -0.270691,-0.00459 -0.267351,0.041969 l 0.04185,0.5834502 c 0.0033,0.046561 0.100961,0.049025 0.225503,0.049025 h 1.8040234 c 0.124541,0 0.183654,0.00283 0.183654,-0.043733 V 6.4495515 c 0,-0.046561 -0.05911,-0.049025 -0.183654,-0.049025" + sodipodi:nodetypes="csssssssc" /> + <path + style="fill:#838686;fill-opacity:1;stroke-width:0.0689405" + id="path2-5-6" + d="M 5.9953181,8.8086125 H 4.1912947 c -0.124542,0 -0.270691,-0.0046 -0.267351,0.04197 l 0.04185,0.58345 c 0.0033,0.04656 0.100961,0.04903 0.225503,0.04903 h 1.8040234 c 0.124541,0 0.183654,0.0028 0.183654,-0.04373 v -0.581686 c 0,-0.04656 -0.05911,-0.04903 -0.183654,-0.04903" + sodipodi:nodetypes="csssssssc" /> + <path + style="fill:#838686;fill-opacity:1;stroke-width:0.0689405" + id="path2-5-5" + d="M 6.0371665,13.894711 H 4.2331431 c -0.124542,0 -0.270691,-0.0046 -0.267351,0.04197 l 0.04185,0.583451 c 0.0033,0.04656 0.100961,0.04903 0.225503,0.04903 h 1.8040234 c 0.124541,0 0.183654,0.0028 0.183654,-0.04373 v -0.581694 c 0,-0.04656 -0.05911,-0.04903 -0.183654,-0.04903" + sodipodi:nodetypes="csssssssc" /> + <path + style="fill:#838686;fill-opacity:1;stroke-width:0.0689405" + id="path2-5-66" + d="M 5.9743941,16.481405 H 4.1703707 c -0.124542,0 -0.270691,-0.0046 -0.267351,0.04197 l 0.04185,0.58345 c 0.0033,0.04656 0.100961,0.04903 0.225503,0.04903 h 1.8040234 c 0.124541,0 0.183654,0.0028 0.183654,-0.04373 v -0.581686 c 0,-0.04656 -0.05911,-0.04902 -0.183654,-0.04902" + sodipodi:nodetypes="csssssssc" /> + </g> + <text + xml:space="preserve" + style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-size:10.6667px;line-height:1.25;font-family:sans-serif;-inkscape-font-specification:'sans-serif Bold';fill:#000000;fill-opacity:1;stroke:none" + x="2.4690492" + y="10.545773" + id="text1686"><tspan + sodipodi:role="line" + id="tspan1684" + x="2.4690492" + y="10.545773">nm</tspan></text> +</svg> diff --git a/GUI/mainwindow/actionmanager.cpp b/GUI/mainwindow/actionmanager.cpp index 84e373bc7faf90c65de053719ddc14097c699c90..ef1c6494774e218dbec174ab1c9acdf945846057 100644 --- a/GUI/mainwindow/actionmanager.cpp +++ b/GUI/mainwindow/actionmanager.cpp @@ -254,6 +254,20 @@ void ActionManager::onAboutToShowSettingsMenu() m_settingsMenu->addSeparator(); + QActionGroup* unitActions = new QActionGroup(this); + const auto addUnitAction = [=](const QString& text, bool isAngstrom) { + auto action = m_settingsMenu->addAction( + text, [=]() { baApp->settings().setDefaultUnitIsAngstrom(isAngstrom); }); + action->setCheckable(true); + action->setChecked(baApp->settings().defaultUnitIsAngstrom() == isAngstrom); + unitActions->addAction(action); + }; + + addUnitAction("Use nanometer as default unit", false); + addUnitAction(u8"Use \u00c5ngstrom as default unit", true); + + m_settingsMenu->addSeparator(); + QActionGroup* styleActions = new QActionGroup(this); const auto addStyleAction = [=](const QString& text, ApplicationSettings::Style style) { auto action = m_settingsMenu->addAction(text, [=]() {