Something went wrong. Try again.
Mixxx DJ software with MCP, Subsonic/Navidrome streaming library support — browse and load tracks from your self-hosted music server mixxx.org
subsonic navidrome streaming audio dj mac linux midi
Something went wrong. Try again.
C++
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262#include "widget/wcolorpicker.h"
#include <QColorDialog>#include <QGridLayout>#include <QPushButton>#include <QStyle>#include <QStyleFactory>
#include "moc_wcolorpicker.cpp"#include "util/parented_ptr.h"
namespace {constexpr int kNumColumnsCandidates[] = {5, 4, 3};} // namespace
// Determine the best number of columns for items in a QGridView.//// Ideally, numItems % numColumn == 0 holds true. Rows that are almost// empty do not look good, so if the we can't find the ideal column count,// we fall back to a column count with the biggest number of elements in// the last row.inline int idealColumnCount(int numItems) { int numColumns = 4; // Default in case kNumColumnsCandidates is empty int numColumnsRemainder = -1; for (const int numColumnsCandidate : kNumColumnsCandidates) { const int remainder = numItems % numColumnsCandidate; if (remainder == 0) { numColumns = numColumnsCandidate; break; } if (remainder > numColumnsRemainder) { numColumnsRemainder = numColumnsCandidate; numColumns = numColumnsCandidate; } }
return numColumns;}
WColorPicker::WColorPicker(Options options, const ColorPalette& palette, QWidget* parent) : QWidget(parent), m_options(options), m_palette(palette), m_pNoColorButton(nullptr), m_pCustomColorButton(nullptr) { QGridLayout* pLayout = new QGridLayout(); pLayout->setContentsMargins(0, 0, 0, 0);
// Unfortunately, not all styles supported by Qt support setting a // background color for QPushButtons (see // https://bugreports.qt.io/browse/QTBUG-11089). For example, when using // the gtk2 style all color buttons would be just grey. It's possible to // work around this by modifying the button border with a QSS stylesheet, // so that the QStyle will be overwritten, but as a sane default for skins // without styles for WColorPicker, we're setting the platform-independent // "Fusion" style here. This will make the buttons look slightly different // from the rest of the application (when not styled via QSS), but that's // better than having buttons without any colors (which would make the // color picker unusable). QStyle* pStyle = QStyleFactory::create(QString("fusion")); pStyle->setParent(this); m_pStyle = parented_ptr<QStyle>(pStyle);
setLayout(pLayout); addColorButtons();
connect(this, &WColorPicker::colorPicked, this, &WColorPicker::slotColorPicked);}
void WColorPicker::removeColorButtons() { QGridLayout* pLayout = qobject_cast<QGridLayout*>(layout()); VERIFY_OR_DEBUG_ASSERT(pLayout) { qWarning() << "Color Picker has no layout!"; return; }
if (m_pCustomColorButton) { pLayout->removeWidget(m_pCustomColorButton); delete m_pCustomColorButton; m_pCustomColorButton = nullptr; }
while (!m_colorButtons.isEmpty()) { QPushButton* pColorButton = m_colorButtons.takeLast(); pLayout->removeWidget(pColorButton); delete pColorButton; }
if (m_pNoColorButton) { pLayout->removeWidget(m_pNoColorButton); delete m_pNoColorButton; m_pNoColorButton = nullptr; }}
void WColorPicker::addColorButtons() { QGridLayout* pLayout = qobject_cast<QGridLayout*>(layout()); VERIFY_OR_DEBUG_ASSERT(pLayout) { qWarning() << "Color Picker has no layout!"; return; }
int row = 0; int column = 0;
int numColors = m_palette.size(); if (m_options.testFlag(Option::AllowNoColor)) { numColors++; } if (m_options.testFlag(Option::AllowCustomColor)) { numColors++; }
int numColumns = idealColumnCount(numColors); if (m_options.testFlag(Option::AllowNoColor)) { addNoColorButton(pLayout, row, column); column++; }
for (const auto& color : m_palette) { addColorButton(color, pLayout, row, column); column++; if (column == numColumns) { column = 0; row++; } }
if (m_options.testFlag(Option::AllowCustomColor)) { addCustomColorButton(pLayout, row, column); column++; }
adjustSize();}
void WColorPicker::addColorButton(mixxx::RgbColor color, QGridLayout* pLayout, int row, int column) { parented_ptr<QPushButton> pButton = make_parented<QPushButton>("", this); if (m_pStyle) { pButton->setStyle(m_pStyle); }
// Set the background color of the button. This can't be overridden in skin stylesheets. pButton->setStyleSheet( QString("QPushButton { background-color: %1; }").arg(mixxx::RgbColor::toQString(color))); pButton->setToolTip(mixxx::RgbColor::toQString(color)); pButton->setCheckable(true); // Without this the button might shrink when setting the checkmark icon, // both here or via external stylesheets. pButton->setSizePolicy(QSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding)); m_colorButtons.append(pButton);
connect(pButton, &QPushButton::clicked, this, [this, color]() { emit colorPicked(mixxx::RgbColor::optional(color)); }); pLayout->addWidget(pButton, row, column);}
void WColorPicker::addNoColorButton(QGridLayout* pLayout, int row, int column) { QPushButton* pButton = m_pNoColorButton; if (!pButton) { pButton = make_parented<QPushButton>("", this); if (m_pStyle) { pButton->setStyle(m_pStyle); }
pButton->setProperty("noColor", true); pButton->setToolTip(tr("No color")); pButton->setCheckable(true); pButton->setSizePolicy(QSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding)); connect(pButton, &QPushButton::clicked, this, [this]() { emit colorPicked(std::nullopt); }); m_pNoColorButton = pButton; } pLayout->addWidget(pButton, row, column);}
void WColorPicker::addCustomColorButton(QGridLayout* pLayout, int row, int column) { QPushButton* pButton = m_pCustomColorButton; if (!pButton) { pButton = make_parented<QPushButton>("", this); if (m_pStyle) { pButton->setStyle(m_pStyle); }
pButton->setProperty("customColor", true); pButton->setToolTip(tr("Custom color")); pButton->setCheckable(true); connect(pButton, &QPushButton::clicked, this, [this]() { QColor color = QColorDialog::getColor(); if (color.isValid()) { emit colorPicked(mixxx::RgbColor::fromQColor(color)); } }); m_pCustomColorButton = pButton; } pLayout->addWidget(pButton, row, column);}
void WColorPicker::setColorButtonChecked(const mixxx::RgbColor::optional_t& color, bool checked) { // Unset currently selected color QPushButton* pButton = nullptr; if (color) { int i = m_palette.indexOf(*color); if (i != -1) { pButton = m_colorButtons.at(i); } } else if (m_options.testFlag(Option::AllowNoColor)) { pButton = m_pNoColorButton; }
if (!pButton) { return; }
pButton->setChecked(checked); if (m_options.testFlag(Option::NoExtStyleSheet)) { pButton->setIcon(QIcon(checked ? ":/images/ic_checkmark.svg" : "")); } // This is needed to re-apply skin styles (e.g. to show/hide a checkmark icon) pButton->style()->polish(pButton);}
void WColorPicker::resetSelectedColor() { setColorButtonChecked(m_selectedColor, false);}
void WColorPicker::setSelectedColor(const mixxx::RgbColor::optional_t& color) { resetSelectedColor();
m_selectedColor = color; setColorButtonChecked(m_selectedColor, true);}
void WColorPicker::setColorPalette(const ColorPalette& palette) { if (m_palette == palette) { return; }
resetSelectedColor(); removeColorButtons(); m_palette = palette; addColorButtons();}
void WColorPicker::slotColorPicked(const mixxx::RgbColor::optional_t& color) { setSelectedColor(color);}