1 #include <QtDebug>
2 
3 #include "skin/legacy/skincontext.h"
4 #include "waveform/renderers/waveformsignalcolors.h"
5 #include "widget/wskincolor.h"
6 
7 #include "waveformmark.h"
8 
9 namespace {
decodeAlignmentFlags(const QString & alignString,Qt::Alignment defaultFlags)10 Qt::Alignment decodeAlignmentFlags(const QString& alignString, Qt::Alignment defaultFlags) {
11     QStringList stringFlags = alignString.toLower()
12                                       .split('|',
13 #if QT_VERSION >= QT_VERSION_CHECK(5, 14, 0)
14                                               Qt::SkipEmptyParts);
15 #else
16                                               QString::SkipEmptyParts);
17 #endif
18 
19     Qt::Alignment hflags;
20     Qt::Alignment vflags;
21 
22     for (const auto& stringFlag : stringFlags) {
23         if (stringFlag == "center") {
24             hflags |= Qt::AlignHCenter;
25             vflags |= Qt::AlignVCenter;
26         } else if (stringFlag == "left") {
27             hflags |= Qt::AlignLeft;
28         } else if (stringFlag == "hcenter") {
29             hflags |= Qt::AlignHCenter;
30         } else if (stringFlag == "right") {
31             hflags |= Qt::AlignRight;
32         } else if (stringFlag == "top") {
33             vflags |= Qt::AlignTop;
34         } else if (stringFlag == "vcenter") {
35             vflags |= Qt::AlignVCenter;
36         } else if (stringFlag == "bottom") {
37             vflags |= Qt::AlignBottom;
38         }
39     }
40 
41     if (hflags != Qt::AlignLeft && hflags != Qt::AlignHCenter && hflags != Qt::AlignRight) {
42         hflags = defaultFlags & Qt::AlignHorizontal_Mask;
43     }
44 
45     if (vflags != Qt::AlignTop && vflags != Qt::AlignVCenter && vflags != Qt::AlignBottom) {
46         vflags = defaultFlags & Qt::AlignVertical_Mask;
47     }
48 
49     return hflags | vflags;
50 }
51 } // anonymous namespace
52 
WaveformMark(const QString & group,const QDomNode & node,const SkinContext & context,const WaveformSignalColors & signalColors,int hotCue)53 WaveformMark::WaveformMark(const QString& group,
54                            const QDomNode& node,
55                            const SkinContext& context,
56                            const WaveformSignalColors& signalColors,
57                            int hotCue)
58         : m_iHotCue(hotCue) {
59     QString control;
60     if (hotCue != Cue::kNoHotCue) {
61         control = "hotcue_" + QString::number(hotCue + 1) + "_position";
62     } else {
63         control = context.selectString(node, "Control");
64     }
65     if (!control.isEmpty()) {
66         m_pPointCos = std::make_unique<ControlProxy>(group, control);
67     }
68 
69     QString visibilityControl = context.selectString(node, "VisibilityControl");
70     if (!visibilityControl.isEmpty()) {
71         ConfigKey key = ConfigKey::parseCommaSeparated(visibilityControl);
72         m_pVisibleCos = std::make_unique<ControlProxy>(key);
73     }
74 
75     QColor color(context.selectString(node, "Color"));
76     if (!color.isValid()) {
77         // As a fallback, grab the color from the parent's AxesColor
78         color = signalColors.getAxesColor();
79         qDebug() << "Didn't get mark <Color>, using parent's <AxesColor>:" << color;
80     } else {
81         color = WSkinColor::getCorrectColor(color);
82     }
83     int dimBrightThreshold = signalColors.getDimBrightThreshold();
84     setBaseColor(color, dimBrightThreshold);
85 
86     m_textColor = context.selectString(node, "TextColor");
87     if (!m_textColor.isValid()) {
88         // Read the text color, otherwise use the parent's BgColor.
89         m_textColor = signalColors.getBgColor();
90         qDebug() << "Didn't get mark <TextColor>, using parent's <BgColor>:" << m_textColor;
91     }
92 
93     QString markAlign = context.selectString(node, "Align");
94     m_align = decodeAlignmentFlags(markAlign, Qt::AlignBottom | Qt::AlignHCenter);
95 
96     // Hotcue text is set by the cue's label in the database, not by the skin.
97     if (hotCue == Cue::kNoHotCue) {
98         m_text = context.selectString(node, "Text");
99     }
100 
101     m_pixmapPath = context.selectString(node, "Pixmap");
102     if (!m_pixmapPath.isEmpty()) {
103         m_pixmapPath = context.makeSkinPath(m_pixmapPath);
104     }
105 }
106 
setBaseColor(QColor baseColor,int dimBrightThreshold)107 void WaveformMark::setBaseColor(QColor baseColor, int dimBrightThreshold) {
108     m_image = QImage();
109     m_fillColor = baseColor;
110     m_borderColor = Color::chooseContrastColor(baseColor, dimBrightThreshold);
111     m_labelColor = Color::chooseColorByBrightness(baseColor,
112             QColor(255, 255, 255, 255),
113             QColor(0, 0, 0, 255),
114             dimBrightThreshold);
115 };
116 
contains(QPoint point,Qt::Orientation orientation) const117 bool WaveformMark::contains(QPoint point, Qt::Orientation orientation) const {
118     // Without some padding, the user would only have a single pixel width that
119     // would count as hovering over the WaveformMark.
120     float lineHoverPadding = 5.0;
121     int position;
122     if (orientation == Qt::Horizontal) {
123         position = point.x();
124     } else {
125         position = point.y();
126     }
127     bool lineHovered = m_linePosition >= position - lineHoverPadding &&
128             m_linePosition <= position + lineHoverPadding;
129 
130     return m_label.area().contains(point) || lineHovered;
131 }
132