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/CommandDispatcher.hpp>
6#include <score/document/DocumentContext.hpp>
7#include <score/tools/Bind.hpp>
8
9#include <ossia/detail/math.hpp>
10
11#include <QComboBox>
12#include <QFormLayout>
13#include <QSpinBox>
14
15#include <Patternist/Commands/PatternProperties.hpp>
16#include <Patternist/PatternEdit.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.commandStack}
28 , m_channel{this}
29 , m_lanes{this}
30 , m_length{this}
31 , m_rate{this}
32 , m_labels{this}
33 {
34 m_channel.setRange(1, 16);
35 m_lanes.setRange(1, 127);
36 m_length.setRange(1, Pattern::maxLength);
37 m_rate.setRange(1, 64);
38 m_rate.setPrefix(QStringLiteral("1/"));
39 m_rate.setToolTip(tr("Steps per whole note"));
40 for(auto box : {&m_channel, &m_lanes, &m_length, &m_rate})
41 box->setKeyboardTracking(false);
42
43 m_labels.addItem(tr("Note and number"), int(LaneLabels::NameAndNumber));
44 m_labels.addItem(tr("Note name"), int(LaneLabels::Name));
45 m_labels.addItem(tr("MIDI number"), int(LaneLabels::Number));
46 m_labels.addItem(tr("General MIDI drum"), int(LaneLabels::DrumName));
47
48 auto lay = new QFormLayout{this};
49 lay->addRow(tr("Channel"), &m_channel);
50 lay->addRow(tr("Lanes"), &m_lanes);
51 lay->addRow(tr("Steps"), &m_length);
52 lay->addRow(tr("Rate"), &m_rate);
53 lay->addRow(tr("Labels"), &m_labels);
54
55 updateFromModel();
56
57 con(obj, &ProcessModel::channelChanged, this, [this] { updateFromModel(); });
58 con(obj, &ProcessModel::currentPatternChanged, this, [this] { updateFromModel(); });
59 con(obj, &ProcessModel::patternsChanged, this, [this] { updateFromModel(); });
60 con(obj, &ProcessModel::laneLabelsChanged, this, [this] { updateFromModel(); });
61
62 con(m_channel, qOverload<int>(&QSpinBox::valueChanged), this, [this](int v) {
63 if(v != process().channel())
64 m_dispatcher.submit<SetPatternChannel>(process(), v);
65 });
66
67 con(m_lanes, qOverload<int>(&QSpinBox::valueChanged), this, [this](int n) {
68 editPattern([n](Pattern& p) {
69 if(n < int(p.lanes.size()))
70 p.lanes.resize(n);
71 while(int(p.lanes.size()) < n)
72 addLane(p);
73 });
74 });
75
76 con(m_length, qOverload<int>(&QSpinBox::valueChanged), this,
77 [this](int n) { editPattern([n](Pattern& p) { setLength(p, n); }); });
78
79 con(m_rate, qOverload<int>(&QSpinBox::valueChanged), this,
80 [this](int n) { editPattern([n](Pattern& p) { p.division = n; }); });
81
82 con(m_labels, qOverload<int>(&QComboBox::currentIndexChanged), this, [this](int) {
83 const auto l = LaneLabels(m_labels.currentData().toInt());
84 if(l != process().laneLabels())
85 m_dispatcher.submit<SetLaneLabels>(process(), l);
86 });
87 }
88
89private:
90 template <typename F>
91 void editPattern(F f)
92 {
93 const auto& obj = process();
94 if(!ossia::valid_index(obj.currentPattern(), obj.patterns()))
95 return;
96 auto p = obj.patterns()[obj.currentPattern()];
97 f(p);
98 normalize(p);
99 if(p != obj.patterns()[obj.currentPattern()])
100 m_dispatcher.submit<UpdatePattern>(obj, obj.currentPattern(), p);
101 }
102
103 void updateFromModel()
104 {
105 const auto& obj = process();
106 QSignalBlocker b0{m_channel}, b1{m_lanes}, b2{m_length}, b3{m_rate}, b4{m_labels};
107 m_channel.setValue(obj.channel());
108 m_labels.setCurrentIndex(m_labels.findData(int(obj.laneLabels())));
109
110 const bool valid = ossia::valid_index(obj.currentPattern(), obj.patterns());
111 for(auto box : {&m_lanes, &m_length, &m_rate})
112 box->setEnabled(valid);
113 if(!valid)
114 return;
115 const Pattern& pat = obj.patterns()[obj.currentPattern()];
116 m_lanes.setValue(pat.lanes.size());
117 m_length.setValue(pat.length);
118 m_rate.setValue(pat.division);
119 }
120
121 CommandDispatcher<> m_dispatcher;
122
123 QSpinBox m_channel;
124 QSpinBox m_lanes;
125 QSpinBox m_length;
126 QSpinBox m_rate;
127 QComboBox m_labels;
128};
130 : public Process::InspectorWidgetDelegateFactory_T<ProcessModel, InspectorWidget>
131{
132 SCORE_CONCRETE("03d55730-fc4a-42a7-b573-35c330c5bad2")
133};
134}
The CommandDispatcher class.
Definition CommandDispatcher.hpp:13
Definition PatternInspector.hpp:131
Definition PatternInspector.hpp:22
Definition PatternModel.hpp:247
Definition PatternProperties.hpp:18
Definition ProcessInspectorWidgetDelegate.hpp:13
Definition ProcessInspectorWidgetDelegateFactory.hpp:53
Definition PatternModel.hpp:139
Definition DocumentContext.hpp:18