Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

move ordering to waveformmarkset #12237

Merged
merged 3 commits into from
Nov 7, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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;
Swiftb0y marked this conversation as resolved.
Show resolved Hide resolved

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
Loading