• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

ossia / score / 30237868584

27 Jul 2026 04:43AM UTC coverage: 15.388% (+0.09%) from 15.298%
30237868584

Pull #2146

github

web-flow
Merge 648972a7d into d36abedc4
Pull Request #2146: Per-platform relative mouse motion (pointer lock) instead of cursor warping

120 of 181 new or added lines in 7 files covered. (66.3%)

422 existing lines in 6 files now uncovered.

30591 of 198799 relevant lines covered (15.39%)

1072.94 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

0.0
/src/lib/score/graphics/widgets/QGraphicsCombo.cpp
1
#include <score/graphics/InfiniteScroller.hpp>
2
#include <score/graphics/widgets/QGraphicsCombo.hpp>
3
#include <score/model/Skin.hpp>
4
#include <score/tools/Cursor.hpp>
5

6
#include <ossia/detail/math.hpp>
7

8
#include <QApplication>
9
#include <QGraphicsSceneMouseEvent>
10
#include <QPainter>
11
#include <QScreen>
12

13
#include <wobjectimpl.h>
14
W_OBJECT_IMPL(score::QGraphicsCombo);
×
15

16
namespace score
17
{
18
/*
19
struct SCORE_LIB_BASE_EXPORT ComboBoxWithEnter final : public QComboBox
20
{
21
  W_OBJECT(ComboBoxWithEnter)
22

23
public:
24
  ComboBoxWithEnter(QWidget* parent = nullptr) : QComboBox{parent} { }
25

26
  void editingFinished() W_SIGNAL(editingFinished)
27

28
private:
29
  bool eventFilter(QObject* watched, QEvent* event) override
30
  {
31
    if (event->type() == QEvent::FocusOut)
32
    {
33
      editingFinished();
34
    }
35

36
    return false;
37
  }
38

39
  bool event(QEvent* event) override
40
  {
41
    auto res = QComboBox::event(event);
42
    if (event->type() == QEvent::ShortcutOverride)
43
    {
44
      QKeyEvent* keyEvent = static_cast<QKeyEvent*>(event);
45
      switch (keyEvent->key())
46
      {
47
        case Qt::Key_Enter:
48
        case Qt::Key_Return:
49
        case Qt::Key_Escape:
50
          editingFinished();
51
        default:
52
          break;
53
      }
54
    }
55
    return res;
56
  }
57

58
  void focusInEvent(QFocusEvent* event) override
59
  {
60
    QComboBox::focusInEvent(event);
61
  }
62

63
  void focusOutEvent(QFocusEvent* event) override
64
  {
65
    dumpObjectTree();
66
    auto lvs = findChildren<QListView*>();
67

68
    if (!lvs.empty())
69
    {
70
      auto lv = lvs.front();
71
      lv->installEventFilter(this);
72
      QTimer::singleShot(2000, this, [this] {
73
        auto lvs = findChildren<QListView*>();
74
        if(!lvs.empty())
75
        {
76
          auto lv = lvs.front();
77
          if (!lv->hasFocus())
78
          {
79
            editingFinished();
80
          }
81
        }
82
      });
83
    }
84
    else
85
    {
86
      editingFinished();
87
    }
88
    QComboBox::focusOutEvent(event);
89
  }
90
};
91
*/
92

93
struct DefaultComboImpl
94
{
95
  static void mousePressEvent(QGraphicsCombo& self, QGraphicsSceneMouseEvent* event)
×
96
  {
97
    if(event->button() == Qt::LeftButton)
×
98
    {
99
      self.m_grab = true;
×
100
      InfiniteScroller::start(self, double(self.m_value) / (self.array.size() - 1));
×
101
    }
×
102

103
    event->accept();
×
104
  }
×
105

106
  static void mouseMoveEvent(QGraphicsCombo& self, QGraphicsSceneMouseEvent* event)
×
107
  {
108
    if((event->buttons() & Qt::LeftButton) && self.m_grab)
×
109
    {
110
      double v = InfiniteScroller::move(event);
×
111
      int curPos = std::round(v * (self.array.size() - 1));
×
112
      if(curPos != self.m_value)
×
113
      {
114
        self.m_value = std::clamp(curPos, 0, int(self.array.size() - 1));
×
115
        self.sliderMoved();
×
116
        self.update();
×
117
      }
×
118
    }
×
119
    event->accept();
×
120
  }
×
121

122
  static void mouseReleaseEvent(QGraphicsCombo& self, QGraphicsSceneMouseEvent* event)
×
123
  {
124
    if(event->button() == Qt::LeftButton)
×
125
    {
126
      if(self.m_grab)
×
127
      {
128
        double v = InfiniteScroller::move(event);
×
129
        int curPos = std::round(v * (self.array.size() - 1));
×
130
        if(curPos != self.m_value)
×
131
        {
132
          self.m_value = std::clamp(curPos, 0, int(self.array.size() - 1));
×
133
          self.update();
×
134
        }
×
135
        self.m_grab = false;
×
136
      }
×
NEW
137
      InfiniteScroller::stop(self, event);
×
138
      self.sliderReleased();
×
139
    }
×
140
    else if(event->button() == Qt::RightButton)
×
141
    { /*
142
      QTimer::singleShot(0, [&, pos = event->scenePos()] {
143
        auto w = new ComboBoxWithEnter;
144
        w->addItems(self.array);
145
        w->setCurrentIndex(self.m_value);
146

147
        auto obj = self.scene()->addWidget(w, Qt::WindowStaysOnTopHint | Qt::FramelessWindowHint);
148
        obj->setPos(pos);
149

150
        QTimer::singleShot(0, w, [w] { w->setFocus(); });
151

152
        QObject::connect(
153
            w, SignalUtils::QComboBox_currentIndexChanged_int(), &self, [=, &self](int v) {
154
              self.m_value = v;
155
              self.sliderMoved();
156
              self.update();
157
            });
158

159
        QObject::connect(w, &ComboBoxWithEnter::editingFinished, &self, [obj, &self]() mutable {
160
          if (obj != nullptr)
161
          {
162
            self.sliderReleased();
163
            QTimer::singleShot(0, obj, [scene = self.scene(), obj] {
164
              scene->removeItem(obj);
165
              delete obj;
166
            });
167
          }
168
          obj = nullptr;
169
        });
170
      });*/
171
    }
×
172
    event->accept();
×
173
  }
×
174
};
175

176
QGraphicsCombo::QGraphicsCombo(QGraphicsItem* parent)
×
177
    : QGraphicsItem{parent}
×
178
{
×
179
  auto& skin = score::Skin::instance();
×
180
  setCursor(skin.CursorSpin);
×
181
  this->setAcceptedMouseButtons(Qt::LeftButton | Qt::RightButton);
×
182
}
×
183

184
void QGraphicsCombo::init()
×
185
{
186
  prepareGeometryChange();
×
187

188
  auto& skin = score::Skin::instance();
×
189
  QFontMetricsF metrics{skin.Medium10Pt};
×
190
  double maxW = m_rect.width();
×
191

192
  for(auto& value : this->array)
×
193
  {
194
    auto r = metrics.boundingRect(value);
×
195
    maxW = std::max(r.width() + 8., maxW);
×
196
  }
197
  m_rect.setWidth(maxW);
×
198
}
×
199

200
void QGraphicsCombo::setRect(const QRectF& r)
×
201
{
202
  prepareGeometryChange();
×
203
  m_rect = r;
×
204
}
×
205

206
void QGraphicsCombo::setValue(int v)
×
207
{
208
  m_value = ossia::clamp(v, 0, int(array.size() - 1));
×
209
  update();
×
210
}
×
211

212
int QGraphicsCombo::value() const
×
213
{
214
  return m_value;
×
215
}
216

217
void QGraphicsCombo::mousePressEvent(QGraphicsSceneMouseEvent* event)
×
218
{
219
  DefaultComboImpl::mousePressEvent(*this, event);
×
220
  event->accept();
×
221
}
×
222

223
void QGraphicsCombo::mouseMoveEvent(QGraphicsSceneMouseEvent* event)
×
224
{
225
  DefaultComboImpl::mouseMoveEvent(*this, event);
×
226
  event->accept();
×
227
}
×
228

229
void QGraphicsCombo::mouseReleaseEvent(QGraphicsSceneMouseEvent* event)
×
230
{
231
  DefaultComboImpl::mouseReleaseEvent(*this, event);
×
232
  auto& skin = score::Skin::instance();
×
233
  setCursor(skin.CursorSpin);
×
234
  event->accept();
×
235
}
×
236

237
QRectF QGraphicsCombo::boundingRect() const
×
238
{
239
  return m_rect;
×
240
}
241

242
void QGraphicsCombo::paint(
×
243
    QPainter* painter, const QStyleOptionGraphicsItem* option, QWidget* widget)
244
{
245
  auto& skin = score::Skin::instance();
×
246
  painter->setRenderHint(QPainter::Antialiasing, true);
×
247

248
  painter->setPen(skin.NoPen);
×
249
  painter->setBrush(skin.Emphasis2.main.brush);
×
250

251
  // Draw rect
252
  const QRectF brect = boundingRect().adjusted(1, 1, -1, -1);
×
253
  painter->drawRoundedRect(brect, 1, 1);
×
254

255
  // Draw text
256
  painter->setPen(skin.Base4.main.pen2);
×
257
  painter->setRenderHint(QPainter::Antialiasing, false);
×
258
  painter->setFont(skin.Medium10Pt);
×
259
  if(int n = value(); n >= 0 && n < array.size())
×
260
  {
261
    painter->drawText(brect, array[value()], QTextOption(Qt::AlignCenter));
×
262
  }
×
263

264
  painter->drawLine(2, 2, 2, boundingRect().height() - 2);
×
265
}
×
266
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE TRIAL · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc