Loading...
Searching...
No Matches
NumericValueWidget.hpp
1#pragma once
2#include "ValueWidget.hpp"
3
4#include <score/widgets/MarginLess.hpp>
5#include <score/widgets/SpinBoxes.hpp>
6#include <score/widgets/TextLabel.hpp>
7
8#include <ossia/network/domain/domain.hpp>
9
10#include <QCheckBox>
11#include <QDialog>
12#include <QDialogButtonBox>
13#include <QGridLayout>
14#include <QHBoxLayout>
15#include <QPushButton>
16#include <QVBoxLayout>
17
18namespace State
19{
20template <typename T>
21using MatchingSpinbox = typename score::TemplatedSpinBox<T>::spinbox_type;
22
23template <typename T>
24class NumericValueWidget final : public ValueWidget
25{
26public:
27 NumericValueWidget(T value, QWidget* parent = nullptr)
28 : ValueWidget{parent}
29 {
30 auto lay = new score::MarginLess<QGridLayout>{this};
31 m_valueSBox = new score::SpinBox<T>{this};
32 lay->addWidget(m_valueSBox);
33 m_valueSBox->setValue(value);
34 }
35
36 ossia::value value() const override { return ossia::value{m_valueSBox->value()}; }
37
38private:
39 score::SpinBox<T>* m_valueSBox{};
40};
41
42template <typename T>
43class NumericValueSetDialog final : public QDialog
44{
45public:
46 using set_type = std::vector<T>;
47 NumericValueSetDialog(QWidget* parent)
48 : QDialog{parent}
49 {
50 auto lay = new score::MarginLess<QVBoxLayout>{this};
51 this->setLayout(lay);
52 lay->addLayout(m_lay = new score::MarginLess<QVBoxLayout>);
53
54 auto addbutton = new QPushButton{tr("+"), this};
55 connect(addbutton, &QPushButton::pressed, this, [this] { addRow({}); });
56 lay->addWidget(addbutton);
57
58 auto buttonBox
59 = new QDialogButtonBox{QDialogButtonBox::Ok | QDialogButtonBox::Cancel};
60
61 lay->addWidget(buttonBox);
62
63 connect(buttonBox, &QDialogButtonBox::accepted, this, &QDialog::accept);
64 connect(buttonBox, &QDialogButtonBox::rejected, this, &QDialog::reject);
65 }
66
67 set_type values()
68 {
69 set_type t;
70 for(auto widg : m_widgs)
71 {
72 t.push_back(widg->value().template get<T>());
73 }
74 return t;
75 }
76
77 void setValues(const set_type& t)
78 {
79 // OPTIMIZEME by reusing
80 for(auto row : m_rows)
81 delete row;
82 m_rows.clear();
83 m_widgs.clear();
84
85 for(auto val : t)
86 {
87 addRow(val);
88 }
89 }
90
91private:
92 void addRow(T c)
93 {
94 auto sub_widg = new QWidget{this};
95 auto sub_lay = new score::MarginLess<QHBoxLayout>{sub_widg};
96
97 auto minus_b = new QPushButton{tr("-"), this};
98 sub_lay->addWidget(minus_b);
99
100 connect(minus_b, &QPushButton::clicked, this, [this, i = m_rows.size()] {
101 removeRow(i);
102 });
103
104 auto widg = new NumericValueWidget<T>{c, this};
105 sub_lay->addWidget(widg);
106
107 m_lay->addWidget(sub_widg);
108 m_rows.push_back(sub_widg);
109 m_widgs.push_back(widg);
110 }
111
112 void removeRow(std::size_t i)
113 {
114 if(i < m_rows.size())
115 {
116 delete m_rows[i];
117 m_rows.erase(m_rows.begin() + i);
118 m_widgs.erase(m_widgs.begin() + i);
119 }
120 }
121
122 QVBoxLayout* m_lay{};
123 std::vector<QWidget*> m_rows;
124 std::vector<NumericValueWidget<T>*> m_widgs;
125};
126
127template <typename T>
128class NumericDomainWidget final : public QWidget
129{
130public:
131 using domain_type = ossia::domain_base<T>;
132 using set_type = std::vector<T>;
133
134 NumericDomainWidget(QWidget* parent)
135 : QWidget{parent}
136 {
137 auto lay = new score::MarginLess<QHBoxLayout>{this};
138 this->setLayout(lay);
139
140 m_minCB = new QCheckBox{tr("Min"), this};
141 m_maxCB = new QCheckBox{tr("Max"), this};
142 m_min = new score::SpinBox<T>{this};
143 m_max = new score::SpinBox<T>{this};
144 lay->addWidget(m_minCB);
145 lay->addWidget(m_min);
146 lay->addWidget(m_maxCB);
147 lay->addWidget(m_max);
148
149 m_min->setEnabled(false);
150 m_max->setEnabled(false);
151
152 connect(m_minCB, &QCheckBox::stateChanged, this, [this](int st) {
153 m_min->setEnabled(bool(st));
154 });
155 connect(m_maxCB, &QCheckBox::stateChanged, this, [this](int st) {
156 m_max->setEnabled(bool(st));
157 });
158 auto pb = new QPushButton{tr("Values"), this};
159 lay->addWidget(pb);
160
161 connect(pb, &QPushButton::clicked, this, [this] {
162 NumericValueSetDialog<T> dial{this};
163 dial.setValues(m_values);
164
165 if(dial.exec())
166 {
167 m_values = dial.values();
168 }
169 });
170 }
171
172 domain_type domain() const
173 {
174 domain_type dom;
175
176 if(m_minCB->checkState())
177 dom.min = m_min->value();
178 else
179 dom.min = std::nullopt;
180
181 if(m_maxCB->checkState())
182 dom.max = m_max->value();
183 else
184 dom.max = std::nullopt;
185
186 dom.values = m_values;
187
188 return dom;
189 }
190
191 void set_domain(ossia::domain dom_base)
192 {
193 m_values.clear();
194 m_minCB->setCheckState(Qt::Unchecked);
195 m_maxCB->setCheckState(Qt::Unchecked);
196
197 if(auto dom_p = dom_base.v.target<domain_type>())
198 {
199 auto& dom = *dom_p;
200
201 if(dom.min)
202 {
203 m_minCB->setCheckState(Qt::Checked);
204 m_min->setValue(*dom.min);
205 }
206 if(dom.max)
207 {
208 m_maxCB->setCheckState(Qt::Checked);
209 m_max->setValue(*dom.max);
210 }
211
212 m_values = dom.values;
213 }
214 }
215
216private:
217 QCheckBox* m_minCB{};
218 QCheckBox* m_maxCB{};
219 score::SpinBox<T>* m_min{};
220 score::SpinBox<T>* m_max{};
221
222 set_type m_values;
223};
224}
Definition NumericValueWidget.hpp:129
Definition NumericValueWidget.hpp:44
Definition NumericValueWidget.hpp:25
The ValueWidget class.
Definition ValueWidget.hpp:25
The MarginLess class.
Definition MarginLess.hpp:14
The SpinBox class.
Definition SpinBoxes.hpp:68
Utilities for OSSIA data structures.
Definition DeviceInterface.hpp:33
The TemplatedSpinBox class.
Definition SpinBoxes.hpp:19