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