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_currentPattern{this}
30 , m_lanes{this}
31 , m_duration{this}
32 , m_rate{this}
33 {
34 m_duration.setRange(4, 32);
35 m_rate.setRange(1, 64);
36 m_channel.setRange(1, 16);
37 m_lanes.setRange(1, 127);
38
39 m_channel.setValue(obj.channel());
40
41 if(!ossia::valid_index(obj.currentPattern(), obj.patterns()))
42 return;
43 const Pattern& pat = obj.patterns()[obj.currentPattern()];
44 m_lanes.setValue(pat.lanes.size());
45 m_duration.setValue(pat.length);
46 m_rate.setValue(pat.division);
47 m_currentPattern.setValue(obj.currentPattern());
48
49 auto lay = new QFormLayout{this};
50
51 con(process(), &ProcessModel::channelChanged, this, [&](int c) {
52 if(c != m_channel.value())
53 m_channel.setValue(c);
54 });
55 con(process(), &ProcessModel::currentPatternChanged, this, [&](int c) {
56 if(c == m_currentPattern.value())
57 return;
58
59 m_currentPattern.setValue(c);
60
61 const Pattern& pat = obj.patterns()[c];
62 m_lanes.blockSignals(true);
63 m_duration.blockSignals(true);
64 m_rate.blockSignals(true);
65
66 m_lanes.setValue(pat.lanes.size());
67 m_duration.setValue(pat.length);
68 m_rate.setValue(pat.division);
69
70 m_lanes.blockSignals(false);
71 m_duration.blockSignals(false);
72 m_rate.blockSignals(false);
73 });
74 con(process(), &ProcessModel::patternsChanged, this, [&] {
75 if(!ossia::valid_index(obj.currentPattern(), obj.patterns()))
76 return;
77
78 const Pattern& pat = obj.patterns()[obj.currentPattern()];
79 m_lanes.blockSignals(true);
80 m_duration.blockSignals(true);
81 m_rate.blockSignals(true);
82
83 m_lanes.setValue(pat.lanes.size());
84 m_duration.setValue(pat.length);
85 m_rate.setValue(pat.division);
86
87 m_lanes.blockSignals(false);
88 m_duration.blockSignals(false);
89 m_rate.blockSignals(false);
90 });
91
92 con(m_channel, qOverload<int>(&QSpinBox::valueChanged), this, [&](int v) {
93 if(v != obj.channel())
94 m_dispatcher.submit<SetPatternChannel>(obj, v);
95 });
96 con(m_channel, &QSpinBox::editingFinished, this, [&] { m_dispatcher.commit(); });
97
98 con(m_lanes, qOverload<int>(&QSpinBox::valueChanged), this, [&](int nn) {
99 if(nn <= 0)
100 return;
101
102 if(!ossia::valid_index(obj.currentPattern(), obj.patterns()))
103 return;
104
105 const std::size_t n = nn;
106
107 auto p = obj.patterns()[obj.currentPattern()];
108 if(n == p.lanes.size())
109 {
110 return;
111 }
112 else if(n < p.lanes.size())
113 {
114 p.lanes.resize(n);
115 }
116 else
117 {
118 auto last_lane = p.lanes.back();
119 while(p.lanes.size() < n)
120 p.lanes.push_back(last_lane);
121 }
122
123 m_dispatcher.submit<UpdatePattern>(obj, obj.currentPattern(), p);
124 });
125
126 con(m_lanes, &QSpinBox::editingFinished, this, [&]() { m_dispatcher.commit(); });
127
128 con(m_currentPattern, qOverload<int>(&QSpinBox::valueChanged), this, [&](int v) {
129 if(v != obj.currentPattern())
130 m_dispatcher.submit<SetCurrentPattern>(obj, v);
131 });
132 con(m_currentPattern, &QSpinBox::editingFinished, this,
133 [&]() { m_dispatcher.commit(); });
134
135 con(m_duration, qOverload<int>(&QSpinBox::valueChanged), this, [&]() {
136 int n = m_duration.value();
137 if(n <= 0)
138 return;
139
140 auto p = obj.patterns()[obj.currentPattern()];
141 if(p.length == n)
142 return;
143
144 p.length = n;
145 if(p.length > int64_t(p.lanes[0].pattern.size()))
146 {
147 for(auto& lane : p.lanes)
148 {
149 lane.pattern.resize(n);
150 }
151 }
152
153 m_dispatcher.submit<UpdatePattern>(obj, obj.currentPattern(), p);
154 });
155 con(m_duration, &QSpinBox::editingFinished, this, [&]() { m_dispatcher.commit(); });
156
157 con(m_rate, &QDoubleSpinBox::editingFinished, this, [&] {
158 auto p = obj.patterns()[obj.currentPattern()];
159 if(p.division != m_rate.value())
160 p.division = m_rate.value();
161 m_dispatcher.submit<UpdatePattern>(obj, obj.currentPattern(), p);
162 m_dispatcher.commit();
163 });
164
165 lay->addRow(tr("Channel"), &m_channel);
166 lay->addRow(tr("Current pattern"), &m_currentPattern);
167 lay->addRow(tr("Lanes"), &m_lanes);
168 lay->addRow(tr("Steps"), &m_duration);
169 lay->addRow(tr("Rate"), &m_rate);
170 }
171
172private:
173 OngoingCommandDispatcher& m_dispatcher;
174
175 QSpinBox m_channel;
176 QSpinBox m_currentPattern;
177 QSpinBox m_lanes;
178 QSpinBox m_duration;
179 QDoubleSpinBox m_rate;
180};
182 : public Process::InspectorWidgetDelegateFactory_T<ProcessModel, InspectorWidget>
183{
184 SCORE_CONCRETE("03d55730-fc4a-42a7-b573-35c330c5bad2")
185};
186}
The OngoingCommandDispatcher class.
Definition OngoingCommandDispatcher.hpp:27
void submit(Args &&... args)
Definition OngoingCommandDispatcher.hpp:37
void commit()
Definition OngoingCommandDispatcher.hpp:61
Definition PatternInspector.hpp:183
Definition PatternInspector.hpp:22
Definition PatternModel.hpp:48
Definition PatternProperties.hpp:16
Definition ProcessInspectorWidgetDelegate.hpp:13
Definition ProcessInspectorWidgetDelegateFactory.hpp:53
Definition PatternModel.hpp:36
Definition DocumentContext.hpp:18