Loading...
Searching...
No Matches
PatternInspector.hpp
1#pragma once
2#include <Process/Inspector/ProcessInspectorWidgetDelegate.hpp>
3#include <Process/Inspector/ProcessInspectorWidgetDelegateFactory.hpp>
4
5#include <score/command/Dispatchers/OngoingCommandDispatcher.hpp>
6#include <score/document/DocumentContext.hpp>
7#include <score/tools/Bind.hpp>
8#include <score/widgets/DoubleSlider.hpp>
9#include <score/widgets/SignalUtils.hpp>
10
11#include <ossia/detail/math.hpp>
12
13#include <QFormLayout>
14#include <QSpinBox>
15
16#include <Patternist/Commands/PatternProperties.hpp>
17#include <Patternist/PatternModel.hpp>
18
19namespace Patternist
20{
21class InspectorWidget final : public Process::InspectorWidgetDelegate_T<ProcessModel>
22{
23public:
24 explicit InspectorWidget(
25 const ProcessModel& obj, const score::DocumentContext& doc, QWidget* parent)
26 : InspectorWidgetDelegate_T{obj, parent}
27 , m_dispatcher{doc.dispatcher}
28 , m_channel{this}
29 , m_lanes{this}
30 , m_duration{this}
31 , m_rate{this}
32 {
33 m_duration.setRange(4, 32);
34 m_rate.setRange(1, 64);
35 m_channel.setRange(1, 16);
36 m_lanes.setRange(1, 127);
37
38 m_channel.setValue(obj.channel());
39
40 if(!ossia::valid_index(obj.currentPattern(), obj.patterns()))
41 return;
42 const Pattern& pat = obj.patterns()[obj.currentPattern()];
43 m_lanes.setValue(pat.lanes.size());
44 m_duration.setValue(pat.length);
45 m_rate.setValue(pat.division);
46
47 auto lay = new QFormLayout{this};
48
49 con(process(), &ProcessModel::channelChanged, this, [&](int c) {
50 if(c != m_channel.value())
51 m_channel.setValue(c);
52 });
53 con(process(), &ProcessModel::currentPatternChanged, this, [&](int c) {
54 const Pattern& pat = obj.patterns()[c];
55 m_lanes.blockSignals(true);
56 m_duration.blockSignals(true);
57 m_rate.blockSignals(true);
58
59 m_lanes.setValue(pat.lanes.size());
60 m_duration.setValue(pat.length);
61 m_rate.setValue(pat.division);
62
63 m_lanes.blockSignals(false);
64 m_duration.blockSignals(false);
65 m_rate.blockSignals(false);
66 });
67 con(process(), &ProcessModel::patternsChanged, this, [&] {
68 if(!ossia::valid_index(obj.currentPattern(), obj.patterns()))
69 return;
70
71 const Pattern& pat = obj.patterns()[obj.currentPattern()];
72 m_lanes.blockSignals(true);
73 m_duration.blockSignals(true);
74 m_rate.blockSignals(true);
75
76 m_lanes.setValue(pat.lanes.size());
77 m_duration.setValue(pat.length);
78 m_rate.setValue(pat.division);
79
80 m_lanes.blockSignals(false);
81 m_duration.blockSignals(false);
82 m_rate.blockSignals(false);
83 });
84
85 con(m_channel, qOverload<int>(&QSpinBox::valueChanged), this, [&](int v) {
86 if(v != obj.channel())
87 m_dispatcher.submit<SetPatternChannel>(obj, v);
88 });
89 con(m_channel, &QSpinBox::editingFinished, this, [&] { m_dispatcher.commit(); });
90
91 con(m_lanes, qOverload<int>(&QSpinBox::valueChanged), this, [&](int nn) {
92 if(nn <= 0)
93 return;
94
95 if(!ossia::valid_index(obj.currentPattern(), obj.patterns()))
96 return;
97
98 const std::size_t n = nn;
99
100 auto p = obj.patterns()[obj.currentPattern()];
101 if(n == p.lanes.size())
102 {
103 return;
104 }
105 else if(n < p.lanes.size())
106 {
107 p.lanes.resize(n);
108 }
109 else
110 {
111 auto last_lane = p.lanes.back();
112 while(p.lanes.size() < n)
113 p.lanes.push_back(last_lane);
114 }
115
116 m_dispatcher.submit<UpdatePattern>(obj, obj.currentPattern(), p);
117 });
118
119 con(m_lanes, &QSpinBox::editingFinished, this, [&]() { m_dispatcher.commit(); });
120
121 con(m_duration, qOverload<int>(&QSpinBox::valueChanged), this, [&]() {
122 int n = m_duration.value();
123 if(n <= 0)
124 return;
125
126 auto p = obj.patterns()[obj.currentPattern()];
127 if(p.length == n)
128 return;
129
130 p.length = n;
131 if(p.length > int64_t(p.lanes[0].pattern.size()))
132 {
133 for(auto& lane : p.lanes)
134 {
135 lane.pattern.resize(n);
136 }
137 }
138
139 m_dispatcher.submit<UpdatePattern>(obj, obj.currentPattern(), p);
140 });
141 con(m_duration, &QSpinBox::editingFinished, this, [&]() { m_dispatcher.commit(); });
142
143 con(m_rate, &QDoubleSpinBox::editingFinished, this, [&] {
144 auto p = obj.patterns()[obj.currentPattern()];
145 if(p.division != m_rate.value())
146 p.division = m_rate.value();
147 m_dispatcher.submit<UpdatePattern>(obj, obj.currentPattern(), p);
148 m_dispatcher.commit();
149 });
150
151 lay->addRow(tr("Channel"), &m_channel);
152 lay->addRow(tr("Lanes"), &m_lanes);
153 lay->addRow(tr("Steps"), &m_duration);
154 lay->addRow(tr("Rate"), &m_rate);
155 }
156
157private:
158 OngoingCommandDispatcher& m_dispatcher;
159
160 QSpinBox m_channel;
161 QSpinBox m_lanes;
162 QSpinBox m_duration;
163 QDoubleSpinBox m_rate;
164};
166 : public Process::InspectorWidgetDelegateFactory_T<ProcessModel, InspectorWidget>
167{
168 SCORE_CONCRETE("03d55730-fc4a-42a7-b573-35c330c5bad2")
169};
170}
The OngoingCommandDispatcher class.
Definition OngoingCommandDispatcher.hpp:29
void submit(Watched &&watched, Args &&... args)
Definition OngoingCommandDispatcher.hpp:46
void commit()
Definition Document.cpp:67
Definition PatternInspector.hpp:167
Definition PatternInspector.hpp:22
Definition PatternModel.hpp:49
Definition PatternProperties.hpp:16
Definition ProcessInspectorWidgetDelegate.hpp:13
Definition ProcessInspectorWidgetDelegateFactory.hpp:53
Definition PatternModel.hpp:37
Definition DocumentContext.hpp:18