Chris@923
|
1 /* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */
|
Chris@923
|
2
|
Chris@923
|
3 /*
|
Chris@923
|
4 Sonic Visualiser
|
Chris@923
|
5 An audio file viewer and annotation editor.
|
Chris@923
|
6 Centre for Digital Music, Queen Mary, University of London.
|
Chris@923
|
7
|
Chris@923
|
8 This program is free software; you can redistribute it and/or
|
Chris@923
|
9 modify it under the terms of the GNU General Public License as
|
Chris@923
|
10 published by the Free Software Foundation; either version 2 of the
|
Chris@923
|
11 License, or (at your option) any later version. See the file
|
Chris@923
|
12 COPYING included with this distribution for more information.
|
Chris@923
|
13 */
|
Chris@923
|
14
|
Chris@923
|
15 #include "LevelPanWidget.h"
|
Chris@923
|
16
|
Chris@923
|
17 #include <QPainter>
|
Chris@923
|
18 #include <QMouseEvent>
|
Chris@923
|
19 #include <QWheelEvent>
|
Chris@923
|
20
|
Chris@923
|
21 #include "layer/ColourMapper.h"
|
Chris@925
|
22 #include "base/AudioLevel.h"
|
Chris@923
|
23
|
Chris@1176
|
24 #include "WidgetScale.h"
|
Chris@1176
|
25
|
Chris@923
|
26 #include <iostream>
|
Chris@926
|
27 #include <cmath>
|
Chris@940
|
28 #include <cassert>
|
Chris@923
|
29
|
Chris@923
|
30 using std::cerr;
|
Chris@923
|
31 using std::endl;
|
Chris@923
|
32
|
Chris@940
|
33 static const int maxLevel = 4; // min is 0, may be mute or not depending on m_includeMute
|
Chris@923
|
34 static const int maxPan = 2; // range is -maxPan to maxPan
|
Chris@923
|
35
|
Chris@923
|
36 LevelPanWidget::LevelPanWidget(QWidget *parent) :
|
Chris@923
|
37 QWidget(parent),
|
Chris@923
|
38 m_level(maxLevel),
|
Chris@923
|
39 m_pan(0),
|
Chris@1177
|
40 m_monitorLeft(-1),
|
Chris@1177
|
41 m_monitorRight(-1),
|
Chris@940
|
42 m_editable(true),
|
Chris@1249
|
43 m_editing(false),
|
Chris@940
|
44 m_includeMute(true)
|
Chris@923
|
45 {
|
Chris@1191
|
46 setToolTip(tr("Drag vertically to adjust level, horizontally to adjust pan"));
|
Chris@1201
|
47 setLevel(1.0);
|
Chris@1201
|
48 setPan(0.0);
|
Chris@923
|
49 }
|
Chris@923
|
50
|
Chris@923
|
51 LevelPanWidget::~LevelPanWidget()
|
Chris@923
|
52 {
|
Chris@923
|
53 }
|
Chris@923
|
54
|
Chris@1249
|
55 void
|
Chris@1249
|
56 LevelPanWidget::setToDefault()
|
Chris@1249
|
57 {
|
Chris@1249
|
58 setLevel(1.0);
|
Chris@1249
|
59 setPan(0.0);
|
Chris@1250
|
60 emitLevelChanged();
|
Chris@1250
|
61 emitPanChanged();
|
Chris@1249
|
62 }
|
Chris@1249
|
63
|
Chris@929
|
64 QSize
|
Chris@929
|
65 LevelPanWidget::sizeHint() const
|
Chris@929
|
66 {
|
Chris@1176
|
67 return WidgetScale::scaleQSize(QSize(40, 40));
|
Chris@929
|
68 }
|
Chris@929
|
69
|
Chris@940
|
70 static int
|
Chris@940
|
71 db_to_level(double db)
|
Chris@940
|
72 {
|
Chris@940
|
73 // Only if !m_includeMute, otherwise AudioLevel is used.
|
Chris@940
|
74 // Levels are: +6 0 -6 -12 -20
|
Chris@940
|
75 assert(maxLevel == 4);
|
Chris@940
|
76 if (db > 3.) return 4;
|
Chris@940
|
77 else if (db > -3.) return 3;
|
Chris@940
|
78 else if (db > -9.) return 2;
|
Chris@940
|
79 else if (db > -16.) return 1;
|
Chris@940
|
80 else return 0;
|
Chris@940
|
81 }
|
Chris@940
|
82
|
Chris@940
|
83 static double
|
Chris@940
|
84 level_to_db(int level)
|
Chris@940
|
85 {
|
Chris@940
|
86 // Only if !m_includeMute, otherwise AudioLevel is used.
|
Chris@940
|
87 // Levels are: +6 0 -6 -12 -20
|
Chris@940
|
88 assert(maxLevel == 4);
|
Chris@940
|
89 if (level >= 4) return 6.;
|
Chris@940
|
90 else if (level == 3) return 0.;
|
Chris@940
|
91 else if (level == 2) return -6.;
|
Chris@940
|
92 else if (level == 1) return -12.;
|
Chris@940
|
93 else return -20.;
|
Chris@940
|
94 }
|
Chris@940
|
95
|
Chris@1177
|
96 int
|
Chris@1177
|
97 LevelPanWidget::audioLevelToLevel(float audioLevel, bool withMute)
|
Chris@1177
|
98 {
|
Chris@1177
|
99 int level;
|
Chris@1177
|
100 if (withMute) {
|
Chris@1177
|
101 level = AudioLevel::multiplier_to_fader
|
Chris@1177
|
102 (audioLevel, maxLevel, AudioLevel::ShortFader);
|
Chris@1177
|
103 } else {
|
Chris@1177
|
104 level = db_to_level(AudioLevel::multiplier_to_dB(audioLevel));
|
Chris@1177
|
105 }
|
Chris@1177
|
106 if (level < 0) level = 0;
|
Chris@1177
|
107 if (level > maxLevel) level = maxLevel;
|
Chris@1177
|
108 return level;
|
Chris@1177
|
109 }
|
Chris@1177
|
110
|
Chris@1177
|
111 float
|
Chris@1177
|
112 LevelPanWidget::levelToAudioLevel(int level, bool withMute)
|
Chris@1177
|
113 {
|
Chris@1177
|
114 if (withMute) {
|
Chris@1177
|
115 return float(AudioLevel::fader_to_multiplier
|
Chris@1177
|
116 (level, maxLevel, AudioLevel::ShortFader));
|
Chris@1177
|
117 } else {
|
Chris@1177
|
118 return float(AudioLevel::dB_to_multiplier(level_to_db(level)));
|
Chris@1177
|
119 }
|
Chris@1177
|
120 }
|
Chris@1177
|
121
|
Chris@923
|
122 void
|
Chris@925
|
123 LevelPanWidget::setLevel(float flevel)
|
Chris@923
|
124 {
|
Chris@1177
|
125 int level = audioLevelToLevel(flevel, m_includeMute);
|
Chris@925
|
126 if (level != m_level) {
|
Chris@1266
|
127 m_level = level;
|
Chris@1266
|
128 float convertsTo = getLevel();
|
Chris@1266
|
129 if (fabsf(convertsTo - flevel) > 1e-5) {
|
Chris@1266
|
130 emitLevelChanged();
|
Chris@1266
|
131 }
|
Chris@1266
|
132 update();
|
Chris@925
|
133 }
|
Chris@923
|
134 }
|
Chris@923
|
135
|
Chris@940
|
136 float
|
Chris@940
|
137 LevelPanWidget::getLevel() const
|
Chris@940
|
138 {
|
Chris@1201
|
139 float flevel = levelToAudioLevel(m_level, m_includeMute);
|
Chris@1201
|
140 return flevel;
|
Chris@1177
|
141 }
|
Chris@1177
|
142
|
Chris@1177
|
143 int
|
Chris@1177
|
144 LevelPanWidget::audioPanToPan(float audioPan)
|
Chris@1177
|
145 {
|
Chris@1177
|
146 int pan = int(round(audioPan * maxPan));
|
Chris@1177
|
147 if (pan < -maxPan) pan = -maxPan;
|
Chris@1177
|
148 if (pan > maxPan) pan = maxPan;
|
Chris@1177
|
149 return pan;
|
Chris@1177
|
150 }
|
Chris@1177
|
151
|
Chris@1177
|
152 float
|
Chris@1177
|
153 LevelPanWidget::panToAudioPan(int pan)
|
Chris@1177
|
154 {
|
Chris@1177
|
155 return float(pan) / float(maxPan);
|
Chris@1177
|
156 }
|
Chris@1177
|
157
|
Chris@1177
|
158 void
|
Chris@1177
|
159 LevelPanWidget::setPan(float fpan)
|
Chris@1177
|
160 {
|
Chris@1177
|
161 int pan = audioPanToPan(fpan);
|
Chris@1177
|
162 if (pan != m_pan) {
|
Chris@1177
|
163 m_pan = pan;
|
Chris@1177
|
164 update();
|
Chris@940
|
165 }
|
Chris@940
|
166 }
|
Chris@940
|
167
|
Chris@1177
|
168 float
|
Chris@1177
|
169 LevelPanWidget::getPan() const
|
Chris@1177
|
170 {
|
Chris@1177
|
171 return panToAudioPan(m_pan);
|
Chris@1177
|
172 }
|
Chris@1177
|
173
|
Chris@923
|
174 void
|
Chris@1177
|
175 LevelPanWidget::setMonitoringLevels(float left, float right)
|
Chris@923
|
176 {
|
Chris@1177
|
177 m_monitorLeft = left;
|
Chris@1177
|
178 m_monitorRight = right;
|
Chris@923
|
179 update();
|
Chris@923
|
180 }
|
Chris@923
|
181
|
Chris@940
|
182 bool
|
Chris@940
|
183 LevelPanWidget::isEditable() const
|
Chris@940
|
184 {
|
Chris@940
|
185 return m_editable;
|
Chris@940
|
186 }
|
Chris@940
|
187
|
Chris@940
|
188 bool
|
Chris@940
|
189 LevelPanWidget::includesMute() const
|
Chris@940
|
190 {
|
Chris@940
|
191 return m_includeMute;
|
Chris@940
|
192 }
|
Chris@940
|
193
|
Chris@923
|
194 void
|
Chris@923
|
195 LevelPanWidget::setEditable(bool editable)
|
Chris@923
|
196 {
|
Chris@923
|
197 m_editable = editable;
|
Chris@923
|
198 update();
|
Chris@923
|
199 }
|
Chris@923
|
200
|
Chris@940
|
201 void
|
Chris@940
|
202 LevelPanWidget::setIncludeMute(bool include)
|
Chris@923
|
203 {
|
Chris@940
|
204 m_includeMute = include;
|
Chris@940
|
205 emitLevelChanged();
|
Chris@940
|
206 update();
|
Chris@923
|
207 }
|
Chris@923
|
208
|
Chris@923
|
209 void
|
Chris@923
|
210 LevelPanWidget::emitLevelChanged()
|
Chris@923
|
211 {
|
Chris@923
|
212 emit levelChanged(getLevel());
|
Chris@923
|
213 }
|
Chris@923
|
214
|
Chris@923
|
215 void
|
Chris@923
|
216 LevelPanWidget::emitPanChanged()
|
Chris@923
|
217 {
|
Chris@923
|
218 emit panChanged(getPan());
|
Chris@923
|
219 }
|
Chris@923
|
220
|
Chris@923
|
221 void
|
Chris@923
|
222 LevelPanWidget::mousePressEvent(QMouseEvent *e)
|
Chris@923
|
223 {
|
Chris@1249
|
224 if (e->button() == Qt::MidButton ||
|
Chris@1249
|
225 ((e->button() == Qt::LeftButton) &&
|
Chris@1249
|
226 (e->modifiers() & Qt::ControlModifier))) {
|
Chris@1249
|
227 setToDefault();
|
Chris@1249
|
228 } else if (e->button() == Qt::LeftButton) {
|
Chris@1249
|
229 m_editing = true;
|
Chris@1249
|
230 mouseMoveEvent(e);
|
Chris@1249
|
231 }
|
Chris@1249
|
232 }
|
Chris@1249
|
233
|
Chris@1249
|
234 void
|
Chris@1249
|
235 LevelPanWidget::mouseReleaseEvent(QMouseEvent *e)
|
Chris@1249
|
236 {
|
Chris@923
|
237 mouseMoveEvent(e);
|
Chris@1249
|
238 m_editing = false;
|
Chris@923
|
239 }
|
Chris@923
|
240
|
Chris@923
|
241 void
|
Chris@923
|
242 LevelPanWidget::mouseMoveEvent(QMouseEvent *e)
|
Chris@923
|
243 {
|
Chris@923
|
244 if (!m_editable) return;
|
Chris@1249
|
245 if (!m_editing) return;
|
Chris@923
|
246
|
Chris@923
|
247 int level, pan;
|
Chris@929
|
248 toCell(rect(), e->pos(), level, pan);
|
Chris@923
|
249 if (level == m_level && pan == m_pan) {
|
Chris@1266
|
250 return;
|
Chris@923
|
251 }
|
Chris@923
|
252 if (level != m_level) {
|
Chris@1266
|
253 m_level = level;
|
Chris@1266
|
254 emitLevelChanged();
|
Chris@923
|
255 }
|
Chris@923
|
256 if (pan != m_pan) {
|
Chris@1266
|
257 m_pan = pan;
|
Chris@1266
|
258 emitPanChanged();
|
Chris@923
|
259 }
|
Chris@923
|
260 update();
|
Chris@923
|
261 }
|
Chris@923
|
262
|
Chris@923
|
263 void
|
Chris@923
|
264 LevelPanWidget::wheelEvent(QWheelEvent *e)
|
Chris@923
|
265 {
|
Chris@923
|
266 if (e->modifiers() & Qt::ControlModifier) {
|
Chris@1266
|
267 if (e->delta() > 0) {
|
Chris@1266
|
268 if (m_pan < maxPan) {
|
Chris@1266
|
269 ++m_pan;
|
Chris@1266
|
270 emitPanChanged();
|
Chris@1266
|
271 update();
|
Chris@1266
|
272 }
|
Chris@1266
|
273 } else {
|
Chris@1266
|
274 if (m_pan > -maxPan) {
|
Chris@1266
|
275 --m_pan;
|
Chris@1266
|
276 emitPanChanged();
|
Chris@1266
|
277 update();
|
Chris@1266
|
278 }
|
Chris@1266
|
279 }
|
Chris@923
|
280 } else {
|
Chris@1266
|
281 if (e->delta() > 0) {
|
Chris@1266
|
282 if (m_level < maxLevel) {
|
Chris@1266
|
283 ++m_level;
|
Chris@1266
|
284 emitLevelChanged();
|
Chris@1266
|
285 update();
|
Chris@1266
|
286 }
|
Chris@1266
|
287 } else {
|
Chris@1266
|
288 if (m_level > 0) {
|
Chris@1266
|
289 --m_level;
|
Chris@1266
|
290 emitLevelChanged();
|
Chris@1266
|
291 update();
|
Chris@1266
|
292 }
|
Chris@1266
|
293 }
|
Chris@923
|
294 }
|
Chris@923
|
295 }
|
Chris@923
|
296
|
Chris@923
|
297 void
|
Chris@929
|
298 LevelPanWidget::toCell(QRectF rect, QPointF loc, int &level, int &pan) const
|
Chris@923
|
299 {
|
Chris@929
|
300 double w = rect.width(), h = rect.height();
|
Chris@929
|
301
|
Chris@923
|
302 int npan = maxPan * 2 + 1;
|
Chris@924
|
303 int nlevel = maxLevel + 1;
|
Chris@929
|
304
|
Chris@924
|
305 double wcell = w / npan, hcell = h / nlevel;
|
Chris@929
|
306
|
Chris@932
|
307 level = int((h - (loc.y() - rect.y())) / hcell);
|
Chris@924
|
308 if (level < 0) level = 0;
|
Chris@923
|
309 if (level > maxLevel) level = maxLevel;
|
Chris@929
|
310
|
Chris@932
|
311 pan = int((loc.x() - rect.x()) / wcell) - maxPan;
|
Chris@923
|
312 if (pan < -maxPan) pan = -maxPan;
|
Chris@923
|
313 if (pan > maxPan) pan = maxPan;
|
Chris@923
|
314 }
|
Chris@923
|
315
|
Chris@923
|
316 QSizeF
|
Chris@929
|
317 LevelPanWidget::cellSize(QRectF rect) const
|
Chris@923
|
318 {
|
Chris@929
|
319 double w = rect.width(), h = rect.height();
|
Chris@923
|
320 int npan = maxPan * 2 + 1;
|
Chris@924
|
321 int nlevel = maxLevel + 1;
|
Chris@924
|
322 double wcell = w / npan, hcell = h / nlevel;
|
Chris@923
|
323 return QSizeF(wcell, hcell);
|
Chris@923
|
324 }
|
Chris@923
|
325
|
Chris@923
|
326 QPointF
|
Chris@929
|
327 LevelPanWidget::cellCentre(QRectF rect, int level, int pan) const
|
Chris@923
|
328 {
|
Chris@929
|
329 QSizeF cs = cellSize(rect);
|
Chris@932
|
330 return QPointF(rect.x() + cs.width() * (pan + maxPan) + cs.width() / 2.,
|
Chris@1266
|
331 rect.y() + rect.height() - cs.height() * (level + 1) + cs.height() / 2.);
|
Chris@923
|
332 }
|
Chris@923
|
333
|
Chris@923
|
334 QSizeF
|
Chris@929
|
335 LevelPanWidget::cellLightSize(QRectF rect) const
|
Chris@923
|
336 {
|
Chris@923
|
337 double extent = 3. / 4.;
|
Chris@929
|
338 QSizeF cs = cellSize(rect);
|
Chris@923
|
339 double m = std::min(cs.width(), cs.height());
|
Chris@923
|
340 return QSizeF(m * extent, m * extent);
|
Chris@923
|
341 }
|
Chris@923
|
342
|
Chris@923
|
343 QRectF
|
Chris@929
|
344 LevelPanWidget::cellLightRect(QRectF rect, int level, int pan) const
|
Chris@923
|
345 {
|
Chris@929
|
346 QSizeF cls = cellLightSize(rect);
|
Chris@929
|
347 QPointF cc = cellCentre(rect, level, pan);
|
Chris@923
|
348 return QRectF(cc.x() - cls.width() / 2.,
|
Chris@1266
|
349 cc.y() - cls.height() / 2.,
|
Chris@1266
|
350 cls.width(),
|
Chris@1266
|
351 cls.height());
|
Chris@923
|
352 }
|
Chris@923
|
353
|
Chris@923
|
354 double
|
Chris@929
|
355 LevelPanWidget::thinLineWidth(QRectF rect) const
|
Chris@923
|
356 {
|
Chris@929
|
357 double tw = ceil(rect.width() / (maxPan * 2. * 10.));
|
Chris@929
|
358 double th = ceil(rect.height() / (maxLevel * 10.));
|
Chris@923
|
359 return std::min(th, tw);
|
Chris@923
|
360 }
|
Chris@923
|
361
|
Chris@941
|
362 static QColor
|
Chris@941
|
363 level_to_colour(int level)
|
Chris@941
|
364 {
|
Chris@941
|
365 assert(maxLevel == 4);
|
Chris@941
|
366 if (level == 0) return Qt::black;
|
Chris@941
|
367 else if (level == 1) return QColor(80, 0, 0);
|
Chris@941
|
368 else if (level == 2) return QColor(160, 0, 0);
|
Chris@941
|
369 else if (level == 3) return QColor(255, 0, 0);
|
Chris@941
|
370 else return QColor(255, 255, 0);
|
Chris@941
|
371 }
|
Chris@941
|
372
|
Chris@923
|
373 void
|
Chris@929
|
374 LevelPanWidget::renderTo(QPaintDevice *dev, QRectF rect, bool asIfEditable) const
|
Chris@923
|
375 {
|
Chris@929
|
376 QPainter paint(dev);
|
Chris@923
|
377
|
Chris@923
|
378 paint.setRenderHint(QPainter::Antialiasing, true);
|
Chris@923
|
379
|
Chris@923
|
380 QPen pen;
|
Chris@923
|
381
|
Chris@929
|
382 double thin = thinLineWidth(rect);
|
Chris@938
|
383
|
Chris@923
|
384 pen.setColor(QColor(127, 127, 127, 127));
|
Chris@929
|
385 pen.setWidthF(cellLightSize(rect).width() + thin);
|
Chris@923
|
386 pen.setCapStyle(Qt::RoundCap);
|
Chris@923
|
387 paint.setPen(pen);
|
Chris@1177
|
388 paint.setBrush(Qt::NoBrush);
|
Chris@923
|
389
|
Chris@923
|
390 for (int pan = -maxPan; pan <= maxPan; ++pan) {
|
Chris@1266
|
391 paint.drawLine(cellCentre(rect, 0, pan), cellCentre(rect, maxLevel, pan));
|
Chris@924
|
392 }
|
Chris@924
|
393
|
Chris@1177
|
394 if (m_monitorLeft > 0.f || m_monitorRight > 0.f) {
|
Chris@1177
|
395 paint.setPen(Qt::NoPen);
|
Chris@1177
|
396 for (int pan = -maxPan; pan <= maxPan; ++pan) {
|
Chris@1177
|
397 float audioPan = panToAudioPan(pan);
|
Chris@1177
|
398 float audioLevel;
|
Chris@1177
|
399 if (audioPan < 0.f) {
|
Chris@1177
|
400 audioLevel = m_monitorLeft + m_monitorRight * (1.f + audioPan);
|
Chris@1177
|
401 } else {
|
Chris@1177
|
402 audioLevel = m_monitorRight + m_monitorLeft * (1.f - audioPan);
|
Chris@1177
|
403 }
|
Chris@1177
|
404 int levelHere = audioLevelToLevel(audioLevel, false);
|
Chris@1177
|
405 for (int level = 0; level <= levelHere; ++level) {
|
Chris@1177
|
406 paint.setBrush(level_to_colour(level));
|
Chris@1177
|
407 QRectF clr = cellLightRect(rect, level, pan);
|
Chris@1177
|
408 paint.drawEllipse(clr);
|
Chris@1177
|
409 }
|
Chris@1177
|
410 }
|
Chris@1177
|
411 paint.setPen(pen);
|
Chris@1177
|
412 paint.setBrush(Qt::NoBrush);
|
Chris@1177
|
413 }
|
Chris@1177
|
414
|
Chris@924
|
415 if (isEnabled()) {
|
Chris@1266
|
416 pen.setColor(Qt::black);
|
Chris@924
|
417 } else {
|
Chris@1266
|
418 pen.setColor(Qt::darkGray);
|
Chris@923
|
419 }
|
Chris@929
|
420
|
Chris@940
|
421 if (!asIfEditable && m_includeMute && m_level == 0) {
|
Chris@929
|
422 pen.setWidthF(thin * 2);
|
Chris@929
|
423 pen.setCapStyle(Qt::RoundCap);
|
Chris@929
|
424 paint.setPen(pen);
|
Chris@930
|
425 paint.drawLine(cellCentre(rect, 0, -maxPan),
|
Chris@930
|
426 cellCentre(rect, maxLevel, maxPan));
|
Chris@930
|
427 paint.drawLine(cellCentre(rect, maxLevel, -maxPan),
|
Chris@930
|
428 cellCentre(rect, 0, maxPan));
|
Chris@929
|
429 return;
|
Chris@929
|
430 }
|
Chris@923
|
431
|
Chris@923
|
432 pen.setWidthF(thin);
|
Chris@923
|
433 pen.setCapStyle(Qt::FlatCap);
|
Chris@923
|
434 paint.setPen(pen);
|
Chris@923
|
435
|
Chris@924
|
436 for (int level = 0; level <= m_level; ++level) {
|
Chris@1266
|
437 if (isEnabled()) {
|
Chris@1266
|
438 paint.setBrush(level_to_colour(level));
|
Chris@1266
|
439 }
|
Chris@1266
|
440 QRectF clr = cellLightRect(rect, level, m_pan);
|
Chris@1266
|
441 if (m_includeMute && m_level == 0) {
|
Chris@1266
|
442 paint.drawLine(clr.topLeft(), clr.bottomRight());
|
Chris@1266
|
443 paint.drawLine(clr.bottomLeft(), clr.topRight());
|
Chris@1266
|
444 } else {
|
Chris@1266
|
445 paint.drawEllipse(clr);
|
Chris@1266
|
446 }
|
Chris@923
|
447 }
|
Chris@923
|
448 }
|
Chris@923
|
449
|
Chris@929
|
450 void
|
Chris@929
|
451 LevelPanWidget::paintEvent(QPaintEvent *)
|
Chris@929
|
452 {
|
Chris@929
|
453 renderTo(this, rect(), m_editable);
|
Chris@929
|
454 }
|
Chris@923
|
455
|
Chris@1180
|
456 void
|
Chris@1180
|
457 LevelPanWidget::enterEvent(QEvent *e)
|
Chris@1180
|
458 {
|
Chris@1180
|
459 QWidget::enterEvent(e);
|
Chris@1180
|
460 emit mouseEntered();
|
Chris@1180
|
461 }
|
Chris@929
|
462
|
Chris@1180
|
463 void
|
Chris@1180
|
464 LevelPanWidget::leaveEvent(QEvent *e)
|
Chris@1180
|
465 {
|
Chris@1180
|
466 QWidget::enterEvent(e);
|
Chris@1180
|
467 emit mouseLeft();
|
Chris@1180
|
468 }
|
Chris@929
|
469
|