Skip to content

Commit

Permalink
[magnetism] Allow processes to have magnetism too
Browse files Browse the repository at this point in the history
  • Loading branch information
jcelerier committed Sep 2, 2023
1 parent b8bfdd6 commit 2ee0812
Show file tree
Hide file tree
Showing 9 changed files with 115 additions and 4 deletions.
6 changes: 6 additions & 0 deletions src/plugins/score-lib-process/Process/Process.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -320,6 +320,12 @@ void ProcessModel::setSlotHeight(double v) noexcept
slotHeightChanged(v);
}

std::optional<Process::MagneticInfo>
ProcessModel::magneticPosition(const QObject* o, const TimeVal t) const noexcept
{
return {};
}

ProcessModel* parentProcess(QObject* obj) noexcept
{
if(obj)
Expand Down
7 changes: 7 additions & 0 deletions src/plugins/score-lib-process/Process/Process.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@
#include <Process/ProcessFlags.hpp>
#include <Process/TimeValue.hpp>

#include <Magnetism/MagneticInfo.hpp>

#include <score/model/Component.hpp>
#include <score/model/EntityImpl.hpp>
#include <score/model/Identifier.hpp>
Expand All @@ -22,6 +24,7 @@
#include <score_lib_process_export.h>
#include <smallfun.hpp>

#include <optional>
#include <vector>
#include <verdigris>

Expand Down Expand Up @@ -133,6 +136,10 @@ class SCORE_LIB_PROCESS_EXPORT ProcessModel
virtual void forEachControl(
smallfun::function<void(Process::ControlInlet&, const ossia::value&)>) const;

// Magnetism
virtual std::optional<Process::MagneticInfo>
magneticPosition(const QObject* o, const TimeVal t) const noexcept;

// Clip duration things
bool loops() const noexcept { return m_loops; }
void setLoops(bool b);
Expand Down
10 changes: 10 additions & 0 deletions src/plugins/score-plugin-automation/Color/GradientModel.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -167,6 +167,16 @@ Process::Preset ProcessModel::savePreset() const noexcept
return p;
}

std::optional<Process::MagneticInfo>
ProcessModel::magneticPosition(const QObject* o, const TimeVal t) const noexcept
{
double pos = t.impl / double(this->duration().impl);

auto it = m_colors.lower_bound(pos);
if(it != m_colors.end())
return Process::MagneticInfo{TimeVal(it->first * this->duration().impl), true};
return {};
}
}

template <>
Expand Down
3 changes: 3 additions & 0 deletions src/plugins/score-plugin-automation/Color/GradientModel.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,9 @@ class SCORE_PLUGIN_AUTOMATION_EXPORT ProcessModel final : public Process::Proces
void loadPreset(const Process::Preset& preset) override;
Process::Preset savePreset() const noexcept override;

std::optional<Process::MagneticInfo>
magneticPosition(const QObject* o, const TimeVal t) const noexcept override;

void setDurationAndScale(const TimeVal& newDuration) noexcept override;
void setDurationAndGrow(const TimeVal& newDuration) noexcept override;
void setDurationAndShrink(const TimeVal& newDuration) noexcept override;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -620,6 +620,10 @@ Process::MagneticInfo FullViewIntervalPresenter::magneticPosition(
TimeVal scenarioT = t;
TimeVal closestTimeSyncT = TimeVal::fromMsecs(std::numeric_limits<int32_t>::max());
bool snapToScenario{};
bool foundMagnetism = false;

// Priority order:
// 1. In the object's parent process
if(auto given_ts = qobject_cast<const Scenario::TimeSyncModel*>(o))
{
if(auto scenario = qobject_cast<Scenario::ProcessModel*>(given_ts->parent()))
Expand All @@ -639,10 +643,80 @@ Process::MagneticInfo FullViewIntervalPresenter::magneticPosition(
{
scenarioT = closestTimeSyncT;
snapToScenario = true;
foundMagnetism = true;
}
}
}

auto is_parent = [](QObject* const parent, const QObject* child) {
while((child = child->parent()))
{
if(child == parent)
return true;
}
return false;
};

// 2. In the processes around
if(!foundMagnetism)
{
for(auto& proc : this->model().processes)
{
if(!is_parent(&proc, o))
{
if(auto pos = proc.magneticPosition(o, t))
{
if(std::abs(pos->time.impl - t.impl)
< std::abs(closestTimeSyncT.impl - t.impl))
closestTimeSyncT = pos->time;
}
}
}

double delta = std::abs((closestTimeSyncT - t).toPixels(m_zoomRatio));
if(delta < 10)
{
scenarioT = closestTimeSyncT;
snapToScenario = true;
foundMagnetism = true;
}
}

// 3. In the child processes around the closest scenario to the moved object

if(!foundMagnetism)
{
auto parentScenar = Scenario::closestParentScenario(o);
if(parentScenar)
{
for(auto& itv : parentScenar->intervals)
{
for(auto& proc : itv.processes)
{
if(!is_parent(&proc, o))
{
if(auto pos = proc.magneticPosition(o, t))
{
if(std::abs(pos->time.impl - t.impl)
< std::abs(closestTimeSyncT.impl - t.impl))
closestTimeSyncT = pos->time;
}
}
}
}
}

double delta = std::abs((closestTimeSyncT - t).toPixels(m_zoomRatio));
if(delta < 10)
{
scenarioT = closestTimeSyncT;
snapToScenario = true;
foundMagnetism = true;
}
}

// 4. That's all, don't search deeper

if(!m_settings.getMagneticMeasures() || !m_settings.getMeasureBars())
return {scenarioT, snapToScenario};

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1057,13 +1057,13 @@ QPointF newProcessPosition(const IntervalModel& cst) noexcept
}

// TODO refactor by grepping for _cast.*IntervalModel
IntervalModel* closestParentInterval(QObject* parentObj) noexcept
IntervalModel* closestParentInterval(const QObject* parentObj) noexcept
{
while(parentObj && !qobject_cast<Scenario::IntervalModel*>(parentObj))
while(parentObj && !qobject_cast<const Scenario::IntervalModel*>(parentObj))
{
parentObj = parentObj->parent();
}
return static_cast<IntervalModel*>(parentObj);
return static_cast<IntervalModel*>(const_cast<QObject*>(parentObj));
}

TimeVal timeDelta(const IntervalModel* self, const IntervalModel* parent)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -323,7 +323,7 @@ struct ParentTimeInfo
};

SCORE_PLUGIN_SCENARIO_EXPORT
IntervalModel* closestParentInterval(QObject*) noexcept;
IntervalModel* closestParentInterval(const QObject*) noexcept;

SCORE_PLUGIN_SCENARIO_EXPORT
ParentTimeInfo closestParentWithMusicalMetrics(const IntervalModel*);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -297,4 +297,13 @@ Process::Preset ProcessModel::savePreset() const noexcept
p.data = r.toByteArray();
return p;
}

Scenario::ProcessModel* closestParentScenario(const QObject* parentObj) noexcept
{
while(parentObj && !qobject_cast<const Scenario::ProcessModel*>(parentObj))
{
parentObj = parentObj->parent();
}
return static_cast<Scenario::ProcessModel*>(const_cast<QObject*>(parentObj));
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -203,6 +203,8 @@ class SCORE_PLUGIN_SCENARIO_EXPORT ProcessModel final

std::unique_ptr<TimenodeGraph> m_graph;
};

Scenario::ProcessModel* closestParentScenario(const QObject* parentObj) noexcept;
}
// TODO this ought to go in Selection.hpp ?
template <typename Vector>
Expand Down

0 comments on commit 2ee0812

Please sign in to comment.