Skip to content

Commit

Permalink
Merge pull request #12237 from m0dB/waveformmarkset-ordered
Browse files Browse the repository at this point in the history
move ordering to waveformmarkset
  • Loading branch information
Swiftb0y authored Nov 7, 2023
2 parents 1e09aa9 + df7dd68 commit 5454b94
Show file tree
Hide file tree
Showing 8 changed files with 142 additions and 94 deletions.
22 changes: 9 additions & 13 deletions src/waveform/renderers/allshader/waveformrendermark.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ void allshader::WaveformRenderMark::initializeGL() {
m_rgbaShader.init();
m_textureShader.init();

for (const auto& pMark : m_marks) {
for (const auto& pMark : std::as_const(m_marks)) {
generateMarkImage(pMark);
}
generatePlayPosMarkTexture();
Expand Down Expand Up @@ -159,22 +159,14 @@ void allshader::WaveformRenderMark::drawMark(const QRectF& rect, QColor color) {

void allshader::WaveformRenderMark::paintGL() {
const float devicePixelRatio = m_waveformRenderer->getDevicePixelRatio();
QMap<WaveformMarkPointer, int> marksOnScreen;
QList<WaveformWidgetRenderer::WaveformMarkOnScreen> marksOnScreen;

checkCuesUpdated();

glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);

for (const auto& pMark : m_marks) {
if (!pMark->isValid()) {
continue;
}

if (pMark->hasVisible() && !pMark->isVisible()) {
continue;
}

for (const auto& pMark : std::as_const(m_marks)) {
if (!pMark->m_pGraphics || pMark->m_pGraphics->m_obsolete) {
generateMarkImage(pMark);
}
Expand Down Expand Up @@ -229,7 +221,9 @@ void allshader::WaveformRenderMark::paintGL() {
}

if (visible) {
marksOnScreen[pMark] = static_cast<int>(drawOffset);
marksOnScreen.append(
WaveformWidgetRenderer::WaveformMarkOnScreen{
pMark, static_cast<int>(drawOffset)});
}
}
}
Expand Down Expand Up @@ -327,7 +321,7 @@ void allshader::WaveformRenderMark::drawTriangle(QPainter* painter,
}

void allshader::WaveformRenderMark::resizeGL(int, int) {
for (const auto& pMark : m_marks) {
for (const auto& pMark : std::as_const(m_marks)) {
generateMarkImage(pMark);
}
generatePlayPosMarkTexture();
Expand Down Expand Up @@ -386,6 +380,8 @@ void allshader::WaveformRenderMark::checkCuesUpdated() {
generateMarkImage(pMark);
}
}

m_marks.update();
}

void allshader::WaveformRenderMark::generateMarkImage(WaveformMarkPointer pMark) {
Expand Down
40 changes: 40 additions & 0 deletions src/waveform/renderers/waveformmarkset.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -69,3 +69,43 @@ WaveformMarkPointer WaveformMarkSet::getHotCueMark(int hotCue) const {
WaveformMarkPointer WaveformMarkSet::getDefaultMark() const {
return m_pDefaultMark;
}

void WaveformMarkSet::update() {
std::map<WaveformMarkSortKey, WaveformMarkPointer> map;
for (const auto& pMark : std::as_const(m_marks)) {
if (pMark->isValid() && pMark->isVisible()) {
double samplePosition = pMark->getSamplePosition();
if (samplePosition != Cue::kNoPosition) {
// Create a stable key for sorting, because the WaveformMark's samplePosition is a
// ControlObject which can change at any time by other threads. Such a change causes
// another updateCues() call, rebuilding map.
auto key = WaveformMarkSortKey(samplePosition, pMark->getHotCue());
map.emplace(key, pMark);
}
}
}

m_marksToRender.clear();
m_marksToRender.reserve(static_cast<QList<WaveformMarkPointer>::size_type>(map.size()));
std::transform(map.begin(),
map.end(),
std::back_inserter(m_marksToRender),
[](auto const& pair) { return pair.second; });
}

WaveformMarkPointer WaveformMarkSet::findHoveredMark(
QPoint pos, Qt::Orientation orientation) const {
// Non-hotcue marks (intro/outro cues, main cue, loop in/out) are sorted
// before hotcues in m_marksToRender so if there is a hotcue in the same
// location, the hotcue gets rendered on top. When right clicking, the
// the hotcue rendered on top must be assigned to m_pHoveredMark to show
// the CueMenuPopup. To accomplish this, m_marksToRender is iterated in
// reverse and the loop breaks as soon as m_pHoveredMark is set.
for (auto it = m_marksToRender.crbegin(); it != m_marksToRender.crend(); ++it) {
const WaveformMarkPointer& pMark = *it;
if (pMark->contains(pos, orientation)) {
return pMark;
}
}
return nullptr;
}
55 changes: 51 additions & 4 deletions src/waveform/renderers/waveformmarkset.h
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,8 @@
class WaveformWidgetRenderer;

// This class helps share code between the WaveformRenderMark and WOverview
// constructors.
// constructors and allows to iterate over the orders marks that have to be
// rendered.
class WaveformMarkSet {
public:
WaveformMarkSet();
Expand All @@ -19,17 +20,63 @@ class WaveformMarkSet {
const SkinContext& context,
const WaveformSignalColors& signalColors);

inline QList<WaveformMarkPointer>::const_iterator begin() const { return m_marks.begin(); }
inline QList<WaveformMarkPointer>::const_iterator end() const { return m_marks.end(); }
template<typename Receiver, typename Slot>
void connectSamplePositionChanged(Receiver receiver, Slot slot) const {
for (const auto& pMark : std::as_const(m_marks)) {
if (pMark->isValid()) {
pMark->connectSamplePositionChanged(receiver, slot);
}
}
};

template<typename Receiver, typename Slot>
void connectSampleEndPositionChanged(Receiver receiver, Slot slot) const {
for (const auto& pMark : std::as_const(m_marks)) {
if (pMark->isValid()) {
pMark->connectSampleEndPositionChanged(receiver, slot);
}
}
};

template<typename Receiver, typename Slot>
void connectVisibleChanged(Receiver receiver, Slot slot) const {
for (const auto& pMark : std::as_const(m_marks)) {
if (pMark->hasVisible()) {
pMark->connectVisibleChanged(receiver, slot);
}
}
}

inline QList<WaveformMarkPointer>::const_iterator begin() const {
return m_marksToRender.begin();
}
inline QList<WaveformMarkPointer>::const_iterator end() const {
return m_marksToRender.end();
}
inline QList<WaveformMarkPointer>::const_iterator cbegin() const {
return m_marksToRender.cbegin();
}
inline QList<WaveformMarkPointer>::const_iterator cend() const {
return m_marksToRender.cend();
}

// hotCue must be valid (>= 0 and < NUM_HOT_CUES)
WaveformMarkPointer getHotCueMark(int hotCue) const;
WaveformMarkPointer getDefaultMark() const;
WaveformMarkPointer findHoveredMark(QPoint point, Qt::Orientation orientation) const;

void update();

private:
void clear() { m_marks.clear(); }
void clear() {
m_marks.clear();
m_marksToRender.clear();
}
WaveformMarkPointer m_pDefaultMark;
QList<WaveformMarkPointer> m_marks;
// List of visible WaveformMarks sorted by the order they appear in the track
QList<WaveformMarkPointer> m_marksToRender;

QMap<int, WaveformMarkPointer> m_hotCueMarks;

DISALLOW_COPY_AND_ASSIGN(WaveformMarkSet);
Expand Down
33 changes: 12 additions & 21 deletions src/waveform/renderers/waveformrendermark.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -40,27 +40,12 @@ void WaveformRenderMark::setup(const QDomNode& node, const SkinContext& context)

void WaveformRenderMark::draw(QPainter* painter, QPaintEvent* /*event*/) {
PainterScope PainterScope(painter);
// Maps mark objects to their positions in the widget.
QMap<WaveformMarkPointer, int> marksOnScreen;
/*
//DEBUG
for (int i = 0; i < m_markPoints.size(); i++) {
if (m_waveformWidget->getTrackSamples())
painter->drawText(40*i,12+12*(i%3),QString::number(m_markPoints[i]->get() / (double)m_waveformWidget->getTrackSamples()));
}
*/
// Associates mark objects with their positions in the widget.
QList<WaveformWidgetRenderer::WaveformMarkOnScreen> marksOnScreen;

painter->setWorldMatrixEnabled(false);

for (const auto& pMark : m_marks) {
if (!pMark->isValid()) {
continue;
}

if (pMark->hasVisible() && !pMark->isVisible()) {
continue;
}

for (const auto& pMark : std::as_const(m_marks)) {
// Generate image on first paint can't be done in setup since we need to
// wait for the render widget to be resized yet.
if (!pMark->m_pGraphics || pMark->m_pGraphics->m_obsolete) {
Expand Down Expand Up @@ -117,7 +102,9 @@ void WaveformRenderMark::draw(QPainter* painter, QPaintEvent* /*event*/) {
}

if (visible) {
marksOnScreen[pMark] = drawOffset;
marksOnScreen.append(
WaveformWidgetRenderer::WaveformMarkOnScreen{
pMark, drawOffset});
}
} else {
const int markHalfHeight =
Expand Down Expand Up @@ -161,7 +148,9 @@ void WaveformRenderMark::draw(QPainter* painter, QPaintEvent* /*event*/) {
}

if (visible) {
marksOnScreen[pMark] = drawOffset;
marksOnScreen.append(
WaveformWidgetRenderer::WaveformMarkOnScreen{
pMark, drawOffset});
}
}
}
Expand All @@ -171,7 +160,7 @@ void WaveformRenderMark::draw(QPainter* painter, QPaintEvent* /*event*/) {

void WaveformRenderMark::onResize() {
// Flag that the mark image has to be updated. New images will be created on next paint.
for (const auto& pMark : m_marks) {
for (const auto& pMark : std::as_const(m_marks)) {
if (pMark->m_pGraphics) {
pMark->m_pGraphics->m_obsolete = true;
}
Expand Down Expand Up @@ -222,6 +211,8 @@ void WaveformRenderMark::slotCuesUpdated() {
generateMarkImage(pMark);
}
}

m_marks.update();
}

void WaveformRenderMark::generateMarkImage(WaveformMarkPointer pMark) {
Expand Down
14 changes: 11 additions & 3 deletions src/waveform/renderers/waveformwidgetrenderer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -413,13 +413,21 @@ ConstWaveformPointer WaveformWidgetRenderer::getWaveform() const {
}

WaveformMarkPointer WaveformWidgetRenderer::getCueMarkAtPoint(QPoint point) const {
for (auto it = m_markPositions.constBegin(); it != m_markPositions.constEnd(); ++it) {
WaveformMarkPointer pMark = it.key();
// The m_markPositions list follows the order of drawing, so we search the
// list in reverse order to find the hovered mark.
//
// TODO It would be preferable to use WaveformMarkSet::findHoveredMark here,
// as done by WOverview, but that requires a) making WaveformMarkSet m_marks
// a member of this class and b) decoupling the calculation of the
// drawoffset from the drawing and c) storing it in WaveformMark.

for (auto it = m_markPositions.crbegin(); it != m_markPositions.crend(); ++it) {
const WaveformMarkPointer& pMark = it->m_pMark;
VERIFY_OR_DEBUG_ASSERT(pMark) {
continue;
}

int markImagePositionInWidgetSpace = it.value();
int markImagePositionInWidgetSpace = it->m_offsetOnScreen;
QPoint pointInImageSpace;
if (getOrientation() == Qt::Horizontal) {
pointInImageSpace = QPoint(point.x() - markImagePositionInWidgetSpace, point.y());
Expand Down
9 changes: 7 additions & 2 deletions src/waveform/renderers/waveformwidgetrenderer.h
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,11 @@ class WaveformWidgetRenderer {
static const double s_waveformDefaultZoom;
static const double s_defaultPlayMarkerPosition;

struct WaveformMarkOnScreen {
WaveformMarkPointer m_pMark;
int m_offsetOnScreen;
};

public:
explicit WaveformWidgetRenderer(const QString& group);
virtual ~WaveformWidgetRenderer();
Expand Down Expand Up @@ -149,7 +154,7 @@ class WaveformWidgetRenderer {
}

void setTrack(TrackPointer track);
void setMarkPositions(const QMap<WaveformMarkPointer, int>& markPositions) {
void setMarkPositions(const QList<WaveformMarkOnScreen>& markPositions) {
m_markPositions = markPositions;
}

Expand Down Expand Up @@ -217,7 +222,7 @@ class WaveformWidgetRenderer {
private:
DISALLOW_COPY_AND_ASSIGN(WaveformWidgetRenderer);
friend class WaveformWidgetFactory;
QMap<WaveformMarkPointer, int> m_markPositions;
QList<WaveformMarkOnScreen> m_markPositions;
// draw play position indicator triangles
void drawPlayPosmarker(QPainter* painter);
void drawTriangle(QPainter* painter,
Expand Down
Loading

0 comments on commit 5454b94

Please sign in to comment.