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 
18 namespace State
19 {
20 template <typename T>
21 using MatchingSpinbox = typename score::TemplatedSpinBox<T>::spinbox_type;
22 
23 template <typename T>
24 class NumericValueWidget final : public ValueWidget
25 {
26 public:
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 
38 private:
39  score::SpinBox<T>* m_valueSBox{};
40 };
41 
42 template <typename T>
43 class NumericValueSetDialog final : public QDialog
44 {
45 public:
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 
91 private:
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 
127 template <typename T>
128 class NumericDomainWidget final : public QWidget
129 {
130 public:
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 
216 private:
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 SpinBox class.
Definition: SpinBoxes.hpp:68
Utilities for OSSIA data structures.
Definition: DeviceInterface.hpp:33
The TemplatedSpinBox class.
Definition: SpinBoxes.hpp:19