diff --git a/GUI/Model/Device/InstrumentItems.cpp b/GUI/Model/Device/InstrumentItems.cpp
index d9d77778c363a396a1b4e1b05c0f2ec44730b93a..8e34bb8c8bf17bb70e289ed814c9fd10b877bd3f 100644
--- a/GUI/Model/Device/InstrumentItems.cpp
+++ b/GUI/Model/Device/InstrumentItems.cpp
@@ -52,6 +52,7 @@ const QString WithPolarizerAnalyzer("WithPolarizerAnalyzer");
 const QString AnalyzerEfficiency("AnalyzerEfficiency");
 const QString AnalyzerTotalTransmission("AnalyzerTotalTransmission");
 const QString Beam("Beam");
+const QString Scan("Scan");
 const QString Polarization("Polarization");
 const QString AnalyzerDirection("AnalyzerDirection");
 const QString Background("Background");
@@ -272,18 +273,22 @@ void InstrumentItem::readFrom(QXmlStreamReader* r)
 }
 
 //  ************************************************************************************************
-//  class SpecularInstrumentItem
+//  class ScanningItem
 //  ************************************************************************************************
 
-SpecularInstrumentItem::SpecularInstrumentItem()
+ScanningItem::ScanningItem(InstrumentItem* instrument, double intensity)
+    : m_scanItem(new ScanItem(instrument))
 {
-    m_scanItem.reset(new ScanItem(this));
-    m_scanItem->intensity().setValue(1); // overwrite default value set by BeamItem c'tor
+    m_scanItem->intensity().setValue(intensity); // overwrite default value set by BeamItem c'tor
 }
 
-ScanItem* SpecularInstrumentItem::scanItem() const
+//  ************************************************************************************************
+//  class SpecularInstrumentItem
+//  ************************************************************************************************
+
+SpecularInstrumentItem::SpecularInstrumentItem()
+    : ScanningItem(this, 1)
 {
-    return dynamic_cast<ScanItem*>(m_scanItem.get());
 }
 
 std::vector<int> SpecularInstrumentItem::shape() const
@@ -404,9 +409,8 @@ ISimulation* SpecularInstrumentItem::createSimulation(const MultiLayer& sample)
 //  ************************************************************************************************
 
 DepthprobeInstrumentItem::DepthprobeInstrumentItem()
+    : ScanningItem(this, 1e8)
 {
-    m_scanItem.reset(new ScanItem(this));
-
     auto* axisItem = scanItem()->inclinationAxisItem();
     axisItem->setMin(0.0);
     axisItem->setMax(1.0);
@@ -428,8 +432,8 @@ void DepthprobeInstrumentItem::writeTo(QXmlStreamWriter* w) const
     w->writeEndElement();
 
     // beam
-    w->writeStartElement(Tag::Beam);
-    m_scanItem->writeTo(w);
+    w->writeStartElement(Tag::Scan);
+    scanItem()->writeTo(w);
     w->writeEndElement();
 
     // z axis
@@ -452,8 +456,8 @@ void DepthprobeInstrumentItem::readFrom(QXmlStreamReader* r)
             XML::gotoEndElementOfTag(r, tag);
 
             // scan
-        } else if (tag == Tag::Beam) {
-            m_scanItem->readFrom(r);
+        } else if (tag == Tag::Scan) {
+            scanItem()->readFrom(r);
             XML::gotoEndElementOfTag(r, tag);
 
             // z axis
@@ -466,11 +470,6 @@ void DepthprobeInstrumentItem::readFrom(QXmlStreamReader* r)
     }
 }
 
-ScanItem* DepthprobeInstrumentItem::scanItem() const
-{
-    return dynamic_cast<ScanItem*>(m_scanItem.get());
-}
-
 std::vector<int> DepthprobeInstrumentItem::shape() const
 {
     return {}; // no certain shape to avoid linking to real data
@@ -536,12 +535,11 @@ const ICoordSystem* DepthprobeInstrumentItem::createCoordSystem() const
 //  ************************************************************************************************
 
 OffspecInstrumentItem::OffspecInstrumentItem()
-    : m_detector(new OffspecDetectorItem)
+    : ScanningItem(this, 1e8)
+    , m_detector(new OffspecDetectorItem)
 {
     m_alphaAxis.initMin("Min", "Starting value", 0.0, Unit::degree, RealLimits::limited(-90, 90));
     m_alphaAxis.initMax("Max", "Ending value", 10.0, Unit::degree, RealLimits::limited(-90, 90));
-
-    m_scanItem.reset(new ScanItem(this));
 }
 
 void OffspecInstrumentItem::writeTo(QXmlStreamWriter* w) const
@@ -554,19 +552,14 @@ void OffspecInstrumentItem::writeTo(QXmlStreamWriter* w) const
     w->writeEndElement();
 
     // beam
-    w->writeStartElement(Tag::Beam);
-    m_scanItem->writeTo(w);
+    w->writeStartElement(Tag::Scan);
+    scanItem()->writeTo(w);
     w->writeEndElement();
 
     // alpha axis
     w->writeStartElement(Tag::AlphaAxis);
     m_alphaAxis.writeTo(w);
     w->writeEndElement();
-
-    // beam parameters groupbox: is expanded?
-    w->writeStartElement(Tag::ExpandBeamParametersGroupbox);
-    XML::writeAttribute(w, XML::Attrib::value, m_expandBeamParameters);
-    w->writeEndElement();
 }
 
 void OffspecInstrumentItem::readFrom(QXmlStreamReader* r)
@@ -583,8 +576,8 @@ void OffspecInstrumentItem::readFrom(QXmlStreamReader* r)
             XML::gotoEndElementOfTag(r, tag);
 
             // scan
-        } else if (tag == Tag::Beam) {
-            m_scanItem->readFrom(r);
+        } else if (tag == Tag::Scan) {
+            scanItem()->readFrom(r);
             XML::gotoEndElementOfTag(r, tag);
 
             // alpha axis
@@ -592,21 +585,11 @@ void OffspecInstrumentItem::readFrom(QXmlStreamReader* r)
             m_alphaAxis.readFrom(r);
             XML::gotoEndElementOfTag(r, tag);
 
-            // beam parameters groupbox: is expanded?
-        } else if (tag == Tag::ExpandBeamParametersGroupbox) {
-            XML::readAttribute(r, XML::Attrib::value, &m_expandBeamParameters);
-            XML::gotoEndElementOfTag(r, tag);
-
         } else
             r->skipCurrentElement();
     }
 }
 
