DefaultGraphicsSliderImpl.hpp
1 #pragma once
2 #include <score/graphics/DefaultControlImpl.hpp>
3 #include <score/model/Skin.hpp>
4 #include <score/widgets/DoubleSpinBox.hpp>
5 #include <score/widgets/SignalUtils.hpp>
6 
7 #include <ossia/detail/math.hpp>
8 
9 #include <QGraphicsProxyWidget>
10 #include <QGraphicsScene>
11 #include <QGraphicsSceneMouseEvent>
12 #include <QGuiApplication>
13 #include <QKeyEvent>
14 #include <QPainter>
15 #include <QPointer>
16 #include <QTimer>
17 
18 #include <score_lib_base_export.h>
19 
20 #include <verdigris>
21 namespace score
22 {
23 
25 {
26  QPointer<DoubleSpinboxWithEnter> spinbox{};
27  QPointer<QGraphicsProxyWidget> spinboxProxy{};
28 };
29 
31 {
32  template <typename T>
33  static void paint(
34  T& self, const score::Skin& skin, const QString& text, QPainter* painter,
35  QWidget* widget)
36  {
37  painter->setRenderHint(QPainter::Antialiasing, false);
38 
39  painter->setPen(skin.NoPen);
40  painter->setBrush(skin.Emphasis2.main.brush);
41 
42  // Draw rect
43  const QRectF brect = self.boundingRect();
44  const QRectF srect = self.sliderRect();
45  painter->drawRoundedRect(srect, 1, 1);
46 
47  // Draw text
48 #if defined(__linux__)
49  static const auto dpi_adjust = widget->devicePixelRatioF() > 1 ? 0 : -1;
50 #elif defined(_WIN32)
51  static const constexpr auto dpi_adjust = 0;
52 #else
53  static const constexpr auto dpi_adjust = -2;
54 #endif
55  painter->setPen(skin.Base4.lighter180.pen1);
56  painter->setFont(skin.Medium8Pt);
57  const auto textrect = brect.adjusted(2, srect.height() + 3 + dpi_adjust, -2, -1);
58  painter->drawText(textrect, text, QTextOption(Qt::AlignCenter));
59 
60  // Draw handle
61  painter->fillRect(self.handleRect(), skin.Base4);
62  if(self.m_hasExec)
63  painter->fillRect(self.execHandleRect(), skin.Base4.lighter180.brush);
64  // painter->setPen(QPen(Qt::green, 1));
65  // painter->setBrush(QBrush(Qt::transparent));
66  // painter->drawRect(textrect);
67  //
68  // painter->setPen(QPen(Qt::red, 1));
69  // painter->setBrush(QBrush(Qt::transparent));
70  // painter->drawRect(self.boundingRect());
71  }
72 
73  template <typename T>
74  static void mousePressEvent(T& self, QGraphicsSceneMouseEvent* event)
75  {
76  if(event->button() == Qt::LeftButton && self.isInHandle(event->pos()))
77  {
78  self.m_grab = true;
79 
80  const auto srect = self.sliderRect();
81  const auto posX = event->pos().x() - srect.x();
82  double curPos = self.from01(ossia::clamp(posX, 0., srect.width()) / srect.width());
83  if(curPos != self.m_value)
84  {
85  self.m_value = curPos;
86  self.sliderMoved();
87  self.update();
88  }
89  }
90 
91  event->accept();
92  }
93 
94  template <typename T>
95  static void mouseMoveEvent(T& self, QGraphicsSceneMouseEvent* event)
96  {
97  if((event->buttons() & Qt::LeftButton) && self.m_grab)
98  {
99  const auto srect = self.sliderRect();
100  const auto posX = event->pos().x() - srect.x();
101  double curPos = self.from01(ossia::clamp(posX, 0., srect.width()) / srect.width());
102  if(curPos != self.m_value)
103  {
104  if constexpr(std::is_same_v<decltype(self.m_value), int>)
105  {
106  self.m_value = curPos;
107  }
108  else
109  {
110  double ratio = qGuiApp->keyboardModifiers() & Qt::CTRL ? 0.1 : 1.;
111  self.m_value = std::clamp(
112  double(self.m_value + ((curPos - self.m_value) * ratio)), 0., 1.);
113  }
114 
115  self.sliderMoved();
116  self.update();
117  }
118  }
119  event->accept();
120  }
121 
122  template <typename T>
123  static void mouseReleaseEvent(T& self, QGraphicsSceneMouseEvent* event)
124  {
125  if(self.m_grab)
126  {
127  const auto srect = self.sliderRect();
128  const auto posX = event->pos().x() - srect.x();
129  double curPos = self.from01(ossia::clamp(posX, 0., srect.width()) / srect.width());
130  if(curPos != self.m_value)
131  {
132  if constexpr(std::is_same_v<decltype(self.m_value), int>)
133  {
134  self.m_value = curPos;
135  }
136  else
137  {
138  double ratio = qGuiApp->keyboardModifiers() & Qt::CTRL ? 0.1 : 1.;
139  self.m_value = std::clamp(
140  double(self.m_value + ((curPos - self.m_value) * ratio)), 0., 1.);
141  }
142  self.update();
143  }
144  }
145 
146  self.m_grab = false;
147  self.sliderReleased();
148 
149  if(event->button() == Qt::RightButton)
150  {
151  contextMenuEvent(self, event->scenePos());
152  }
153  event->accept();
154  }
155 
156  template <typename T>
157  static void contextMenuEvent(T& self, QPointF pos)
158  {
159  QTimer::singleShot(0, &self, [&, self_p = &self, pos] {
160  auto w = new DoubleSpinboxWithEnter;
161  self.impl->spinbox = w;
162  w->setRange(self.min, self.max);
163 
164  w->setDecimals(6);
165  w->setValue(self.map(self.m_value));
166  auto obj = self.scene()->addWidget(
167  w, Qt::WindowStaysOnTopHint | Qt::FramelessWindowHint);
168  obj->setPos(pos);
169  self.impl->spinboxProxy = obj;
170 
171  QTimer::singleShot(0, w, [w] { w->setFocus(); });
172 
173  auto con = QObject::connect(
174  w, SignalUtils::QDoubleSpinBox_valueChanged_double(), &self,
175  [&self, obj, scene = self.scene()](double v) {
176  DefaultControlImpl::editWidgetInContextMenu(self, scene, obj, v);
177  });
178 
179  QObject::connect(
180  w, &DoubleSpinboxWithEnter::editingFinished, &self, [obj, con, self_p] {
181  if(self_p->impl->spinbox)
182  {
183  self_p->sliderReleased();
184  QObject::disconnect(con);
185  QTimer::singleShot(0, self_p, [self_p, scene = self_p->scene(), obj] {
186  scene->removeItem(obj);
187  delete obj;
188  self_p->impl->spinbox = nullptr;
189  self_p->impl->spinboxProxy = nullptr;
190  });
191  self_p->impl->spinbox = nullptr;
192  self_p->impl->spinboxProxy = nullptr;
193  }
194  });
195  });
196  }
197 
198  template <typename T>
199  static void mouseDoubleClickEvent(T& self, QGraphicsSceneMouseEvent* event)
200  {
201  self.m_value = self.unmap(self.init);
202 
203  self.m_grab = true;
204  self.sliderMoved();
205  self.sliderReleased();
206  self.m_grab = false;
207 
208  self.update();
209 
210  event->accept();
211  }
212 };
213 
214 }
Definition: Skin.hpp:93
Base toolkit upon which the software is built.
Definition: Application.cpp:90
Definition: DefaultGraphicsSliderImpl.hpp:31
Definition: DoubleSpinBox.hpp:17
Definition: DefaultGraphicsSliderImpl.hpp:25