28 T& self,
const score::Skin& skin,
const QString& text, QPainter* painter,
31 painter->setRenderHint(QPainter::Antialiasing,
true);
33 painter->setPen(skin.NoPen);
34 painter->setBrush(skin.Emphasis2.main.brush);
37 const QRectF brect = self.boundingRect();
38 painter->drawRoundedRect(brect, 1, 1);
41 painter->setPen(skin.Base4.main.pen1);
42 painter->setFont(skin.Medium8Pt);
43 const auto textrect = brect.adjusted(2, 3, -2, -2);
44 painter->drawText(textrect, text, QTextOption(Qt::AlignLeft));
46 painter->setRenderHint(QPainter::Antialiasing,
false);
50 static void mousePressEvent(T& self, QGraphicsSceneMouseEvent* event)
52 if(event->button() == Qt::LeftButton)
55 InfiniteScroller::start(self, (self.max - self.min) * self.m_value + self.min);
64 static double deltaFor(
double orig,
double bound,
double height)
noexcept
66 const double k = (orig - bound) * height;
67 return k >= 0. ? (-1. + std::sqrt(1. + 4. * k)) / 2.
68 : (1. - std::sqrt(1. - 4. * k)) / 2.;
72 static double mapValue(T& self, QGraphicsSceneMouseEvent* event)
noexcept
74 InfiniteScroller::move_free(event);
76 = std::pow(10., std::log10(1. + std::abs(InfiniteScroller::currentDelta)));
78 const double height = double(InfiniteScroller::currentGeometry.height());
79 auto v = InfiniteScroller::origValue - speed * InfiniteScroller::currentDelta / height;
84 const double bounded = std::clamp(v,
double(self.min),
double(self.max));
87 InfiniteScroller::currentDelta
88 = deltaFor(InfiniteScroller::origValue, bounded, height);
92 v = (v - self.min) / (self.max - self.min);
93 return std::clamp(v, 0., 1.);
97 static void mouseMoveEvent(T& self, QGraphicsSceneMouseEvent* event)
99 if((event->buttons() & Qt::LeftButton) && self.m_grab)
101 if(
const auto v = mapValue(self, event); v != self.m_value)
104 if(!self.m_noValueChangeOnMove)
112 template <
typename T>
113 static void mouseReleaseEvent(T& self, QGraphicsSceneMouseEvent* event)
117 if(
const auto v = mapValue(self, event); v != self.m_value)
122 InfiniteScroller::stop(self, event);
125 if(self.m_noValueChangeOnMove)
128 self.sliderReleased();
130 if(event->button() == Qt::RightButton)
132 contextMenuEvent(self, event->scenePos());
141 template <
typename T>
149 if(self.m_noValueChangeOnMove)
151 self.sliderReleased();
154 template <
typename T>
155 requires std::is_integral_v<std::decay_t<decltype(std::declval<T>().value())>>
156 static void contextMenuEvent(T& self, QPointF pos)
158 auto build = [&, self_p = &self, pos] {
163 w->setRange(self.min, self.max);
165 w->setValue(self.map(self.m_value));
166 auto obj = self.scene()->addWidget(
167 w, Qt::WindowStaysOnTopHint | Qt::FramelessWindowHint);
171#if defined(__EMSCRIPTEN__)
174 QTimer::singleShot(0, w, [w] { w->setFocus(); });
177 auto con = QObject::connect(
178 w, SignalUtils::QSpinBox_valueChanged_int(), &self,
179 [&self, obj, scene = self.scene()](
double v) {
180 DefaultControlImpl::editWidgetInContextMenu(self, scene, obj, v);
184 w, &SpinboxWithEnter::editingFinished, &self, [obj, con, self_p]()
mutable {
187 if(self_p->m_noValueChangeOnMove)
188 self_p->sliderMoved();
189 self_p->sliderReleased();
190 QObject::disconnect(con);
191 QTimer::singleShot(0, obj, [scene = self_p->scene(), obj] {
192 scene->removeItem(obj);
199#if defined(__EMSCRIPTEN__)
202 QTimer::singleShot(0, &self, build);
206 template <
typename T>
207 requires std::is_floating_point_v<std::decay_t<decltype(std::declval<T>().value())>>
208 static void contextMenuEvent(T& self, QPointF pos)
212 auto build = [&, self_p = &self, pos] {
216 auto w =
new DoubleSpinboxWithEnter;
217 w->setRange(self.min, self.max);
220 w->setValue(self.map(self.m_value));
221 auto obj = self.scene()->addWidget(
222 w, Qt::WindowStaysOnTopHint | Qt::FramelessWindowHint);
226#if defined(__EMSCRIPTEN__)
229 QTimer::singleShot(0, w, [w] { w->setFocus(); });
232 auto con = QObject::connect(
233 w, SignalUtils::QDoubleSpinBox_valueChanged_double(), &self,
234 [&self, obj, scene = self.scene()](
double v) {
235 DefaultControlImpl::editWidgetInContextMenu(self, scene, obj, v);
239 w, &DoubleSpinboxWithEnter::editingFinished, &self,
240 [obj, con, self_p]()
mutable {
243 if(self_p->m_noValueChangeOnMove)
244 self_p->sliderMoved();
245 self_p->sliderReleased();
246 QObject::disconnect(con);
247 QTimer::singleShot(0, obj, [scene = self_p->scene(), obj] {
248 scene->removeItem(obj);
255#if defined(__EMSCRIPTEN__)
258 QTimer::singleShot(0, &self, build);
262 template <
typename T>
263 static void mouseDoubleClickEvent(T& self, QGraphicsSceneMouseEvent* event)
265 self.m_value = self.unmap(self.init);
269 self.sliderReleased();