// ************************************************************************************************ // // BornAgain: simulate and fit reflection and scattering // //! @file GUI/View/SampleDesigner/LayerOrientedSampleEditor.cpp //! @brief Implements class LayerOrientedSampleEditor //! //! @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/View/SampleDesigner/LayerOrientedSampleEditor.h" #include "GUI/Application/ApplicationSettings.h" #include "GUI/Model/Project/ProjectDocument.h" #include "GUI/Model/Sample/LayerItem.h" #include "GUI/Model/Sample/SampleItem.h" #include "GUI/View/SampleDesigner/LayerEditorUtil.h" #include "GUI/View/SampleDesigner/SampleEditorController.h" #include "GUI/View/SampleDesigner/SampleForm.h" #include "GUI/View/Widget/StyledToolbar.h" #include <QActionGroup> #include <QBoxLayout> #include <QPushButton> LayerOrientedSampleEditor::LayerOrientedSampleEditor(QWidget* parent, ProjectDocument* document) : QWidget(parent) , m_currentSampleWidget(nullptr) , m_undoAction(nullptr) , m_redoAction(nullptr) , m_showInlineEditButtonsAction(nullptr) , m_asAngstromAction(nullptr) , m_currentSample(nullptr) , m_document(document) { m_scrollArea = new QScrollArea(this); m_scrollArea->setWidgetResizable(true); m_scrollArea->setWidget(createEmptyWidget()); m_toolbar = new StyledToolbar(this); m_toolbar->setToolButtonStyle(Qt::ToolButtonTextBesideIcon); auto* mainLayout = new QVBoxLayout(this); mainLayout->setContentsMargins(0, 0, 0, 0); mainLayout->setSpacing(0); mainLayout->addWidget(m_toolbar); mainLayout->addWidget(m_scrollArea); m_showInlineEditButtonsAction = new QAction(QIcon(":/images/edit.svg"), "Edit structure", this); connect(m_showInlineEditButtonsAction, &QAction::toggled, this, &LayerOrientedSampleEditor::onShowInlineEditButtonsToggled); m_showInlineEditButtonsAction->setCheckable(true); m_showInlineEditButtonsAction->setChecked(true); m_toolbar->addAction(m_showInlineEditButtonsAction); 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 (appSettings->defaultUnitIsAngstrom()) m_asAngstromAction->setChecked(true); else asNanometerAction->setChecked(true); m_toolbar->addActions(ag->actions()); } LayerOrientedSampleEditor::~LayerOrientedSampleEditor() { qDeleteAll(m_editControllers.values()); } void LayerOrientedSampleEditor::setCurrentSample(SampleItem* sampleItem) { if (m_currentSample != nullptr) m_editControllers[m_currentSample]->setSampleForm(nullptr); m_currentSampleWidget = nullptr; delete m_scrollArea->takeWidget(); // use the correct toolbar buttons (from correct undo stack) delete m_undoAction; m_undoAction = nullptr; delete m_redoAction; m_redoAction = nullptr; m_currentSample = sampleItem; if (m_currentSample == nullptr) { m_scrollArea->setWidget(createEmptyWidget()); updateActionEnabling(); return; } if (!m_editControllers.contains(m_currentSample)) m_editControllers.insert(m_currentSample, new SampleEditorController(m_document, m_currentSample)); auto* ec = m_editControllers[m_currentSample]; connect(ec, &SampleEditorController::requestViewInRealspace, this, &LayerOrientedSampleEditor::requestViewInRealspace); connect(ec, &SampleEditorController::aboutToRemoveItem, this, &LayerOrientedSampleEditor::aboutToRemoveItem); connect(ec, &SampleEditorController::modified, this, &LayerOrientedSampleEditor::modified); m_undoAction = ec->undoStack()->createUndoAction(this); m_redoAction = ec->undoStack()->createRedoAction(this); m_undoAction->setIcon(QIcon(":/images/undo-variant.svg")); m_redoAction->setIcon(QIcon(":/images/redo.svg")); m_toolbar->addAction(m_undoAction); m_toolbar->addAction(m_redoAction); createLayerColors(); m_currentSampleWidget = new SampleForm(this, m_currentSample, ec); ec->setSampleForm(m_currentSampleWidget); m_currentSampleWidget->setSizePolicy(QSizePolicy::Minimum, QSizePolicy::Minimum); m_scrollArea->setWidget(m_currentSampleWidget); m_currentSampleWidget->showInlineEditButtons(m_showInlineEditButtonsAction->isChecked()); m_currentSampleWidget->setUseAngstrom(m_asAngstromAction->isChecked()); updateActionEnabling(); } void LayerOrientedSampleEditor::updateActionEnabling() { // Undo/Redo is not complete => hide the related buttons/actions if (m_undoAction) m_undoAction->setVisible(false); if (m_redoAction) m_redoAction->setVisible(false); } void LayerOrientedSampleEditor::onShowInlineEditButtonsToggled(bool checked) { if (m_currentSampleWidget) m_currentSampleWidget->showInlineEditButtons(checked); } void LayerOrientedSampleEditor::onUnitActionToggled() { if (m_currentSampleWidget) m_currentSampleWidget->setUseAngstrom(m_asAngstromAction->isChecked()); } void LayerOrientedSampleEditor::createLayerColors() // #baLayerEditor move to better place { if (!m_currentSample) return; int col = 0; for (auto* l : m_currentSample->layerItems()) { if (l->color().isValid()) continue; l->setColor(LayerEditorUtils::predefinedLayerColors()[col]); col++; if (col == LayerEditorUtils::predefinedLayerColors().size()) col = 0; } } QWidget* LayerOrientedSampleEditor::createEmptyWidget() { auto* emptyWidget = new QWidget(this); auto* btn = new QPushButton("Create sample", emptyWidget); connect(btn, &QPushButton::clicked, this, &LayerOrientedSampleEditor::requestCreateNewSample); auto* layout = new QHBoxLayout(emptyWidget); layout->setContentsMargins(10, 20, 10, 20); layout->addStretch(); layout->addWidget(btn); layout->addStretch(); layout->setAlignment(Qt::AlignTop); return emptyWidget; }