-ScanItem* OffspecInstrumentItem::scanItem() const
-{
-    return dynamic_cast<ScanItem*>(m_scanItem.get());
-}
-
 std::vector<int> OffspecInstrumentItem::shape() const
 {
     return {(int)m_alphaAxis.nbins(), detectorItem()->ySize()};
@@ -645,15 +628,15 @@ const ICoordSystem* OffspecInstrumentItem::createCoordSystem() const
 
 ISimulation* OffspecInstrumentItem::createSimulation(const MultiLayer& sample) const
 {
-    auto beam = scanItem()->createBeam();
+    const auto beam = scanItem()->createBeam();
     beam->setPolarization(m_polarization);
-    auto detector = detectorItem()->createOffspecDetector();
+    const auto detector = detectorItem()->createOffspecDetector();
     detector->setAnalyzer(m_analyzerDirection, m_analyzerEfficiency, m_analyzerTotalTransmission);
 
     const auto* det = dynamic_cast<const OffspecDetector*>(detector.get());
     auto* result = new OffspecSimulation(*beam, sample, *det);
 
-    const auto axis = alphaAxis().createAxis(Units::deg);
+    const auto axis = alphaScanAxis().createAxis(Units::deg);
     result->setBeamParameters(scanItem()->wavelength(), *axis, scanItem()->azimuthalAngle());
 
     if (const auto background = backgroundItem()->createBackground())
@@ -768,9 +751,9 @@ std::unique_ptr<IDetector> GISASInstrumentItem::createDetector() const
 
 ISimulation* GISASInstrumentItem::createSimulation(const MultiLayer& sample) const
 {
-    auto beam = beamItem()->createBeam();
+    const auto beam = beamItem()->createBeam();
     beam->setPolarization(m_polarization);
-    auto detector = detectorItem()->createDetector();
+    const auto detector = detectorItem()->createDetector();
     detector->setAnalyzer(m_analyzerDirection, m_analyzerEfficiency, m_analyzerTotalTransmission);
     detector->setDetectorNormal(beam->ki());
 
diff --git a/GUI/Model/Device/InstrumentItems.h b/GUI/Model/Device/InstrumentItems.h
index c369310e0c2eac7fce02ccd4506fb6abb4843c31..cd0190a180120857eac85d83c32e4ba9a97c3cfe 100644
--- a/GUI/Model/Device/InstrumentItems.h
+++ b/GUI/Model/Device/InstrumentItems.h
@@ -22,14 +22,15 @@
 #include "GUI/Model/Descriptor/SelectionProperty.h"
 #include "GUI/Model/Descriptor/VectorProperty.h"
 #include "GUI/Model/Device/BackgroundItems.h"
-#include "GUI/Model/Device/BeamItems.h"
 #include "GUI/Model/Device/DetectorItem.h"
+#include "GUI/Model/Device/SourceItems.h"
 #include <functional>
 #include <memory>
 
 class BackgroundItem;
 class DataItem;
 class DepthprobeSimulation;
+class IBeamScan;
 class ISimulation;
 class MaskContainerItem;
 class MultiLayer;
@@ -138,11 +139,21 @@ protected:
 };
 
 
-class SpecularInstrumentItem : public InstrumentItem {
+//! Mix-in class, to equip an instrument class with a scan item
+
+class ScanningItem {
 public:
-    SpecularInstrumentItem();
+    ScanningItem(InstrumentItem* instrument, double intensity);
+    ScanItem* scanItem() const { return m_scanItem.get(); }
+
+private:
+    std::unique_ptr<ScanItem> m_scanItem;
+};
 
-    ScanItem* scanItem() const;
+
+class SpecularInstrumentItem : public InstrumentItem, public ScanningItem {
+public:
+    SpecularInstrumentItem();
 
     std::vector<int> shape() const override;
     void updateToRealData(const RealItem* item) override;
@@ -152,21 +163,16 @@ public:
     const ICoordSystem* createCoordSystem() const override;
 
     ISimulation* createSimulation(const MultiLayer& sample) const override;
-
-private:
-    std::unique_ptr<ScanItem> m_scanItem;
 };
 
 
-class DepthprobeInstrumentItem : public InstrumentItem {
+class DepthprobeInstrumentItem : public InstrumentItem, public ScanningItem {
 public:
     DepthprobeInstrumentItem();
 
     void writeTo(QXmlStreamWriter* w) const override;
     void readFrom(QXmlStreamReader* r) override;
 
-    ScanItem* scanItem() const;
-
     std::vector<int> shape() const override;
     void updateToRealData(const RealItem* item) override;
     QString instrumentType() const override;
@@ -174,55 +180,42 @@ public:
     const ICoordSystem* createCoordSystem() const override;
 
     AxisProperty& zAxis() { return m_zAxis; }
-    const AxisProperty& zAxis() const { return m_zAxis; }
 
     bool isExpandParameters() const { return m_expandParameters; }
     void setExpandParameters(bool b) { m_expandParameters = b; }
 
     ISimulation* createSimulation(const MultiLayer& sample) const override;
 
-protected:
+private:
     mutable std::unique_ptr<const ICoordSystem> m_coosys;
     AxisProperty m_zAxis;
     bool m_expandParameters = true;
-
-private:
-    std::unique_ptr<ScanItem> m_scanItem;
 };
 
 
-class OffspecInstrumentItem : public InstrumentItem {
+class OffspecInstrumentItem : public InstrumentItem, public ScanningItem {
 public:
     OffspecInstrumentItem();
 
     void writeTo(QXmlStreamWriter* w) const override;
     void readFrom(QXmlStreamReader* r) override;
 
-    ScanItem* scanItem() const;
-
     std::vector<int> shape() const override;
     void updateToRealData(const RealItem* item) override;
     QString instrumentType() const override;
 
     const ICoordSystem* createCoordSystem() const override;
 
-    AxisProperty& alphaAxis() { return m_alphaAxis; }
-    const AxisProperty& alphaAxis() const { return m_alphaAxis; }
-
-    bool isExpandBeamParameters() const { return m_expandBeamParameters; }
-    void setExpandBeamParameters(bool b) { m_expandBeamParameters = b; }
+    AxisProperty& alphaScanAxis() { return m_alphaAxis; }
+    const AxisProperty& alphaScanAxis() const { return m_alphaAxis; }
 
     ISimulation* createSimulation(const MultiLayer& sample) const override;
 
     OffspecDetectorItem* detectorItem() const { return m_detector.get(); }
 
-protected:
+private:
     AxisProperty m_alphaAxis;
-    bool m_expandBeamParameters = true;
     std::unique_ptr<OffspecDetectorItem> m_detector;
-
-private:
-    std::unique_ptr<ScanItem> m_scanItem;
 };
 
 
diff --git a/GUI/Model/Device/PointwiseAxisItem.cpp b/GUI/Model/Device/PointwiseAxisItem.cpp
index c322e09dd001c3f7d35295bc5fb04bbefb1c74db..27b6eef5c86635f80541801708c1c0809d0bdfa1 100644
--- a/GUI/Model/Device/PointwiseAxisItem.cpp
+++ b/GUI/Model/Device/PointwiseAxisItem.cpp
@@ -17,6 +17,7 @@
 #include "Device/Data/Datafield.h"
 #include "Device/IO/ReadWriteINT.h"
 #include "GUI/Model/Device/InstrumentItems.h"
+
 namespace {
 namespace Tag {
 
diff --git a/GUI/Model/Device/BeamItems.cpp b/GUI/Model/Device/SourceItems.cpp
similarity index 82%
rename from GUI/Model/Device/BeamItems.cpp
rename to GUI/Model/Device/SourceItems.cpp
index 33268beba4d656fe8972212b28f3e442000af4af..403ef3882cbabb88e7bbf6142bc248b0a81e0747 100644
--- a/GUI/Model/Device/BeamItems.cpp
+++ b/GUI/Model/Device/SourceItems.cpp
@@ -2,7 +2,7 @@
 //
 //  BornAgain: simulate and fit reflection and scattering
 //
-//! @file      GUI/Model/Device/BeamItems.cpp
+//! @file      GUI/Model/Device/SourceItems.cpp
 //! @brief     Implements BeamItem hierarchy
 //!
 //! @homepage  http://www.bornagainproject.org
@@ -12,14 +12,19 @@
 //
 //  ************************************************************************************************
 
-#include "GUI/Model/Device/BeamItems.h"
+#include "GUI/Model/Device/SourceItems.h"
+#include "Base/Axis/FixedBinAxis.h"
 #include "Base/Const/Units.h"
 #include "Base/Util/Assert.h"
 #include "Device/Beam/Beam.h"
+#include "Device/Beam/FootprintGauss.h"
+#include "Device/Beam/FootprintSquare.h"
 #include "GUI/Model/Device/BeamAngleItems.h"
 #include "GUI/Model/Device/BeamWavelengthItem.h"
 #include "GUI/Model/Device/FootprintItems.h"
 #include "GUI/Model/Device/GrazingScanItem.h"
+#include "GUI/Model/Device/PointwiseAxisItem.h"
+#include "Sim/Scan/IBeamScan.h"
 
 namespace {
 
@@ -53,7 +58,6 @@ SourceItem::SourceItem()
 void SourceItem::writeTo(QXmlStreamWriter* w) const
 {
     ASSERT(m_wavelengthItem);
-    ASSERT(m_inclinationAngleItem);
 
     XML::writeAttribute(w, XML::Attrib::version, uint(1));
 
@@ -72,11 +76,6 @@ void SourceItem::writeTo(QXmlStreamWriter* w) const
     m_azimuthalAngleItem->writeTo(w);
     w->writeEndElement();
 
-    // inclination angle
-    w->writeStartElement(Tag::InclinationAngle);
-    m_inclinationAngleItem->writeTo(w);
-    w->writeEndElement();
-
     // beam parameters groupbox: is expanded?
     w->writeStartElement(Tag::ExpandBeamParametersGroupbox);
     XML::writeAttribute(w, XML::Attrib::value, m_expandBeamParameters);
@@ -86,7 +85,6 @@ void SourceItem::writeTo(QXmlStreamWriter* w) const
 void SourceItem::readFrom(QXmlStreamReader* r)
 {
     ASSERT(m_wavelengthItem);
-    ASSERT(m_inclinationAngleItem);
 
     const uint version = XML::readUIntAttribute(r, XML::Attrib::version);
     Q_UNUSED(version)
@@ -109,11 +107,6 @@ void SourceItem::readFrom(QXmlStreamReader* r)
             m_azimuthalAngleItem->readFrom(r);
             XML::gotoEndElementOfTag(r, tag);
 
-            // inclination angle
-        } else if (tag == Tag::InclinationAngle) {
-            m_inclinationAngleItem->readFrom(r);
-            XML::gotoEndElementOfTag(r, tag);
-
             // beam parameters groupbox: is expanded?
         } else if (tag == Tag::ExpandBeamParametersGroupbox) {
             XML::readAttribute(r, XML::Attrib::value, &m_expandBeamParameters);
@@ -142,18 +135,6 @@ BeamWavelengthItem* SourceItem::wavelengthItem() const
     return m_wavelengthItem.get();
 }
 
-void SourceItem::setInclinationAngle(double value)
-{
-    ASSERT(m_inclinationAngleItem);
-    m_inclinationAngleItem->resetToValue(value);
-}
-
-BeamDistributionItem* SourceItem::beamDistributionItem() const
-{
-    ASSERT(m_inclinationAngleItem);
-    return m_inclinationAngleItem.get();
-}
-
 double SourceItem::azimuthalAngle() const
 {
     ASSERT(m_azimuthalAngleItem);
@@ -172,18 +153,6 @@ BeamAzimuthalAngleItem* SourceItem::azimuthalAngleItem() const
     return m_azimuthalAngleItem.get();
 }
 
-std::shared_ptr<Beam> SourceItem::createBeam() const
-{
-    double lambda = wavelength();
-    double inclination_angle = Units::deg2rad(getInclinationAngle());
-    double azimuthal_angle = Units::deg2rad(azimuthalAngle());
-
-    auto result =
-        std::make_shared<Beam>(InBeam(intensity(), lambda, inclination_angle, azimuthal_angle));
-
-    return result;
-}
-
 //  ************************************************************************************************
 //  BeamItem
 //  ************************************************************************************************
@@ -196,18 +165,25 @@ BeamItem::BeamItem()
 
 void BeamItem::writeTo(QXmlStreamWriter* w) const
 {
+    ASSERT(m_inclinationAngleItem);
     XML::writeAttribute(w, XML::Attrib::version, uint(1));
 
     // parameters from base class
     w->writeStartElement(Tag::BaseData);
     SourceItem::writeTo(w);
     w->writeEndElement();
+
+    // inclination angle
+    w->writeStartElement(Tag::InclinationAngle);
+    m_inclinationAngleItem->writeTo(w);
+    w->writeEndElement();
 }
 
 void BeamItem::readFrom(QXmlStreamReader* r)
 {
     const uint version = XML::readUIntAttribute(r, XML::Attrib::version);
     Q_UNUSED(version)
+    ASSERT(m_inclinationAngleItem);
 
     while (r->readNextStartElement()) {
         QString tag = r->name().toString();
@@ -217,27 +193,75 @@ void BeamItem::readFrom(QXmlStreamReader* r)
             SourceItem::readFrom(r);
             XML::gotoEndElementOfTag(r, tag);
 
+            // inclination angle
+        } else if (tag == Tag::InclinationAngle) {
+            m_inclinationAngleItem->readFrom(r);
+            XML::gotoEndElementOfTag(r, tag);
+
         } else
             r->skipCurrentElement();
     }
 }
 
+void BeamItem::setInclinationAngle(double value)
+{
+    ASSERT(m_inclinationAngleItem);
+    m_inclinationAngleItem->resetToValue(value);
+}
+
+BeamDistributionItem* BeamItem::beamDistributionItem() const
+{
+    ASSERT(m_inclinationAngleItem);
+    return m_inclinationAngleItem.get();
+}
+
 double BeamItem::getInclinationAngle() const
 {
     return dynamic_cast<BeamInclinationAngleItem*>(beamDistributionItem())->inclinationAngle();
 }
 
+std::unique_ptr<Beam> BeamItem::createBeam() const
+{
+    double lambda = wavelength();
+    double inclination_angle = Units::deg2rad(getInclinationAngle());
+    double azimuthal_angle = Units::deg2rad(azimuthalAngle());
+
+    return std::make_unique<Beam>(InBeam(intensity(), lambda, inclination_angle, azimuthal_angle));
+}
+
 //  ************************************************************************************************
 //  ScanItem
 //  ************************************************************************************************
 
 ScanItem::ScanItem(const InstrumentItem* owningInstrument)
 {
-    m_inclinationAngleItem.reset(new GrazingScanItem(owningInstrument));
+    m_grazingScanItem.reset(new GrazingScanItem(owningInstrument));
     m_wavelengthItem.reset(new BeamWavelengthItem);
     m_footprint.init("Type", "Footprint type");
 }
 
+void ScanItem::setScan(const IBeamScan* scan)
+{
+    setIntensity(scan->intensity());
+    setWavelength(scan->wavelength());
+    setAzimuthalAngle(0.0);
+
+    auto* axis_item = inclinationAxisItem();
+    const IAxis* axis = dynamic_cast<const FixedBinAxis*>(scan->coordinateAxis());
+    ASSERT(axis);
+    axis_item->setBinCount(static_cast<int>(axis->size()));
+    axis_item->setMin(axis->min() / Units::deg);
+    axis_item->setMax(axis->max() / Units::deg);
+    axis_item->setTitle(QString::fromStdString(axis->axisName()));
+
+    if (const IFootprintFactor* footprint = scan->footprintFactor()) {
+        if (const auto* const fp = dynamic_cast<const FootprintGauss*>(footprint))
+            setGaussianFootprint(fp->widthRatio());
+        else if (const auto* const fp = dynamic_cast<const FootprintSquare*>(footprint))
+            setSquareFootprint(fp->widthRatio());
+    }
+}
+
 void ScanItem::writeTo(QXmlStreamWriter* w) const
 {
     XML::writeAttribute(w, XML::Attrib::version, uint(1));
@@ -291,16 +315,9 @@ double ScanItem::getInclinationAngle() const
     return 0.0;
 }
 
-void ScanItem::setInclinationAngle(double value)
-{
-    ASSERT(value == 0.0);
-    SourceItem::setInclinationAngle(0.);
-}
-
 GrazingScanItem* ScanItem::grazingScanItem() const
 {
-    ASSERT(m_inclinationAngleItem);
-    return dynamic_cast<GrazingScanItem*>(m_inclinationAngleItem.get());
+    return m_grazingScanItem.get();
 }
 
 BasicAxisItem* ScanItem::inclinationAxisItem() const
@@ -329,6 +346,15 @@ void ScanItem::updateToData(const IAxis& axis, QString units)
     }
 }
 
+std::unique_ptr<Beam> ScanItem::createBeam() const
+{
+    double lambda = wavelength();
+    double inclination_angle = Units::deg2rad(getInclinationAngle());
+    double azimuthal_angle = Units::deg2rad(azimuthalAngle());
+
+    return std::make_unique<Beam>(InBeam(intensity(), lambda, inclination_angle, azimuthal_angle));
+}
+
 /*
 std::shared_ptr<AlphaScan> ScanItem::createAlphaScan() const
 {
diff --git a/GUI/Model/Device/BeamItems.h b/GUI/Model/Device/SourceItems.h
similarity index 84%
rename from GUI/Model/Device/BeamItems.h
rename to GUI/Model/Device/SourceItems.h
index fd42c9952973bb48e93524380bfd3c0c67b52abb..fa8550fdf133639ad8cd2e68f482a4f49f9503ff 100644
--- a/GUI/Model/Device/BeamItems.h
+++ b/GUI/Model/Device/SourceItems.h
@@ -2,7 +2,7 @@
 //
 //  BornAgain: simulate and fit reflection and scattering
 //
-//! @file      GUI/Model/Device/BeamItems.h
+//! @file      GUI/Model/Device/SourceItems.h
 //! @brief     Defines BeamItem hierarchy
 //!
 //! @homepage  http://www.bornagainproject.org
@@ -12,8 +12,8 @@
 //
 //  ************************************************************************************************
 
-#ifndef BORNAGAIN_GUI_MODEL_DEVICE_BEAMITEMS_H
-#define BORNAGAIN_GUI_MODEL_DEVICE_BEAMITEMS_H
+#ifndef BORNAGAIN_GUI_MODEL_DEVICE_SOURCEITEMS_H
+#define BORNAGAIN_GUI_MODEL_DEVICE_SOURCEITEMS_H
 
 #include "GUI/Model/CatDevice/FootprintItemCatalog.h"
 #include "GUI/Model/Descriptor/DoubleProperty.h"
@@ -29,6 +29,7 @@ class BeamWavelengthItem;
 class FootprintItem;
 class GrazingScanItem;
 class IAxis;
+class IBeamScan;
 class InstrumentItem;
 
 //! Base class for BeamItem and ScanItem. Name refers to radiation source.
@@ -42,17 +43,10 @@ public:
     void setWavelength(double value);
     BeamWavelengthItem* wavelengthItem() const;
 
-    virtual double getInclinationAngle() const = 0;
-    virtual void setInclinationAngle(double value);
-
-    BeamDistributionItem* beamDistributionItem() const;
-
     double azimuthalAngle() const;
     void setAzimuthalAngle(double value);
     BeamAzimuthalAngleItem* azimuthalAngleItem() const;
 
-    std::shared_ptr<Beam> createBeam() const;
-
     bool isExpandBeamParameters() const { return m_expandBeamParameters; }
     void setExpandBeamParameters(bool b) { m_expandBeamParameters = b; }
 
@@ -63,7 +57,6 @@ protected:
 
     std::unique_ptr<BeamWavelengthItem> m_wavelengthItem;
     std::unique_ptr<BeamAzimuthalAngleItem> m_azimuthalAngleItem;
-    std::unique_ptr<BeamDistributionItem> m_inclinationAngleItem;
 
     DoubleProperty m_intensity;
     bool m_expandBeamParameters = true;
@@ -76,18 +69,26 @@ public:
     void writeTo(QXmlStreamWriter* w) const;
     void readFrom(QXmlStreamReader* r);
 
-    double getInclinationAngle() const override;
+    BeamDistributionItem* beamDistributionItem() const;
+    void setInclinationAngle(double value);
+    double getInclinationAngle() const;
+
+    std::unique_ptr<Beam> createBeam() const;
+
+private:
+    std::unique_ptr<BeamDistributionItem> m_inclinationAngleItem;
 };
 
 class ScanItem : public SourceItem {
 public:
     explicit ScanItem(const InstrumentItem* owningInstrument);
 
+    void setScan(const IBeamScan* scan);
+
     void writeTo(QXmlStreamWriter* w) const;
     void readFrom(QXmlStreamReader* r);
 
-    double getInclinationAngle() const override;
-    void setInclinationAngle(double value) override;
+    double getInclinationAngle() const;
 
     GrazingScanItem* grazingScanItem() const;
     BasicAxisItem* inclinationAxisItem() const;
@@ -102,9 +103,12 @@ public:
     bool isExpandFootprint() const { return m_expandFootprint; }
     void setExpandFootprint(bool b) { m_expandFootprint = b; }
 
+    std::unique_ptr<Beam> createBeam() const;
+
 private:
     SelectionProperty<FootprintItemCatalog> m_footprint;
     bool m_expandFootprint = true;
+    std::unique_ptr<GrazingScanItem> m_grazingScanItem;
 };
 
-#endif // BORNAGAIN_GUI_MODEL_DEVICE_BEAMITEMS_H
+#endif // BORNAGAIN_GUI_MODEL_DEVICE_SOURCEITEMS_H
diff --git a/GUI/Model/FromCore/ItemizeSimulation.cpp b/GUI/Model/FromCore/ItemizeSimulation.cpp
index d3aa4ec88630f98d2dfce5ccc3c083e4776a4c19..a7aa6700af2bb05355cba03e800669edca146ce1 100644
--- a/GUI/Model/FromCore/ItemizeSimulation.cpp
+++ b/GUI/Model/FromCore/ItemizeSimulation.cpp
@@ -15,8 +15,6 @@
 #include "GUI/Model/FromCore/ItemizeSimulation.h"
 #include "Base/Const/Units.h"
 #include "Device/Beam/Beam.h"
-#include "Device/Beam/FootprintGauss.h"
-#include "Device/Beam/FootprintSquare.h"
 #include "Device/Detector/OffspecDetector.h"
 #include "Device/Detector/SphericalDetector.h"
 #include "Device/Mask/DetectorMask.h"
@@ -143,16 +141,6 @@ void setDetectorMasks(DetectorItem* detector_item, const IDetector& detector)
     }
 }
 
-void setFootprintFactor(const IFootprintFactor* footprint, ScanItem* beam_item)
-{
-    if (!footprint)
-        return;
-    if (const auto* const gaussian_fp = dynamic_cast<const FootprintGauss*>(footprint))
-        beam_item->setGaussianFootprint(gaussian_fp->widthRatio());
-    else if (const auto* const square_fp = dynamic_cast<const FootprintSquare*>(footprint))
-        beam_item->setSquareFootprint(square_fp->widthRatio());
-}
-
 void setDistributionTypeAndPars(BeamDistributionItem* pdi, const IDistribution1D* d)
 {
     const double factor = 1 / pdi->scaleFactor();
@@ -238,22 +226,10 @@ void setOffspecBeamItem(ScanItem* scan_item, const OffspecSimulation& simulation
 
     scan_item->setIntensity(beam.intensity());
     scan_item->setWavelength(beam.wavelength());
-    scan_item->setInclinationAngle(Units::rad2deg(beam.alpha_i()));
     scan_item->setAzimuthalAngle(Units::rad2deg(beam.phi_i()));
     // TODO implement beam divergence
 }
 
-void setAxisItem(BasicAxisItem* item, const IAxis& axis, double factor)
-{
-    if (!dynamic_cast<const FixedBinAxis*>(&axis))
-        throw Error("setAxisItem() -> Error. Unexpected axis");
-
-    item->setBinCount(static_cast<int>(axis.size()));
-    item->setMin(factor * axis.min());
-    item->setMax(factor * axis.max());
-    item->setTitle(QString::fromStdString(axis.axisName()));
-}
-
 void setSphericalDetector(SphericalDetectorItem* detectorItem, const SphericalDetector& detector)
 {
     // Axes
@@ -416,9 +392,9 @@ OffspecInstrumentItem* createOffspecInstrumentItem(const OffspecSimulation& simu
     setPolarizer2(result, detector.analyzer());
 
     const double factor = 1. / Units::deg;
-    result->alphaAxis().setNbins(simulation.beamAxis()->size());
-    result->alphaAxis().setMin(factor * simulation.beamAxis()->min());
-    result->alphaAxis().setMax(factor * simulation.beamAxis()->max());
+    result->alphaScanAxis().setNbins(simulation.beamAxis()->size());
+    result->alphaScanAxis().setMin(factor * simulation.beamAxis()->min());
+    result->alphaScanAxis().setMax(factor * simulation.beamAxis()->max());
 
     return result;
 }
@@ -430,15 +406,7 @@ SpecularInstrumentItem* createSpecularInstrumentItem(const SpecularSimulation& s
 
     const IBeamScan* scan = simulation.scan();
 
-    scan_item->setIntensity(scan->intensity());
-    scan_item->setWavelength(scan->wavelength());
-    scan_item->setInclinationAngle(0.0); // inclination angle is hardcoded
-    scan_item->setAzimuthalAngle(0.0);   // azimuthal angle is hardcoded
-
-    auto* axis_item = scan_item->inclinationAxisItem();
-    setAxisItem(axis_item, *scan->coordinateAxis(), 1. / Units::deg);
-
-    setFootprintFactor(scan->footprintFactor(), scan_item);
+    scan_item->setScan(scan);
 
     if (const auto* s2 = dynamic_cast<const AlphaScan*>(scan)) {
         if (const IDistribution1D* distribution = s2->wavelengthDistribution())
diff --git a/GUI/Model/Project/LinkInstrumentManager.cpp b/GUI/Model/Project/LinkInstrumentManager.cpp
index 720b8b2e041e31b93093ee808d12b164e7095780..de50ebf90dafc4bb8d28968c7a70c523829f2cd9 100644
--- a/GUI/Model/Project/LinkInstrumentManager.cpp
+++ b/GUI/Model/Project/LinkInstrumentManager.cpp
@@ -68,12 +68,11 @@ QString printShapeMessage(const std::vector<int>& instrument_shape,
 LinkInstrumentManager::LinkInstrumentManager(ProjectDocument* document)
     : m_document(document)
 {
-    connect(m_document->instrumentsEditController(),
-            &MultiInstrumentNotifier::instrumentAddedOrRemoved, this,
+    connect(m_document->multiNotifier(), &MultiInstrumentNotifier::instrumentAddedOrRemoved, this,
             &LinkInstrumentManager::onInstrumentAddedOrRemoved);
 
-    connect(m_document->instrumentsEditController(), &MultiInstrumentNotifier::instrumentChanged,
-            this, &LinkInstrumentManager::onInstrumentChanged);
+    connect(m_document->multiNotifier(), &MultiInstrumentNotifier::instrumentChanged, this,
+            &LinkInstrumentManager::onInstrumentChanged);
 }
 
 bool LinkInstrumentManager::canLinkDataToInstrument(const RealItem* realItem,
@@ -109,8 +108,7 @@ bool LinkInstrumentManager::canLinkDataToInstrument(const RealItem* realItem,
     if (!QuestionOnInstrumentReshaping(message))
         return false;
 
-    m_document->instrumentsEditController()->updateInstrumentToRealDataItem(instrumentItem,
-                                                                            realItem);
+    m_document->multiNotifier()->updateInstrumentToRealDataItem(instrumentItem, realItem);
     return true;
 }
 
diff --git a/GUI/Model/Project/ProjectDocument.cpp b/GUI/Model/Project/ProjectDocument.cpp
index 02f8050f2d17227020430d7f526087c20cf87218..2c564dc90bf3e50f23046bd54d4bd838b0c50f23 100644
--- a/GUI/Model/Project/ProjectDocument.cpp
+++ b/GUI/Model/Project/ProjectDocument.cpp
@@ -147,7 +147,7 @@ LinkInstrumentManager* ProjectDocument::linkInstrumentManager()
     return m_linkManager.get();
 }
 
-MultiInstrumentNotifier* ProjectDocument::instrumentsEditController()
+MultiInstrumentNotifier* ProjectDocument::multiNotifier()
 {
     return &m_instrumentEditController;
 }
diff --git a/GUI/Model/Project/ProjectDocument.h b/GUI/Model/Project/ProjectDocument.h
index 44a71e9d110c938ed81ba32e3ec4b4da2aebbcb3..bd475e3d227cbf55b066d032a82108cc11f6cf7b 100644
--- a/GUI/Model/Project/ProjectDocument.h
+++ b/GUI/Model/Project/ProjectDocument.h
@@ -80,7 +80,7 @@ public:
     //! Use this to modify instrument list or instrument data.
     //! Listen to its signals to get notification about any changes.
     //! \sa MultiInstrumentNotifier for more information
-    MultiInstrumentNotifier* instrumentsEditController();
+    MultiInstrumentNotifier* multiNotifier();
 
     void saveProjectFileWithData(const QString& projectPullPath);
 
diff --git a/GUI/View/Import/RealDataPropertiesWidget.cpp b/GUI/View/Import/RealDataPropertiesWidget.cpp
index 181a40d4f773efbcc28e0c7e6b772cff4d7ceea8..34c8ea419a6116d8bf22eafb5b6dd24dc3e5ae76 100644
--- a/GUI/View/Import/RealDataPropertiesWidget.cpp
+++ b/GUI/View/Import/RealDataPropertiesWidget.cpp
@@ -49,12 +49,10 @@ RealDataPropertiesWidget::RealDataPropertiesWidget(QWidget* parent, ProjectDocum
             static_cast<void (QComboBox::*)(int)>(&QComboBox::currentIndexChanged), this,
             &RealDataPropertiesWidget::onInstrumentComboIndexChanged);
 
-    connect(m_document->instrumentsEditController(),
-            &MultiInstrumentNotifier::instrumentAddedOrRemoved, this,
+    connect(m_document->multiNotifier(), &MultiInstrumentNotifier::instrumentAddedOrRemoved, this,
             &RealDataPropertiesWidget::updateInstrumentComboEntries);
 
-    connect(m_document->instrumentsEditController(),
-            &MultiInstrumentNotifier::instrumentNameChanged, this,
+    connect(m_document->multiNotifier(), &MultiInstrumentNotifier::instrumentNameChanged, this,
             &RealDataPropertiesWidget::updateInstrumentComboEntries);
 
     connect(m_document->linkInstrumentManager(), &LinkInstrumentManager::linkToInstrumentChanged,
diff --git a/GUI/View/Instrument/DepthprobeInstrumentEditor.cpp b/GUI/View/Instrument/DepthprobeInstrumentEditor.cpp
index 403cb57ba88d28e177a9c1ad0a6c374249c658be..14b0af052169ee08dc46e786c31ac57512b72507 100644
--- a/GUI/View/Instrument/DepthprobeInstrumentEditor.cpp
+++ b/GUI/View/Instrument/DepthprobeInstrumentEditor.cpp
@@ -15,7 +15,7 @@
 #include "GUI/View/Instrument/DepthprobeInstrumentEditor.h"
 #include "GUI/Model/Device/InstrumentItems.h"
 #include "GUI/View/Device/AxisPropertyForm.h"
-#include "GUI/View/Instrument/SpecularBeamEditor.h"
+#include "GUI/View/Instrument/ScanEditor.h"
 #include <QVBoxLayout>
 
 DepthprobeInstrumentEditor::DepthprobeInstrumentEditor(QWidget* parent,
@@ -28,8 +28,8 @@ DepthprobeInstrumentEditor::DepthprobeInstrumentEditor(QWidget* parent,
     auto* layout = new QVBoxLayout(this);
     layout->setContentsMargins(0, 0, 0, 0);
 
-    auto* beamEditor = new SpecularBeamEditor(this, instrument->scanItem(), &m_ec);
-    layout->addWidget(beamEditor);
+    auto* scanEditor = new ScanEditor(this, instrument->scanItem(), &m_ec);
+    layout->addWidget(scanEditor);
 
     auto* depthAxisEditor = new AxisPropertyForm(this, "Depth axis", &instrument->zAxis(),
                                                  "Number of points in scan across sample bulk");
@@ -37,8 +37,7 @@ DepthprobeInstrumentEditor::DepthprobeInstrumentEditor(QWidget* parent,
 
     layout->addStretch();
 
-    connect(beamEditor, &SpecularBeamEditor::dataChanged, this,
-            &DepthprobeInstrumentEditor::dataChanged);
+    connect(scanEditor, &ScanEditor::dataChanged, this, &DepthprobeInstrumentEditor::dataChanged);
     connect(depthAxisEditor, &AxisPropertyForm::dataChanged, this,
             &DepthprobeInstrumentEditor::dataChanged);
 }
diff --git a/GUI/View/Instrument/GISASBeamEditor.cpp b/GUI/View/Instrument/GISASBeamEditor.cpp
index 1964867f340bd29a1e919853ba05b5f51169c4b2..b22e79b2ca7842c7ccd01e90600f7f5d420203e8 100644
--- a/GUI/View/Instrument/GISASBeamEditor.cpp
+++ b/GUI/View/Instrument/GISASBeamEditor.cpp
@@ -15,9 +15,9 @@
 #include "GUI/View/Instrument/GISASBeamEditor.h"
 #include "Base/Util/Assert.h"
 #include "GUI/Model/Device/BeamAngleItems.h"
-#include "GUI/Model/Device/BeamItems.h"
 #include "GUI/Model/Device/BeamWavelengthItem.h"
 #include "GUI/Model/Device/GrazingScanItem.h"
+#include "GUI/Model/Device/SourceItems.h"
 #include "GUI/View/Instrument/DistributionEditor.h"
 #include "GUI/View/Numeric/FixupDoubleValidator.h"
 #include "GUI/View/Tool/GroupBoxCollapser.h"
diff --git a/GUI/View/Instrument/InstrumentLibraryEditor.cpp b/GUI/View/Instrument/InstrumentLibraryEditor.cpp
index 9854fd28793014d0d70e4027276c4032ccf4e070..abda0e01b990d0095e4dd0401a4cc005269c49e6 100644
--- a/GUI/View/Instrument/InstrumentLibraryEditor.cpp
+++ b/GUI/View/Instrument/InstrumentLibraryEditor.cpp
@@ -221,7 +221,7 @@ void InstrumentLibraryEditor::createWidgetsForCurrentInstrument()
                 &InstrumentLibraryEditor::onInstrumentChangedByEditor);
         layout->addWidget(editor);
     } else if (auto* os = dynamic_cast<OffspecInstrumentItem*>(currentInstrument)) {
-        auto* editor = new OffspecInstrumentEditor(m_ui->scrollArea, os);
+        auto* editor = new OffspecInstrumentEditor(m_ui->scrollArea, os, ec);
         connect(editor, &OffspecInstrumentEditor::dataChanged, this,
                 &InstrumentLibraryEditor::onInstrumentChangedByEditor);
         layout->addWidget(editor);
diff --git a/GUI/View/Instrument/InstrumentListView.cpp b/GUI/View/Instrument/InstrumentListView.cpp
index 51d2276f887ff877a359f681611fed079b5bb08c..4222dddedff2e4a79c734eb7a809f45cd7024f7a 100644
--- a/GUI/View/Instrument/InstrumentListView.cpp
+++ b/GUI/View/Instrument/InstrumentListView.cpp
@@ -51,7 +51,7 @@ InstrumentListView::InstrumentListView(ProjectDocument* document, QWidget* paren
                           "}\n"));
     layout->addWidget(m_listView);
 
-    m_model = new InstrumentListModel(this, m_document->instrumentsEditController());
+    m_model = new InstrumentListModel(this, m_document->multiNotifier());
     m_listView->setModel(m_model);
 
     m_newGisasAction = new QAction("New GISAS", this);
diff --git a/GUI/View/Instrument/InstrumentView.cpp b/GUI/View/Instrument/InstrumentView.cpp
index dead4a27ec579e7fcc672040982856afcabe0bf3..48cb7ca49354655acbd53ecff962d7b1f02d9d71 100644
--- a/GUI/View/Instrument/InstrumentView.cpp
+++ b/GUI/View/Instrument/InstrumentView.cpp
@@ -71,16 +71,16 @@ void InstrumentView::showEvent(QShowEvent*)
     // disconnect because when this view is visible, no other instance is modifying instruments. By
     // disconnecting, no additional logic is necessary to avoid recursive calls (recursive since
     // this view also causes instrumentChanged to be emitted).
-    disconnect(m_document->instrumentsEditController(), &MultiInstrumentNotifier::instrumentChanged,
-               this, &InstrumentView::onInstrumentChangedFromExternal);
+    disconnect(m_document->multiNotifier(), &MultiInstrumentNotifier::instrumentChanged, this,
+               &InstrumentView::onInstrumentChangedFromExternal);
 }
 
 void InstrumentView::hideEvent(QHideEvent*)
 {
     // when the instrument view gets hidden (meaning another view is shown), it's necessary to
     // listen to changes (e.g. performed by the LinkInstrumentManager).
-    connect(m_document->instrumentsEditController(), &MultiInstrumentNotifier::instrumentChanged,
-            this, &InstrumentView::onInstrumentChangedFromExternal);
+    connect(m_document->multiNotifier(), &MultiInstrumentNotifier::instrumentChanged, this,
+            &InstrumentView::onInstrumentChangedFromExternal);
 }
 
 void InstrumentView::createWidgetsForCurrentInstrument()
@@ -123,14 +123,14 @@ void InstrumentView::createWidgetsForCurrentInstrument()
     connect(collapser, &GroupBoxCollapser::toggled, this,
             [currentInstrument](bool b) { currentInstrument->setExpandInfo(b); });
 
-    auto* ec = m_document->instrumentsEditController();
+    auto* ec = m_document->multiNotifier();
     if (auto* sp = dynamic_cast<SpecularInstrumentItem*>(currentInstrument)) {
         auto* editor = new SpecularInstrumentEditor(m_scrollArea, sp, ec);
         connect(editor, &SpecularInstrumentEditor::dataChanged, this,
                 &InstrumentView::onInstrumentChangedByEditor);
         layout->addWidget(editor);
     } else if (auto* os = dynamic_cast<OffspecInstrumentItem*>(currentInstrument)) {
-        auto* editor = new OffspecInstrumentEditor(m_scrollArea, os);
+        auto* editor = new OffspecInstrumentEditor(m_scrollArea, os, ec);
         connect(editor, &OffspecInstrumentEditor::dataChanged, this,
                 &InstrumentView::onInstrumentChangedByEditor);
         layout->addWidget(editor);
@@ -154,7 +154,7 @@ void InstrumentView::onInstrumentNameEdited(const QString& newName)
 {
     auto* currentInstrument = m_instrumentListView->currentInstrumentItem();
     if (currentInstrument && currentInstrument->instrumentName() != newName)
-        m_document->instrumentsEditController()->setInstrumentName(currentInstrument, newName);
+        m_document->multiNotifier()->setInstrumentName(currentInstrument, newName);
 }
 
 void InstrumentView::onInstrumentdescriptionEdited(const QString& t)
@@ -168,7 +168,7 @@ void InstrumentView::onInstrumentdescriptionEdited(const QString& t)
 
 void InstrumentView::onInstrumentChangedByEditor()
 {
-    m_document->instrumentsEditController()->notifyInstrumentChanged(
+    m_document->multiNotifier()->notifyInstrumentChanged(
         m_instrumentListView->currentInstrumentItem());
 }
 
diff --git a/GUI/View/Instrument/OffspecBeamEditor.cpp b/GUI/View/Instrument/OffspecBeamEditor.cpp
deleted file mode 100644
index 5e28e1b21c750692ed39a4af424dc7d889884d82..0000000000000000000000000000000000000000
--- a/GUI/View/Instrument/OffspecBeamEditor.cpp
+++ /dev/null
@@ -1,88 +0,0 @@
-//  ************************************************************************************************
-//
-//  BornAgain: simulate and fit reflection and scattering
-//
-//! @file      GUI/View/Instrument/OffspecBeamEditor.cpp
-//! @brief     Implements class OffspecBeamEditor
-//!
-//! @homepage  http://www.bornagainproject.org
-//! @license   GNU General Public License v3 or higher (see COPYING)
-//! @copyright Forschungszentrum Jülich GmbH 2018
-//! @authors   Scientific Computing Group at MLZ (see CITATION, AUTHORS)
-//
-//  ************************************************************************************************
-
-#include "GUI/View/Instrument/OffspecBeamEditor.h"
-#include "GUI/Model/Device/BeamAngleItems.h"
-#include "GUI/Model/Device/BeamWavelengthItem.h"
-#include "GUI/Model/Device/InstrumentItems.h"
-#include "GUI/View/Device/AxisPropertyForm.h"
-#include "GUI/View/Instrument/DistributionEditor.h"
-#include "GUI/View/Numeric/FixupDoubleValidator.h"
-#include "GUI/View/Tool/GroupBoxCollapser.h"
-#include <QFormLayout>
-#include <QLineEdit>
-
-OffspecBeamEditor::OffspecBeamEditor(QWidget* parent, OffspecInstrumentItem* item)
-    : QGroupBox("Beam and scan parameters", parent)
-{
-    ASSERT(item);
-
-    auto* vLayout = new QVBoxLayout(this);
-    vLayout->setContentsMargins(30, 8, 0, 0);
-    auto* form = new QFormLayout();
-    form->setFieldGrowthPolicy(QFormLayout::FieldsStayAtSizeHint);
-    vLayout->addLayout(form);
-    auto* intensityEditor = new QLineEdit(this);
-    intensityEditor->setToolTip("Beam intensity in neutrons/photons per second.");
-    auto* validator = new FixupDoubleValidator(intensityEditor);
-    validator->setNotation(QDoubleValidator::ScientificNotation);
-    validator->setRange(0.0, 1e32, 1000);
-    intensityEditor->setValidator(validator);
-    form->addRow("Intensity:", intensityEditor);
-
-    ScanItem* scanI = item->scanItem();
-
-    auto* wavelengthEditor = new DistributionEditor(
-        "Wavelength", MeanConfig{true}, GUI::ID::Distributions::All, this, scanI->wavelengthItem());
-    vLayout->addWidget(wavelengthEditor);
-
-    auto* inclinationEditor = new AxisPropertyForm(this, "Grazing angles", &item->alphaAxis(),
-                                                   "Number of points in scan");
-    vLayout->addWidget(inclinationEditor);
-
-    auto* azimuthalEditor =
-        new DistributionEditor("Azimuthal angle", MeanConfig{false}, GUI::ID::Distributions::All,
-                               this, scanI->azimuthalAngleItem());
-    vLayout->addWidget(azimuthalEditor);
-
-    intensityEditor->setText(QString::number(scanI->intensity()));
-
-    auto* collapser = GroupBoxCollapser::installIntoGroupBox(this);
-    collapser->setExpanded(item->isExpandBeamParameters());
-    connect(collapser, &GroupBoxCollapser::toggled, this,
-            [item](bool b) { item->setExpandBeamParameters(b); });
-
-    connect(wavelengthEditor, &DistributionEditor::distributionChanged, this,
-            &OffspecBeamEditor::dataChanged);
-    connect(inclinationEditor, &AxisPropertyForm::dataChanged, this,
-            &OffspecBeamEditor::dataChanged);
-    connect(azimuthalEditor, &DistributionEditor::distributionChanged, this,
-            &OffspecBeamEditor::dataChanged);
-
-    // validate value while typing
-    connect(intensityEditor, &QLineEdit::textEdited, [=]() {
-        QString str = intensityEditor->text();
-        int pos;
-        if (intensityEditor->validator()->validate(str, pos) == QValidator::Acceptable) {
-            scanI->setIntensity(intensityEditor->text().toDouble());
-            emit dataChanged();
-        }
-    });
-    // if validator does not assert the input value, it says about that,
-    // and here we return to the last correct value
-    connect(validator, &FixupDoubleValidator::fixupSignal, [=]() {
-        auto* editor = qobject_cast<QLineEdit*>(validator->parent());
-        editor->setText(QString::number(scanI->intensity(), 'g'));
-    });
-}
diff --git a/GUI/View/Instrument/OffspecBeamEditor.h b/GUI/View/Instrument/OffspecBeamEditor.h
deleted file mode 100644
index ee4d8c447186cbcd7227c72797ef9658118766c7..0000000000000000000000000000000000000000
--- a/GUI/View/Instrument/OffspecBeamEditor.h
+++ /dev/null
@@ -1,34 +0,0 @@
-//  ************************************************************************************************
-//
-//  BornAgain: simulate and fit reflection and scattering
-//
-//! @file      GUI/View/Instrument/OffspecBeamEditor.h
-//! @brief     Defines class OffspecBeamEditor
-//!
-//! @homepage  http://www.bornagainproject.org
-//! @license   GNU General Public License v3 or higher (see COPYING)
-//! @copyright Forschungszentrum Jülich GmbH 2018
-//! @authors   Scientific Computing Group at MLZ (see CITATION, AUTHORS)
-//
-//  ************************************************************************************************
-
-#ifndef BORNAGAIN_GUI_VIEW_INSTRUMENT_OFFSPECBEAMEDITOR_H
-#define BORNAGAIN_GUI_VIEW_INSTRUMENT_OFFSPECBEAMEDITOR_H
-
-#include <QGroupBox>
-
-class OffspecInstrumentItem;
-
-//! Off-specular beam editor. Operates on OffspecInstrumentItem
-
-class OffspecBeamEditor : public QGroupBox {
-    Q_OBJECT
-
-public:
-    OffspecBeamEditor(QWidget* parent, OffspecInstrumentItem* item);
-
-signals:
-    void dataChanged();
-};
-
-#endif // BORNAGAIN_GUI_VIEW_INSTRUMENT_OFFSPECBEAMEDITOR_H
diff --git a/GUI/View/Instrument/OffspecInstrumentEditor.cpp b/GUI/View/Instrument/OffspecInstrumentEditor.cpp
index 9ffb526a28670dbd6b3ab08245bca43039156801..70cb2f73c2c53772fd640eba4f4a2b7975beee21 100644
--- a/GUI/View/Instrument/OffspecInstrumentEditor.cpp
+++ b/GUI/View/Instrument/OffspecInstrumentEditor.cpp
@@ -14,20 +14,22 @@
 
 #include "GUI/View/Instrument/OffspecInstrumentEditor.h"
 #include "GUI/Model/Device/InstrumentItems.h"
-#include "GUI/View/Instrument/OffspecBeamEditor.h"
 #include "GUI/View/Instrument/OffspecDetectorEditor.h"
 #include "GUI/View/Instrument/PolarizationAnalysisEditor.h"
+#include "GUI/View/Instrument/ScanEditor.h"
 
+OffspecInstrumentEditor::OffspecInstrumentEditor(QWidget* parent, OffspecInstrumentItem* instrument,
+                                                 MultiInstrumentNotifier* ec)
 
-OffspecInstrumentEditor::OffspecInstrumentEditor(QWidget* parent, OffspecInstrumentItem* instrument)
     : QWidget(parent)
+    , m_ec(ec, instrument)
 {
     ASSERT(instrument);
     auto* layout = new QVBoxLayout(this);
     layout->setContentsMargins(0, 0, 0, 0);
 
-    auto* beamEditor = new OffspecBeamEditor(this, instrument);
-    layout->addWidget(beamEditor);
+    auto* scanEditor = new ScanEditor(this, instrument->scanItem(), &m_ec);
+    layout->addWidget(scanEditor);
 
     auto* detectorEditor = new OffspecDetectorEditor(this, instrument);
     layout->addWidget(detectorEditor);
@@ -37,8 +39,7 @@ OffspecInstrumentEditor::OffspecInstrumentEditor(QWidget* parent, OffspecInstrum
 
     layout->addStretch();
 
-    connect(beamEditor, &OffspecBeamEditor::dataChanged, this,
-            &OffspecInstrumentEditor::dataChanged);
+    connect(scanEditor, &ScanEditor::dataChanged, this, &OffspecInstrumentEditor::dataChanged);
     connect(detectorEditor, &OffspecDetectorEditor::dataChanged, this,
             &OffspecInstrumentEditor::dataChanged);
     connect(polMatricesAnalysisEditor, &PolarizationAnalysisEditor::dataChanged, this,
diff --git a/GUI/View/Instrument/OffspecInstrumentEditor.h b/GUI/View/Instrument/OffspecInstrumentEditor.h
index dda3efdcdbf83ec3b8e54752df37eddbc4335929..394aefa58d7d4aaa124a8faa3ffcb66eb7d08346 100644
--- a/GUI/View/Instrument/OffspecInstrumentEditor.h
+++ b/GUI/View/Instrument/OffspecInstrumentEditor.h
@@ -15,18 +15,24 @@
 #ifndef BORNAGAIN_GUI_VIEW_INSTRUMENT_OFFSPECINSTRUMENTEDITOR_H
 #define BORNAGAIN_GUI_VIEW_INSTRUMENT_OFFSPECINSTRUMENTEDITOR_H
 
+#include "GUI/Model/Device/InstrumentNotifier.h"
 #include <QWidget>
 
+class MultiInstrumentNotifier;
 class OffspecInstrumentItem;
 
 class OffspecInstrumentEditor : public QWidget {
     Q_OBJECT
 
 public:
-    OffspecInstrumentEditor(QWidget* parent, OffspecInstrumentItem* instrument);
+    OffspecInstrumentEditor(QWidget* parent, OffspecInstrumentItem* instrument,
+                            MultiInstrumentNotifier* ec);
 
 signals:
     void dataChanged();
+
+private:
+    InstrumentNotifier m_ec;
 };
 
 #endif // BORNAGAIN_GUI_VIEW_INSTRUMENT_OFFSPECINSTRUMENTEDITOR_H
diff --git a/GUI/View/Instrument/SpecularBeamEditor.cpp b/GUI/View/Instrument/ScanEditor.cpp
similarity index 92%
rename from GUI/View/Instrument/SpecularBeamEditor.cpp
rename to GUI/View/Instrument/ScanEditor.cpp
index 4e60b3cf4a6fcb998c6183c593478072e768d1ef..27d4dfcdbac35a4fefca33b945dc2e414634c84c 100644
--- a/GUI/View/Instrument/SpecularBeamEditor.cpp
+++ b/GUI/View/Instrument/ScanEditor.cpp
@@ -2,8 +2,8 @@
 //
 //  BornAgain: simulate and fit reflection and scattering
 //
-//! @file      GUI/View/Instrument/SpecularBeamEditor.cpp
-//! @brief     Defines class SpecularBeamEditor
+//! @file      GUI/View/Instrument/ScanEditor.cpp
+//! @brief     Defines class ScanEditor
 //!
 //! @homepage  http://www.bornagainproject.org
 //! @license   GNU General Public License v3 or higher (see COPYING)
@@ -12,11 +12,11 @@
 //
 //  ************************************************************************************************
 
-#include "GUI/View/Instrument/SpecularBeamEditor.h"
+#include "GUI/View/Instrument/ScanEditor.h"
 #include "Base/Util/Assert.h"
-#include "GUI/Model/Device/BeamItems.h"
 #include "GUI/Model/Device/BeamWavelengthItem.h"
 #include "GUI/Model/Device/InstrumentNotifier.h"
+#include "GUI/Model/Device/SourceItems.h"
 #include "GUI/View/Device/FootprintForm.h"
 #include "GUI/View/Instrument/AlphaScanEditor.h"
 #include "GUI/View/Instrument/DistributionEditor.h"
@@ -25,7 +25,7 @@
 #include <QFormLayout>
 #include <QLineEdit>
 
-SpecularBeamEditor::SpecularBeamEditor(QWidget* parent, ScanItem* item, InstrumentNotifier* ec)
+ScanEditor::ScanEditor(QWidget* parent, ScanItem* item, InstrumentNotifier* ec)
     : QGroupBox("Beam and scan parameters", parent)
 {
     ASSERT(item);
@@ -75,7 +75,7 @@ SpecularBeamEditor::SpecularBeamEditor(QWidget* parent, ScanItem* item, Instrume
     connect(inclinationEditor, &AlphaScanEditor::dataChanged, wavelengthEditor,
             &DistributionEditor::updateData);
 
-    connect(footprintEditor, &FootprintForm::dataChanged, this, &SpecularBeamEditor::dataChanged);
+    connect(footprintEditor, &FootprintForm::dataChanged, this, &ScanEditor::dataChanged);
 
     // validate value while typing
     connect(intensityLineEdit, &QLineEdit::textEdited, [=]() {
diff --git a/GUI/View/Instrument/SpecularBeamEditor.h b/GUI/View/Instrument/ScanEditor.h
similarity index 62%
rename from GUI/View/Instrument/SpecularBeamEditor.h
rename to GUI/View/Instrument/ScanEditor.h
index 33c137960b2ab5bf4d7c49bdab4e6d29a04ef3c7..d542a467c0d38fc5bbe9365ba74d6f10bc37ca26 100644
--- a/GUI/View/Instrument/SpecularBeamEditor.h
+++ b/GUI/View/Instrument/ScanEditor.h
@@ -2,8 +2,8 @@
 //
 //  BornAgain: simulate and fit reflection and scattering
 //
-//! @file      GUI/View/Instrument/SpecularBeamEditor.h
-//! @brief     Defines class SpecularBeamEditor
+//! @file      GUI/View/Instrument/ScanEditor.h
+//! @brief     Defines class ScanEditor
 //!
 //! @homepage  http://www.bornagainproject.org
 //! @license   GNU General Public License v3 or higher (see COPYING)
@@ -12,8 +12,8 @@
 //
 //  ************************************************************************************************
 
-#ifndef BORNAGAIN_GUI_VIEW_INSTRUMENT_SPECULARBEAMEDITOR_H
-#define BORNAGAIN_GUI_VIEW_INSTRUMENT_SPECULARBEAMEDITOR_H
+#ifndef BORNAGAIN_GUI_VIEW_INSTRUMENT_SCANEDITOR_H
+#define BORNAGAIN_GUI_VIEW_INSTRUMENT_SCANEDITOR_H
 
 #include <QGroupBox>
 
@@ -22,14 +22,14 @@ class InstrumentNotifier;
 
 //! Specular beam editor. Operates on ScanItem.
 
-class SpecularBeamEditor : public QGroupBox {
+class ScanEditor : public QGroupBox {
     Q_OBJECT
 
 public:
-    SpecularBeamEditor(QWidget* parent, ScanItem* item, InstrumentNotifier* ec);
+    ScanEditor(QWidget* parent, ScanItem* item, InstrumentNotifier* ec);
 
 signals:
     void dataChanged();
 };
 
-#endif // BORNAGAIN_GUI_VIEW_INSTRUMENT_SPECULARBEAMEDITOR_H
+#endif // BORNAGAIN_GUI_VIEW_INSTRUMENT_SCANEDITOR_H
diff --git a/GUI/View/Instrument/SpecularInstrumentEditor.cpp b/GUI/View/Instrument/SpecularInstrumentEditor.cpp
index 8efc66fcf4c58288757644cd541fb1ce528de8dd..5b8d9cce1948c80ae59a430b9d6ec8ac4c4a0fad 100644
--- a/GUI/View/Instrument/SpecularInstrumentEditor.cpp
+++ b/GUI/View/Instrument/SpecularInstrumentEditor.cpp
@@ -16,7 +16,7 @@
 #include "GUI/Model/Device/InstrumentItems.h"
 #include "GUI/View/Device/BackgroundForm.h"
 #include "GUI/View/Instrument/PolarizationAnalysisEditor.h"
-#include "GUI/View/Instrument/SpecularBeamEditor.h"
+#include "GUI/View/Instrument/ScanEditor.h"
 
 SpecularInstrumentEditor::SpecularInstrumentEditor(QWidget* parent,
                                                    SpecularInstrumentItem* instrument,
@@ -28,8 +28,8 @@ SpecularInstrumentEditor::SpecularInstrumentEditor(QWidget* parent,
     auto* layout = new QVBoxLayout(this);
     layout->setContentsMargins(0, 0, 0, 0);
 
-    auto* beamEditor = new SpecularBeamEditor(this, instrument->scanItem(), &m_ec);
-    layout->addWidget(beamEditor);
+    auto* scanEditor = new ScanEditor(this, instrument->scanItem(), &m_ec);
+    layout->addWidget(scanEditor);
 
     auto* polMatricesAnalysisEditor = new PolarizationAnalysisEditor(this, instrument);
     layout->addWidget(polMatricesAnalysisEditor);
@@ -39,8 +39,7 @@ SpecularInstrumentEditor::SpecularInstrumentEditor(QWidget* parent,
 
     layout->addStretch();
 
-    connect(beamEditor, &SpecularBeamEditor::dataChanged, this,
-            &SpecularInstrumentEditor::dataChanged);
+    connect(scanEditor, &ScanEditor::dataChanged, this, &SpecularInstrumentEditor::dataChanged);
     connect(polMatricesAnalysisEditor, &PolarizationAnalysisEditor::dataChanged, this,
             &SpecularInstrumentEditor::dataChanged);
     connect(backgroundForm, &BackgroundForm::dataChanged, this,
diff --git a/Tests/Unit/GUI/TestAutosaveController.cpp b/Tests/Unit/GUI/TestAutosaveController.cpp
index d9ee8fdc09edd929378de4abcafb4f4a0bb1fa3f..1934ae9b4bb03753200fa33e715e3a1a6aa5667b 100644
--- a/Tests/Unit/GUI/TestAutosaveController.cpp
+++ b/Tests/Unit/GUI/TestAutosaveController.cpp
@@ -17,8 +17,7 @@ protected:
     void modify_models(ProjectDocument& doc)
     {
         auto* instrument = doc.instrumentModel()->instrumentItems().front();
-        doc.instrumentsEditController()->setInstrumentName(instrument,
-                                                           QUuid::createUuid().toString());
+        doc.multiNotifier()->setInstrumentName(instrument, QUuid::createUuid().toString());
     }
     const int m_save_wait = 10000;
 };
diff --git a/Tests/Unit/GUI/TestInstrumentItems.cpp b/Tests/Unit/GUI/TestInstrumentItems.cpp
index 008761f4b6256f86906142401034a3fa4944f51a..5bbc0b4ec568164482f6b6785d192b682b40256c 100644
--- a/Tests/Unit/GUI/TestInstrumentItems.cpp
+++ b/Tests/Unit/GUI/TestInstrumentItems.cpp
@@ -11,17 +11,17 @@ TEST(TestInstrumentCollection, instrumentAddedRemoved)
 {
     ProjectDocument document;
 
-    QSignalSpy spy(document.instrumentsEditController(), SIGNAL(instrumentAddedOrRemoved()));
+    QSignalSpy spy(document.multiNotifier(), SIGNAL(instrumentAddedOrRemoved()));
     EXPECT_TRUE(spy.isValid());
 
     // populating instrument model
-    auto* p = document.instrumentsEditController()->addInstrumentItem<GISASInstrumentItem>();
+    auto* p = document.multiNotifier()->addInstrumentItem<GISASInstrumentItem>();
 
     // checking that a signal was emitted about the new instrument
     EXPECT_EQ(spy.count(), 1);
 
     // removing instrument
-    document.instrumentsEditController()->removeInstrument(p);
+    document.multiNotifier()->removeInstrument(p);
     EXPECT_EQ(spy.count(), 2);
 }
 
@@ -32,44 +32,40 @@ TEST(TestInstrumentCollection, instrumentChanged)
     ProjectDocument document;
 
     // populating instrument model
-    auto* instrument1 =
-        document.instrumentsEditController()->addInstrumentItem<GISASInstrumentItem>();
-    auto* instrument2 =
-        document.instrumentsEditController()->addInstrumentItem<SpecularInstrumentItem>();
+    auto* instrument1 = document.multiNotifier()->addInstrumentItem<GISASInstrumentItem>();
+    auto* instrument2 = document.multiNotifier()->addInstrumentItem<SpecularInstrumentItem>();
 
-    QSignalSpy spy(document.instrumentsEditController(),
-                   SIGNAL(instrumentChanged(const InstrumentItem*)));
+    QSignalSpy spy(document.multiNotifier(), SIGNAL(instrumentChanged(const InstrumentItem*)));
     EXPECT_TRUE(spy.isValid());
 
     // change name of instrument 1
-    document.instrumentsEditController()->setInstrumentName(instrument1, "A");
+    document.multiNotifier()->setInstrumentName(instrument1, "A");
     EXPECT_EQ(spy.count(), 1);
     const auto* instr = qvariant_cast<const InstrumentItem*>(spy.at(0).at(0));
     EXPECT_EQ(instr, instrument1);
 
     // change other properties, e.g. id
     instrument1->setId("xxxxx");
-    document.instrumentsEditController()->notifyInstrumentChanged(instrument1);
+    document.multiNotifier()->notifyInstrumentChanged(instrument1);
     EXPECT_EQ(spy.count(), 2);
 
     // change name of instrument 2
-    document.instrumentsEditController()->setInstrumentName(instrument2, "B");
+    document.multiNotifier()->setInstrumentName(instrument2, "B");
     EXPECT_EQ(spy.count(), 3);
     instr = qvariant_cast<const InstrumentItem*>(spy.at(2).at(0));
     EXPECT_EQ(instr, instrument2);
 
     // Add another instrument
-    auto* instrument3 =
-        document.instrumentsEditController()->addInstrumentItem<OffspecInstrumentItem>();
+    auto* instrument3 = document.multiNotifier()->addInstrumentItem<OffspecInstrumentItem>();
 
     // Change instrument2
-    document.instrumentsEditController()->setInstrumentName(instrument2, "BB");
+    document.multiNotifier()->setInstrumentName(instrument2, "BB");
     EXPECT_EQ(spy.count(), 4);
     instr = qvariant_cast<const InstrumentItem*>(spy.at(3).at(0));
     EXPECT_EQ(instr, instrument2);
 
     // Change instrument3
-    document.instrumentsEditController()->setInstrumentName(instrument3, "C");
+    document.multiNotifier()->setInstrumentName(instrument3, "C");
     EXPECT_EQ(spy.count(), 5);
     instr = qvariant_cast<const InstrumentItem*>(spy.at(4).at(0));
     EXPECT_EQ(instr, instrument3);
diff --git a/Tests/Unit/GUI/TestLinkInstrument.cpp b/Tests/Unit/GUI/TestLinkInstrument.cpp
index 99bb0e121bd62aaa0806d08bb1e62ef3492c80d3..3a0a6894fb88c7bb7424d0edb67baa32040259b2 100644
--- a/Tests/Unit/GUI/TestLinkInstrument.cpp
+++ b/Tests/Unit/GUI/TestLinkInstrument.cpp
@@ -55,7 +55,7 @@ TEST(TestLinkInstrument, canLinkToInstrument)
     // changing detector binning and checking that link is destroyed
     auto* detectorItem = dynamic_cast<RectangularDetectorItem*>(instrument->detectorItem());
     detectorItem->setXSize(10);
-    document.instrumentsEditController()->notifyInstrumentChanged(instrument);
+    document.multiNotifier()->notifyInstrumentChanged(instrument);
 
     EXPECT_EQ(linkedRealDataItems(*document.realModel(), instrument), QList<RealItem*>());
     EXPECT_EQ(realData->instrumentId(), QString());
diff --git a/Tests/Unit/GUI/TestProjectDocument.cpp b/Tests/Unit/GUI/TestProjectDocument.cpp
index 91cc0a6c739094b3c8c2685b2ccad40b3954bd51..043dbe4a5cdce763d0471013df95d811a948b6ab 100644
--- a/Tests/Unit/GUI/TestProjectDocument.cpp
+++ b/Tests/Unit/GUI/TestProjectDocument.cpp
@@ -19,8 +19,7 @@ protected:
     void modify_models(ProjectDocument& doc)
     {
         auto* instrument = doc.instrumentModel()->instrumentItems().front();
-        doc.instrumentsEditController()->setInstrumentName(instrument,
-                                                           QUuid::createUuid().toString());
+        doc.multiNotifier()->setInstrumentName(instrument, QUuid::createUuid().toString());
     }
 };