-
-
Notifications
You must be signed in to change notification settings - Fork 1.3k
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
avoid overlapping marks #12273
avoid overlapping marks #12273
Conversation
What about |
The ideas in this PR are pretty good (I like the priority concept) but I feel like just stacking marks with the exact same sampleposition on top of each other is not the best solution. For example, cues set carelessly and without quantize might have slightly different samplepositions, but are still essentially on top of each other. Also, the labels of different cues still fight with each other as well (as seen in your screenshot). If instead comparing cues by sampleposition, we just avoided the collision of the boxes in general, the special cases where markers are on top of each other or very near would be solved automatically. How feasible do you think this is? |
Certainly feasible, definitely more complicated to implement, and potentially resulting in undesired situations with markers jumping up and down when changing the zoom level. In any case, I would only consider doing that after a more thorough refactoring of the related code. With the current code, these are minor changes that bring a very noticable improvement. My proposal is to start here and implement further improvements like you are suggestion down the road. |
Sounds good as well, let me know when this PR is ready. |
I agree this is a good first start, and that in the longer term a generalized box-avoidance solution is preferable. I think it's ok if things move around as the zoom changes, that's like a web page reflowing when the size changes. |
Yes, I am using this, and this works for all markers excepts for the loop markers. EDIT: No, I am not, sorry for the confusion. |
…aveform renderers. reduced code duplications, fix setting the initial size of the waveform renderers
7e2568e
to
0277e3c
Compare
Works like a charm! I have reduced code duplication between the legacy and allshader waveformmarkrenderer.cpp (with a shared intermediate baseclass) and done cleanup. Everything is working as expected, so this is now ready for review. |
When I build this I get
I reconfigured to make sure precompiled headers are off, though same reasult. |
On Windows it builds - and works as intended! |
#include <QOpenGLTexture> | ||
#include <QPainterPath> | ||
|
||
#include "track/track.h" | ||
#include "util/color/color.h" | ||
#include "util/colorcomponents.h" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It builds when I restore this include
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is on Ubuntu 20.04, and it seems this and #12303 slip through because we don't have a 20.04 runner anymore even though we support it?
@ronso0 I added the missing include and I slightly improved the hovering detection. It is still not perfect, but certainly better, and good enough for now. I think that with these last changes this PR is ready for merge. |
It think even if this is not the best solution, it's an improvement and does not go down a road that would be hard to reverse. I am in favor of merging this for 2.4 |
Okay, great! I'll test this soonish, but I'll the code review to others ;) I'm still no good at fully understanding / judging class inheritance, ownership, basic oop rules .. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thank you for the PR.
Here some code and comment improvement comments.
const WaveformSignalColors& signalColors, | ||
int hotCue) | ||
: m_linePosition{}, m_breadth{}, m_iHotCue{hotCue} { | ||
: m_linePosition{}, m_breadth{}, m_level{}, m_iPriority(priority), m_iHotCue(hotCue) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can you stack these. A table like list improves readability IMHO. I though clang-format will do it for us.
We should investigate why it is no longer the case.
} | ||
bool lineHovered = m_linePosition >= point.x() - lineHoverPadding && | ||
return m_linePosition >= point.x() - lineHoverPadding && |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
lineHoverPadding and the comment can be moved to the anonymous namespace.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
done
return m_label.area().contains(point) || lineHovered; | ||
bool WaveformMark::contains(QPoint point, Qt::Orientation orientation) const { | ||
if (orientation == Qt::Vertical) { | ||
point = QPoint(point.y(), static_cast<int>(m_breadth) - point.x()); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can you add a comment here? Maybe we can also rename or document m_breath. Can it be width?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We don't have width here, but I will add a comment explaining that in the case of Qt::Vertical orientation, breadth is width.
@@ -292,7 +306,7 @@ QImage WaveformMark::generateImage(float breadth, float devicePixelRatio) { | |||
const bool useIcon = m_iconPath != ""; | |||
|
|||
// Determine drawing geometries | |||
const MarkerGeometry markerGeometry(label, useIcon, m_align, breadth); | |||
const MarkerGeometry markerGeometry(label, useIcon, m_align, m_breadth, m_level); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think we can use here { } initialization for better readability.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
done
@@ -109,7 +148,8 @@ class WaveformMark { | |||
QString m_iconPath; | |||
|
|||
float m_linePosition; | |||
int m_breadth; | |||
float m_breadth; | |||
int m_level; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
m_level can make use of a comment.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
done
@@ -19,16 +19,16 @@ class WaveformMark { | |||
public: | |||
class Graphics { | |||
public: | |||
Graphics() | |||
: m_obsolete{false} { | |||
Graphics() { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think the ctor can be removed now.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
done
generateMarkImage(pMark); | ||
} | ||
// Will create textures so requires OpenGL context | ||
updateMarkImages(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is m_obsolete still in use?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
yes, to indicate that the image has to be regenerated. I leave a comment.
} | ||
|
||
void WaveformRenderMarkBase::updateMarkImages() { | ||
for (auto& pMark : m_marks) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
for (auto& pMark : m_marks) { | |
for (const auto& pMark : qAsConst(m_marks)) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
done
double prevSamplePosition = Cue::kNoPosition; | ||
std::map<Qt::Alignment, int> levels; | ||
for (auto& pMark : m_marksToRender) { | ||
if (pMark->getSamplePosition() != prevSamplePosition) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
do we need to consider a certain distance here?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Which values of https://doc.qt.io/qt-6/qt.html#AlignmentFlag-enumf are considered?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
do we need to consider a certain distance here?
Ideally yes, but that goes beyond this PR. This deals only with marks set at quantised positions, which IMO covers the primary use case.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Which values of https://doc.qt.io/qt-6/qt.html#AlignmentFlag-enumf are considered?
I'll leave a comment
#include "waveform/renderers/waveformwidgetrenderer.h" | ||
|
||
WaveformRenderMarkBase::WaveformRenderMarkBase( | ||
WaveformWidgetRenderer* waveformWidgetRenderer, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
the p prefix is missing.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
done
Indeed its much better now! Thanks! |
Sorry for the delay, @daschuer , this fell of my radar (I was convinced it was already merged). I addressed all your comments. |
Ok, let's merge this! Thank you! |
Hm, after playing with this I've encountered a number of cases where it makes the waveform harder to read. There are a lot of tracks where the main cue overlaps with the intro marker and thus obscures the waveform (at least when viewed at a small-ish height): Any ideas? Perhaps the calculation could somehow incorporate the amplitude of the waveform to "avoid" stacking markers if there isn't enough space? |
Yeah, that is really very small, I never do that, as my eyesight is quite bad 😅 Do you really mean "the amplitude of the waveform", or do you mean the height of the waveform viewer? I think the first is a bad idea, the second might work and should be easy to implement. Like limiting the total space occupied by the markers from either top or bottom to a third of the total height. In your example that would mean (almost) fully overlapping I guess. Alternatively we could scale the markers to a smaller size. I guess that if you are okay with staring at small waveforms you are also okay with staring at small markers ;-) |
Why not scale the markers below a certain height limit - e.g. no marker must be higher than 20% of the waveform viewer height. BTW: The feature itself helped me removing saved loop from Serato, where I wasn't ware of before, because hotcues/loops >8 have no pads. |
On laptops where screen real estate is limited, it's quite useful to have small waveforms IMO, especially when browsing the library and even more when playing with 4 decks.
I was thinking of the actual waveform, though admittedly that might be too complex to implement/might have surprising semantics e.g. when adjusting gain etc.
I like that idea!
Yeah, I guess that would be hard to avoid, though I think it would be fine if they overlap like in previous versions in that case. Ideally perhaps even in a deterministic order (i.e. always rendering the CUE marker above the intro/outro markers)
Interesting idea, though I'd probably still consider overlapping markers the best tradeoff for readability. |
I feel like scaling the markers non-uniformly could potentially look a bit off. But perhaps we could just make the marker scale configurable? In any case, we should make sure that the default works well. |
How about this? (and let's move the conversation there) #12501 |
draw overlapping marks at increasing/decreasing y position in the waveform viewer