From f81e8d2f03a4a3226b0b8a58abbed9bc4f97d690 Mon Sep 17 00:00:00 2001 From: Lukas Waslowski Date: Thu, 16 May 2024 12:21:42 +0000 Subject: [PATCH 01/38] DlgTrackInfo/LastPlayed: Add "Last played" field to track info dialog --- src/library/dlgtrackinfo.cpp | 4 ++++ src/library/dlgtrackinfo.ui | 25 ++++++++++++++++++++++++- 2 files changed, 28 insertions(+), 1 deletion(-) diff --git a/src/library/dlgtrackinfo.cpp b/src/library/dlgtrackinfo.cpp index badfcbe353e..138f1dea690 100644 --- a/src/library/dlgtrackinfo.cpp +++ b/src/library/dlgtrackinfo.cpp @@ -378,6 +378,10 @@ void DlgTrackInfo::replaceTrackRecord( mixxx::displayLocalDateTime( mixxx::localDateTimeFromUtc( m_trackRecord.getDateAdded()))); + txtDateLastPlayed->setText( + mixxx::displayLocalDateTime( + mixxx::localDateTimeFromUtc( + m_trackRecord.getPlayCounter().getLastPlayedAt()))); updateTrackMetadataFields(); } diff --git a/src/library/dlgtrackinfo.ui b/src/library/dlgtrackinfo.ui index 635db530a92..b6006794e0a 100644 --- a/src/library/dlgtrackinfo.ui +++ b/src/library/dlgtrackinfo.ui @@ -609,6 +609,29 @@ + + + Last played: + + + + + + + + 75 + true + + + + + + + Qt::LinksAccessibleByMouse|Qt::TextSelectableByKeyboard|Qt::TextSelectableByMouse + + + + ReplayGain: @@ -622,7 +645,7 @@ - + From 0eda4b9b4357be10ee0c0110db5df054c755d320 Mon Sep 17 00:00:00 2001 From: Lukas Waslowski Date: Sat, 25 May 2024 17:24:06 +0000 Subject: [PATCH 02/38] DlgTrackInfo/LastPlayed: Display placeholder for last played date --- src/library/dlgtrackinfo.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/library/dlgtrackinfo.cpp b/src/library/dlgtrackinfo.cpp index 138f1dea690..da4b224ec22 100644 --- a/src/library/dlgtrackinfo.cpp +++ b/src/library/dlgtrackinfo.cpp @@ -378,10 +378,10 @@ void DlgTrackInfo::replaceTrackRecord( mixxx::displayLocalDateTime( mixxx::localDateTimeFromUtc( m_trackRecord.getDateAdded()))); - txtDateLastPlayed->setText( - mixxx::displayLocalDateTime( - mixxx::localDateTimeFromUtc( - m_trackRecord.getPlayCounter().getLastPlayedAt()))); + auto lastPlayed = m_trackRecord.getPlayCounter().getLastPlayedAt(); + txtDateLastPlayed->setText(lastPlayed.isValid() + ? mixxx::displayLocalDateTime(mixxx::localDateTimeFromUtc(lastPlayed)) + : QStringLiteral("-")); updateTrackMetadataFields(); } From 79b6d7fa99d50431d6444dc40c7db3bbbf743443 Mon Sep 17 00:00:00 2001 From: Lukas Waslowski Date: Thu, 16 May 2024 13:07:23 +0000 Subject: [PATCH 03/38] DlgTrackInfo/Layout: Fix alignment of "Grouping" and "Comments" label This makes these two labels have the same alignment and pixel position (relative to their input control) as all the other labels in the dialog. --- src/library/dlgtrackinfo.cpp | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/library/dlgtrackinfo.cpp b/src/library/dlgtrackinfo.cpp index da4b224ec22..531c5c22371 100644 --- a/src/library/dlgtrackinfo.cpp +++ b/src/library/dlgtrackinfo.cpp @@ -88,6 +88,11 @@ void DlgTrackInfo::init() { // This is necessary to pass on mouseMove events to WStarRating m_pWStarRating->setMouseTracking(true); + // Workaround: Align the baseline of the "Comments" label + // with the baseline of the text inside the comments field + const int topMargin = txtComment->frameWidth() + int(txtComment->document()->documentMargin()); + lblTrackComment->setContentsMargins(0, topMargin, 0, 0); + if (m_pTrackModel) { connect(btnNext, &QPushButton::clicked, From c00dfc95e88c82cd880858bdc0dfa614ff44aa1c Mon Sep 17 00:00:00 2001 From: Lukas Waslowski Date: Tue, 21 May 2024 10:50:08 +0000 Subject: [PATCH 04/38] DlgTrackInfo/Cleanup: Fix: Make text of "Bitrate" field selectable All other similar fields in the dialog are selectable, so this seems to just have been an oversight. --- src/library/dlgtrackinfo.ui | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/library/dlgtrackinfo.ui b/src/library/dlgtrackinfo.ui index b6006794e0a..12e699ddeba 100644 --- a/src/library/dlgtrackinfo.ui +++ b/src/library/dlgtrackinfo.ui @@ -695,6 +695,9 @@ + + Qt::LinksAccessibleByMouse|Qt::TextSelectableByKeyboard|Qt::TextSelectableByMouse + From 9aa4ff0023c9e2a6d47704831c9d7d0f0ab35808 Mon Sep 17 00:00:00 2001 From: Lukas Waslowski Date: Mon, 20 May 2024 10:45:57 +0000 Subject: [PATCH 05/38] DlgTrackInfo/Cleanup: Improve GroupBox names --- src/library/dlgtrackinfo.ui | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/library/dlgtrackinfo.ui b/src/library/dlgtrackinfo.ui index 12e699ddeba..e3c13734074 100644 --- a/src/library/dlgtrackinfo.ui +++ b/src/library/dlgtrackinfo.ui @@ -49,7 +49,7 @@ - + @@ -459,7 +459,7 @@ - + 0 From 2e5a11be542c9fb997de9136dc641238bf21dd20 Mon Sep 17 00:00:00 2001 From: Lukas Waslowski Date: Fri, 17 May 2024 10:54:52 +0000 Subject: [PATCH 06/38] DlgTrackInfo/Cleanup: Group related properties in the header --- src/library/dlgtrackinfo.h | 4 ---- 1 file changed, 4 deletions(-) diff --git a/src/library/dlgtrackinfo.h b/src/library/dlgtrackinfo.h index a05a7bfcb5f..768e9354a7a 100644 --- a/src/library/dlgtrackinfo.h +++ b/src/library/dlgtrackinfo.h @@ -104,18 +104,14 @@ class DlgTrackInfo : public QDialog, public Ui::DlgTrackInfo { void updateSpinBpmFromBeats(); const UserSettingsPointer m_pUserSettings; - const TrackModel* const m_pTrackModel; TrackPointer m_pLoadedTrack; - QModelIndex m_currentTrackIndex; - mixxx::TrackRecord m_trackRecord; mixxx::BeatsPointer m_pBeatsClone; bool m_trackHasBeatMap; - TapFilter m_tapFilter; mixxx::Bpm m_lastTapedBpm; From 9b9aa75ae050bf6d38763050becfb66c9a2ecb3d Mon Sep 17 00:00:00 2001 From: Lukas Waslowski Date: Thu, 16 May 2024 22:01:40 +0000 Subject: [PATCH 07/38] DlgTrackInfo/Cleanup: Simplify updateTrackMetadataFields --- src/library/dlgtrackinfo.cpp | 46 ++++++++++++++++-------------------- 1 file changed, 20 insertions(+), 26 deletions(-) diff --git a/src/library/dlgtrackinfo.cpp b/src/library/dlgtrackinfo.cpp index 531c5c22371..d340ef48c93 100644 --- a/src/library/dlgtrackinfo.cpp +++ b/src/library/dlgtrackinfo.cpp @@ -392,35 +392,29 @@ void DlgTrackInfo::replaceTrackRecord( } void DlgTrackInfo::updateTrackMetadataFields() { + const auto metadata = m_trackRecord.getMetadata(); + const auto trackInfo = metadata.getTrackInfo(); + const auto albumInfo = metadata.getAlbumInfo(); + const auto signalInfo = metadata.getStreamInfo().getSignalInfo(); + // Editable fields - txtTrackName->setText( - m_trackRecord.getMetadata().getTrackInfo().getTitle()); - txtArtist->setText( - m_trackRecord.getMetadata().getTrackInfo().getArtist()); - txtAlbum->setText( - m_trackRecord.getMetadata().getAlbumInfo().getTitle()); - txtAlbumArtist->setText( - m_trackRecord.getMetadata().getAlbumInfo().getArtist()); - txtGenre->setText( - m_trackRecord.getMetadata().getTrackInfo().getGenre()); - txtComposer->setText( - m_trackRecord.getMetadata().getTrackInfo().getComposer()); - txtGrouping->setText( - m_trackRecord.getMetadata().getTrackInfo().getGrouping()); - txtYear->setText( - m_trackRecord.getMetadata().getTrackInfo().getYear()); - txtTrackNumber->setText( - m_trackRecord.getMetadata().getTrackInfo().getTrackNumber()); - txtComment->setPlainText( - m_trackRecord.getMetadata().getTrackInfo().getComment()); - txtBpm->setText( - m_trackRecord.getMetadata().getTrackInfo().getBpmText()); + txtTrackName->setText(trackInfo.getTitle()); + txtArtist->setText(trackInfo.getArtist()); + txtAlbum->setText(albumInfo.getTitle()); + txtAlbumArtist->setText(albumInfo.getArtist()); + txtGenre->setText(trackInfo.getGenre()); + txtComposer->setText(trackInfo.getComposer()); + txtGrouping->setText(trackInfo.getGrouping()); + txtYear->setText(trackInfo.getYear()); + txtTrackNumber->setText(trackInfo.getTrackNumber()); + txtComment->setPlainText(trackInfo.getComment()); + txtBpm->setText(trackInfo.getBpmText()); displayKeyText(); // Non-editable fields txtDuration->setText( - m_trackRecord.getMetadata().getDurationText(mixxx::Duration::Precision::SECONDS)); - QString bitrate = m_trackRecord.getMetadata().getBitrateText(); + metadata.getDurationText(mixxx::Duration::Precision::SECONDS)); + QString bitrate = metadata.getBitrateText(); if (bitrate.isEmpty()) { txtBitrate->clear(); } else { @@ -428,9 +422,9 @@ void DlgTrackInfo::updateTrackMetadataFields() { } txtReplayGain->setText( mixxx::ReplayGain::ratioToString( - m_trackRecord.getMetadata().getTrackInfo().getReplayGain().getRatio())); + trackInfo.getReplayGain().getRatio())); - auto samplerate = m_trackRecord.getMetadata().getStreamInfo().getSignalInfo().getSampleRate(); + auto samplerate = signalInfo.getSampleRate(); if (samplerate.isValid()) { txtSamplerate->setText(QString::number(samplerate.value()) + " Hz"); } else { From f1f3089bb18eb7e2975b567ea0bb6d1e113f1377 Mon Sep 17 00:00:00 2001 From: Lukas Waslowski Date: Tue, 21 May 2024 11:38:53 +0000 Subject: [PATCH 08/38] DlgTrackInfo/Cleanup: Associate read-only fields with track property names --- src/library/dlgtrackinfo.cpp | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/src/library/dlgtrackinfo.cpp b/src/library/dlgtrackinfo.cpp index d340ef48c93..40e2d4f84f6 100644 --- a/src/library/dlgtrackinfo.cpp +++ b/src/library/dlgtrackinfo.cpp @@ -61,7 +61,7 @@ void DlgTrackInfo::init() { // Store tag edit widget pointers to allow focusing a specific widgets when // this is opened by double-clicking a WTrackProperty label. - // Associate with property strings taken from library/dao/trackdao.h + // Associate with property strings taken from library/dao/trackdao.cpp m_propertyWidgets.insert("artist", txtArtist); m_propertyWidgets.insert("title", txtTrackName); m_propertyWidgets.insert("titleInfo", txtTrackName); @@ -75,6 +75,16 @@ void DlgTrackInfo::init() { m_propertyWidgets.insert("key", txtKey); m_propertyWidgets.insert("grouping", txtGrouping); m_propertyWidgets.insert("comment", txtComment); + m_propertyWidgets.insert("datetime_added", txtDateAdded); + m_propertyWidgets.insert("duration", txtDuration); + m_propertyWidgets.insert("timesplayed", txtDateLastPlayed); + m_propertyWidgets.insert("last_played_at", txtDateLastPlayed); + m_propertyWidgets.insert("filetype", txtType); + m_propertyWidgets.insert("bitrate", txtBitrate); + m_propertyWidgets.insert("samplerate", txtSamplerate); + m_propertyWidgets.insert("replaygain", txtReplayGain); + m_propertyWidgets.insert("replaygain_peak", txtReplayGain); + m_propertyWidgets.insert("track_locations.location", txtLocation); coverLayout->setAlignment(Qt::AlignRight | Qt::AlignTop); coverLayout->setSpacing(0); From 25eb63c401d14323f1981f640d6d7c50b2e560f8 Mon Sep 17 00:00:00 2001 From: Lukas Waslowski Date: Mon, 20 May 2024 12:08:31 +0000 Subject: [PATCH 09/38] WStarRating: Remove Qt5 compatibility code --- src/widget/wstarrating.cpp | 4 ---- 1 file changed, 4 deletions(-) diff --git a/src/widget/wstarrating.cpp b/src/widget/wstarrating.cpp index 840ff7d16aa..00ef7dd88e3 100644 --- a/src/widget/wstarrating.cpp +++ b/src/widget/wstarrating.cpp @@ -54,11 +54,7 @@ void WStarRating::paintEvent(QPaintEvent * /*unused*/) { } void WStarRating::mouseMoveEvent(QMouseEvent *event) { -#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0) const int pos = event->position().toPoint().x(); -#else - const int pos = event->x(); -#endif int star = m_visualStarRating.starAtPosition(pos, rect()); if (star == StarRating::kInvalidStarCount) { From 4b309a8ca61a4a2275fa2f2742e95a047e03517c Mon Sep 17 00:00:00 2001 From: Lukas Waslowski Date: Thu, 16 May 2024 11:02:39 +0000 Subject: [PATCH 10/38] WStarRating: Add keyboard controls for modifying the star rating --- src/widget/wstarrating.cpp | 65 ++++++++++++++++++++++++++++++++++++++ src/widget/wstarrating.h | 1 + 2 files changed, 66 insertions(+) diff --git a/src/widget/wstarrating.cpp b/src/widget/wstarrating.cpp index 00ef7dd88e3..4030383ed56 100644 --- a/src/widget/wstarrating.cpp +++ b/src/widget/wstarrating.cpp @@ -53,6 +53,71 @@ void WStarRating::paintEvent(QPaintEvent * /*unused*/) { m_visualStarRating.paint(&painter, m_contentRect); } +void WStarRating::keyPressEvent(QKeyEvent* event) { + // Change rating when certain keys are pressed + QKeyEvent* ke = static_cast(event); + int newRating = m_visualStarRating.starCount(); + switch (ke->key()) { + case Qt::Key_0: { + newRating = 0; + break; + } + case Qt::Key_1: { + newRating = 1; + break; + } + case Qt::Key_2: { + newRating = 2; + break; + } + case Qt::Key_3: { + newRating = 3; + break; + } + case Qt::Key_4: { + newRating = 4; + break; + } + case Qt::Key_5: { + newRating = 5; + break; + } + case Qt::Key_6: { + newRating = 6; + break; + } + case Qt::Key_7: { + newRating = 7; + break; + } + case Qt::Key_8: { + newRating = 8; + break; + } + case Qt::Key_9: { + newRating = 9; + break; + } + case Qt::Key_Right: + case Qt::Key_Plus: { + newRating++; + break; + } + case Qt::Key_Left: + case Qt::Key_Minus: { + newRating--; + break; + } + default: { + event->ignore(); + return; + } + } + newRating = math_clamp(newRating, StarRating::kMinStarCount, m_visualStarRating.maxStarCount()); + updateVisualRating(newRating); + m_starCount = newRating; +} + void WStarRating::mouseMoveEvent(QMouseEvent *event) { const int pos = event->position().toPoint().x(); int star = m_visualStarRating.starAtPosition(pos, rect()); diff --git a/src/widget/wstarrating.h b/src/widget/wstarrating.h index 99164c265a6..e32ed001701 100644 --- a/src/widget/wstarrating.h +++ b/src/widget/wstarrating.h @@ -22,6 +22,7 @@ class WStarRating : public WWidget { protected: void paintEvent(QPaintEvent* e) override; + void keyPressEvent(QKeyEvent* event) override; void mouseMoveEvent(QMouseEvent *event) override; void mouseReleaseEvent(QMouseEvent *event) override; void leaveEvent(QEvent * /*unused*/) override; From 43ef74bb043a0df13288e277127d0704f39062f3 Mon Sep 17 00:00:00 2001 From: Lukas Waslowski Date: Mon, 20 May 2024 11:38:34 +0000 Subject: [PATCH 11/38] WStarRating: Highlight the control when having keyboard focus --- src/widget/wstarrating.cpp | 51 +++++++++++++++++++++++++++++++++++--- src/widget/wstarrating.h | 6 ++++- 2 files changed, 52 insertions(+), 5 deletions(-) diff --git a/src/widget/wstarrating.cpp b/src/widget/wstarrating.cpp index 4030383ed56..8bb37bcceaf 100644 --- a/src/widget/wstarrating.cpp +++ b/src/widget/wstarrating.cpp @@ -11,8 +11,10 @@ class QWidgets; WStarRating::WStarRating(QWidget* pParent) : WWidget(pParent), + m_focusedViaKeyboard(false), m_starCount(0), m_visualStarRating(m_starCount) { + setAttribute(Qt::WA_Hover); } void WStarRating::setup(const QDomNode& node, const SkinContext& context) { @@ -42,15 +44,51 @@ void WStarRating::slotSetRating(int starCount) { emit ratingChangeRequest(starCount); } +void WStarRating::focusInEvent(QFocusEvent* event) { + m_focusedViaKeyboard = event->reason() == Qt::TabFocusReason || + event->reason() == Qt::BacktabFocusReason || + event->reason() == Qt::ShortcutFocusReason; + QWidget::focusInEvent(event); +} + +void WStarRating::focusOutEvent(QFocusEvent* event) { + auto shouldUpdateVisual = m_focusedViaKeyboard; + m_focusedViaKeyboard = false; + QWidget::focusInEvent(event); + if (shouldUpdateVisual) { + update(); + } +} + void WStarRating::paintEvent(QPaintEvent * /*unused*/) { QStyleOption option; option.initFrom(this); QStylePainter painter(this); - painter.setBrush(option.palette.text()); + // The default value for State_KeyboardFocusChange is never + // reset once set to true for a certain window, so we + // implement our own custom version of it instead. + if (m_focusedViaKeyboard) { + option.state |= QStyle::State_KeyboardFocusChange; + } else { + option.state &= ~QStyle::State_KeyboardFocusChange; + } + + // Center rating horizontally and vertically + QRect contentRect(QPoint(0, 0), m_visualStarRating.sizeHint()); + contentRect.moveCenter(option.rect.center()); + painter.drawPrimitive(QStyle::PE_Widget, option); - m_visualStarRating.paint(&painter, m_contentRect); + if (focusPolicy() != Qt::NoFocus && + (option.state & QStyle::State_HasFocus) && + (option.state & QStyle::State_KeyboardFocusChange)) { + painter.setBrush(option.palette.highlight().color()); + } else { + painter.setBrush(option.palette.text().color()); + } + + m_visualStarRating.paint(&painter, contentRect); } void WStarRating::keyPressEvent(QKeyEvent* event) { @@ -113,8 +151,10 @@ void WStarRating::keyPressEvent(QKeyEvent* event) { return; } } + bool shouldUpdateVisual = !m_focusedViaKeyboard; + m_focusedViaKeyboard = true; newRating = math_clamp(newRating, StarRating::kMinStarCount, m_visualStarRating.maxStarCount()); - updateVisualRating(newRating); + updateVisualRating(newRating, shouldUpdateVisual); m_starCount = newRating; } @@ -133,8 +173,11 @@ void WStarRating::leaveEvent(QEvent* /*unused*/) { resetVisualRating(); } -void WStarRating::updateVisualRating(int starCount) { +void WStarRating::updateVisualRating(int starCount, bool forceRepaint) { if (starCount == m_visualStarRating.starCount()) { + if (forceRepaint) { + update(); + } return; } m_visualStarRating.setStarCount(starCount); diff --git a/src/widget/wstarrating.h b/src/widget/wstarrating.h index e32ed001701..ef18246fdb1 100644 --- a/src/widget/wstarrating.h +++ b/src/widget/wstarrating.h @@ -21,6 +21,8 @@ class WStarRating : public WWidget { void ratingChangeRequest(int starCount); protected: + void focusInEvent(QFocusEvent* e) override; + void focusOutEvent(QFocusEvent* e) override; void paintEvent(QPaintEvent* e) override; void keyPressEvent(QKeyEvent* event) override; void mouseMoveEvent(QMouseEvent *event) override; @@ -29,12 +31,14 @@ class WStarRating : public WWidget { void fillDebugTooltip(QStringList* debug) override; private: + bool m_focusedViaKeyboard; + int m_starCount; StarRating m_visualStarRating; mutable QRect m_contentRect; - void updateVisualRating(int starCount); + void updateVisualRating(int starCount, bool forceRepaint = false); void resetVisualRating() { updateVisualRating(m_starCount); } From ae81d1f2575eb2bc95edd9f0559a37b278012eb5 Mon Sep 17 00:00:00 2001 From: Lukas Waslowski Date: Thu, 16 May 2024 11:00:37 +0000 Subject: [PATCH 12/38] DlgTrackInfo/StarRating: Move UI setup code into the .ui file. --- src/library/dlgtrackinfo.cpp | 6 ------ src/library/dlgtrackinfo.ui | 12 ++++++++++++ 2 files changed, 12 insertions(+), 6 deletions(-) diff --git a/src/library/dlgtrackinfo.cpp b/src/library/dlgtrackinfo.cpp index 40e2d4f84f6..9e0617c4fca 100644 --- a/src/library/dlgtrackinfo.cpp +++ b/src/library/dlgtrackinfo.cpp @@ -86,14 +86,8 @@ void DlgTrackInfo::init() { m_propertyWidgets.insert("replaygain_peak", txtReplayGain); m_propertyWidgets.insert("track_locations.location", txtLocation); - coverLayout->setAlignment(Qt::AlignRight | Qt::AlignTop); - coverLayout->setSpacing(0); - coverLayout->setContentsMargins(0, 0, 0, 0); coverLayout->insertWidget(0, m_pWCoverArtLabel.get()); - starsLayout->setAlignment(Qt::AlignRight | Qt::AlignVCenter); - starsLayout->setSpacing(0); - starsLayout->setContentsMargins(0, 0, 0, 0); starsLayout->insertWidget(0, m_pWStarRating.get()); // This is necessary to pass on mouseMove events to WStarRating m_pWStarRating->setMouseTracking(true); diff --git a/src/library/dlgtrackinfo.ui b/src/library/dlgtrackinfo.ui index e3c13734074..b9bffd3c0b9 100644 --- a/src/library/dlgtrackinfo.ui +++ b/src/library/dlgtrackinfo.ui @@ -102,9 +102,15 @@ 0 + + 0 + QLayout::SetDefaultConstraint + + Qt::AlignRight|Qt::AlignVCenter + @@ -216,9 +222,15 @@ 0 + + 0 + QLayout::SetDefaultConstraint + + Qt::AlignRight|Qt::AlignVCenter + From 5bef6d22ba80515b7fa765ef77ff1e4d795f99c1 Mon Sep 17 00:00:00 2001 From: Lukas Waslowski Date: Thu, 16 May 2024 22:23:07 +0200 Subject: [PATCH 13/38] DlgTrackInfo/StarRating: Integrate WStarRating into the tab order --- src/library/dlgtrackinfo.cpp | 13 ++++--------- src/library/dlgtrackinfo.h | 1 - src/library/dlgtrackinfo.ui | 30 +++++++++++++++--------------- 3 files changed, 19 insertions(+), 25 deletions(-) diff --git a/src/library/dlgtrackinfo.cpp b/src/library/dlgtrackinfo.cpp index 9e0617c4fca..dc3096e4560 100644 --- a/src/library/dlgtrackinfo.cpp +++ b/src/library/dlgtrackinfo.cpp @@ -45,7 +45,6 @@ DlgTrackInfo::DlgTrackInfo( m_tapFilter(this, kFilterLength, kMaxInterval), m_pWCoverArtMenu(make_parented(this)), m_pWCoverArtLabel(make_parented(this, m_pWCoverArtMenu)), - m_pWStarRating(make_parented(this)), m_pColorPicker(make_parented( WColorPicker::Option::AllowNoColor | // TODO(xxx) remove this once the preferences are themed via QSS @@ -88,10 +87,6 @@ void DlgTrackInfo::init() { coverLayout->insertWidget(0, m_pWCoverArtLabel.get()); - starsLayout->insertWidget(0, m_pWStarRating.get()); - // This is necessary to pass on mouseMove events to WStarRating - m_pWStarRating->setMouseTracking(true); - // Workaround: Align the baseline of the "Comments" label // with the baseline of the text inside the comments field const int topMargin = txtComment->frameWidth() + int(txtComment->document()->documentMargin()); @@ -275,7 +270,7 @@ void DlgTrackInfo::init() { this, &DlgTrackInfo::slotReloadCoverArt); - connect(m_pWStarRating, + connect(starRating, &WStarRating::ratingChangeRequest, this, &DlgTrackInfo::slotRatingChanged); @@ -364,7 +359,7 @@ void DlgTrackInfo::updateFromTrack(const Track& track) { reloadTrackBeats(track); - m_pWStarRating->slotSetRating(m_pLoadedTrack->getRating()); + starRating->slotSetRating(m_pLoadedTrack->getRating()); } void DlgTrackInfo::replaceTrackRecord( @@ -643,7 +638,7 @@ void DlgTrackInfo::clear() { txtLocation->setText(""); - m_pWStarRating->slotSetRating(0); + starRating->slotSetRating(0); } void DlgTrackInfo::slotBpmScale(mixxx::Beats::BpmScale bpmScale) { @@ -758,7 +753,7 @@ void DlgTrackInfo::slotRatingChanged(int rating) { } if (m_trackRecord.isValidRating(rating) && rating != m_trackRecord.getRating()) { - m_pWStarRating->slotSetRating(rating); + starRating->slotSetRating(rating); m_trackRecord.setRating(rating); } } diff --git a/src/library/dlgtrackinfo.h b/src/library/dlgtrackinfo.h index 768e9354a7a..1a8a0ebe864 100644 --- a/src/library/dlgtrackinfo.h +++ b/src/library/dlgtrackinfo.h @@ -119,7 +119,6 @@ class DlgTrackInfo : public QDialog, public Ui::DlgTrackInfo { parented_ptr m_pWCoverArtMenu; parented_ptr m_pWCoverArtLabel; - parented_ptr m_pWStarRating; parented_ptr m_pColorPicker; std::unique_ptr m_pDlgTagFetcher; diff --git a/src/library/dlgtrackinfo.ui b/src/library/dlgtrackinfo.ui index b9bffd3c0b9..6506f75f5d6 100644 --- a/src/library/dlgtrackinfo.ui +++ b/src/library/dlgtrackinfo.ui @@ -211,27 +211,19 @@ - + + + true + + + Qt::StrongFocus + 0 0 - - - 0 - - - 0 - - - QLayout::SetDefaultConstraint - - - Qt::AlignRight|Qt::AlignVCenter - - @@ -1057,6 +1049,13 @@ Often results in higher quality beatgrids, but will not do well on tracks that h + + + WStarRating + QWidget +
widget/wstarrating.h
+
+
tabWidget txtTrackName @@ -1067,6 +1066,7 @@ Often results in higher quality beatgrids, but will not do well on tracks that h txtGenre txtGrouping txtComment + starRating txtYear txtKey txtTrackNumber From f60d4c2066422e1349455658aefd461776be4d87 Mon Sep 17 00:00:00 2001 From: Lukas Waslowski Date: Thu, 16 May 2024 23:37:01 +0000 Subject: [PATCH 14/38] DlgTrackInfo/LeftRight: Conditionally enable/disable btnNext and btnPrev --- src/library/dlgtrackinfo.cpp | 16 ++++++++++++---- src/library/dlgtrackinfo.h | 1 + 2 files changed, 13 insertions(+), 4 deletions(-) diff --git a/src/library/dlgtrackinfo.cpp b/src/library/dlgtrackinfo.cpp index dc3096e4560..394686dc81a 100644 --- a/src/library/dlgtrackinfo.cpp +++ b/src/library/dlgtrackinfo.cpp @@ -324,9 +324,14 @@ void DlgTrackInfo::slotPrevDlgTagFetcher() { loadPrevTrack(); } +QModelIndex DlgTrackInfo::getPrevNextTrack(bool next) { + return m_currentTrackIndex.sibling( + m_currentTrackIndex.row() + (next ? 1 : -1), + m_currentTrackIndex.column()); +} + void DlgTrackInfo::loadNextTrack() { - auto nextRow = m_currentTrackIndex.sibling( - m_currentTrackIndex.row() + 1, m_currentTrackIndex.column()); + auto nextRow = getPrevNextTrack(true); if (nextRow.isValid()) { loadTrack(nextRow); emit next(); @@ -334,8 +339,7 @@ void DlgTrackInfo::loadNextTrack() { } void DlgTrackInfo::loadPrevTrack() { - QModelIndex prevRow = m_currentTrackIndex.sibling( - m_currentTrackIndex.row() - 1, m_currentTrackIndex.column()); + auto prevRow = getPrevNextTrack(false); if (prevRow.isValid()) { loadTrack(prevRow); emit previous(); @@ -495,7 +499,11 @@ void DlgTrackInfo::loadTrack(const QModelIndex& index) { return; } TrackPointer pTrack = m_pTrackModel->getTrack(index); + m_currentTrackIndex = index; + btnPrev->setEnabled(getPrevNextTrack(false).isValid()); + btnNext->setEnabled(getPrevNextTrack(true).isValid()); + loadTrackInternal(pTrack); if (m_pDlgTagFetcher && m_pDlgTagFetcher->isVisible()) { m_pDlgTagFetcher->loadTrack(m_currentTrackIndex); diff --git a/src/library/dlgtrackinfo.h b/src/library/dlgtrackinfo.h index 1a8a0ebe864..3cb7e99a36e 100644 --- a/src/library/dlgtrackinfo.h +++ b/src/library/dlgtrackinfo.h @@ -77,6 +77,7 @@ class DlgTrackInfo : public QDialog, public Ui::DlgTrackInfo { void slotReloadCoverArt(); private: + QModelIndex getPrevNextTrack(bool next); void loadNextTrack(); void loadPrevTrack(); void loadTrackInternal(const TrackPointer& pTrack); From ae797c208abdd721c798f984d0f3281c06bbd515 Mon Sep 17 00:00:00 2001 From: Lukas Waslowski Date: Thu, 16 May 2024 22:03:52 +0000 Subject: [PATCH 15/38] DlgTrackInfo/LeftRight: Add Alt+Left / Alt+Right as additional shortcuts for navigating between tracks --- src/library/dlgtrackinfo.cpp | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/src/library/dlgtrackinfo.cpp b/src/library/dlgtrackinfo.cpp index 394686dc81a..628b6c321fb 100644 --- a/src/library/dlgtrackinfo.cpp +++ b/src/library/dlgtrackinfo.cpp @@ -1,5 +1,6 @@ #include "library/dlgtrackinfo.h" +#include #include #include #include @@ -101,6 +102,18 @@ void DlgTrackInfo::init() { &QPushButton::clicked, this, &DlgTrackInfo::slotPrevButton); + + QShortcut* nextShortcut = new QShortcut(QKeySequence("Alt+Right"), this); + QShortcut* prevShortcut = new QShortcut(QKeySequence("Alt+Left"), this); + + connect(nextShortcut, + &QShortcut::activated, + btnNext, + [this] { btnNext->animateClick(); }); + connect(prevShortcut, + &QShortcut::activated, + btnPrev, + [this] { btnPrev->animateClick(); }); } else { btnNext->hide(); btnPrev->hide(); From 643533e68a990580062de16f1caf12501043f726 Mon Sep 17 00:00:00 2001 From: Lukas Waslowski Date: Sat, 22 Jun 2024 18:37:46 +0000 Subject: [PATCH 16/38] DlgTrackInfo/LeftRight: Refocus the current widget when moving to a different track --- src/library/dlgtrackinfo.cpp | 17 +++++++++++++++++ src/library/dlgtrackinfo.h | 1 + 2 files changed, 18 insertions(+) diff --git a/src/library/dlgtrackinfo.cpp b/src/library/dlgtrackinfo.cpp index 628b6c321fb..b022cd7ffda 100644 --- a/src/library/dlgtrackinfo.cpp +++ b/src/library/dlgtrackinfo.cpp @@ -347,6 +347,7 @@ void DlgTrackInfo::loadNextTrack() { auto nextRow = getPrevNextTrack(true); if (nextRow.isValid()) { loadTrack(nextRow); + refocusCurrentWidget(); emit next(); } } @@ -355,10 +356,26 @@ void DlgTrackInfo::loadPrevTrack() { auto prevRow = getPrevNextTrack(false); if (prevRow.isValid()) { loadTrack(prevRow); + refocusCurrentWidget(); emit previous(); } } +/// Simulate moving the focus out of and then back into the currently +/// focused widget to trigger behaviors like the "Select all on focus" +/// for QLineEdit. +/// +/// This is done when moving to the previous/next track, because, +/// logically, the user has moved to a new dialog, even though we +/// reuse the current dialog instance internally. +void DlgTrackInfo::refocusCurrentWidget() { + QWidget* focusedWidget = QApplication::focusWidget(); + if (focusedWidget && isAncestorOf(focusedWidget)) { + focusedWidget->clearFocus(); + focusedWidget->setFocus(Qt::ShortcutFocusReason); + } +} + void DlgTrackInfo::updateFromTrack(const Track& track) { const QSignalBlocker signalBlocker(this); diff --git a/src/library/dlgtrackinfo.h b/src/library/dlgtrackinfo.h index 3cb7e99a36e..81f55995d1d 100644 --- a/src/library/dlgtrackinfo.h +++ b/src/library/dlgtrackinfo.h @@ -80,6 +80,7 @@ class DlgTrackInfo : public QDialog, public Ui::DlgTrackInfo { QModelIndex getPrevNextTrack(bool next); void loadNextTrack(); void loadPrevTrack(); + void refocusCurrentWidget(); void loadTrackInternal(const TrackPointer& pTrack); void reloadTrackBeats(const Track& track); void trackColorDialogSetColor(const mixxx::RgbColor::optional_t& color); From dcd791bd1a92168420eb15b768bc6d87de6ee76c Mon Sep 17 00:00:00 2001 From: Lukas Waslowski Date: Thu, 16 May 2024 22:34:16 +0000 Subject: [PATCH 17/38] DlgTrackInfo/Sizing: Scroll to start of text fields by setting the cursor position --- src/library/dlgtrackinfo.cpp | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/src/library/dlgtrackinfo.cpp b/src/library/dlgtrackinfo.cpp index b022cd7ffda..a7d26069503 100644 --- a/src/library/dlgtrackinfo.cpp +++ b/src/library/dlgtrackinfo.cpp @@ -444,6 +444,18 @@ void DlgTrackInfo::updateTrackMetadataFields() { txtBpm->setText(trackInfo.getBpmText()); displayKeyText(); + // Set cursor / scroll position of editable fields (only relevant + // when the content's width is larger than the width of the QLineEdit) + txtTrackName->setCursorPosition(0); + txtArtist->setCursorPosition(0); + txtAlbum->setCursorPosition(0); + txtAlbumArtist->setCursorPosition(0); + txtGenre->setCursorPosition(0); + txtComposer->setCursorPosition(0); + txtGrouping->setCursorPosition(0); + txtYear->setCursorPosition(0); + txtTrackNumber->setCursorPosition(0); + // Non-editable fields txtDuration->setText( metadata.getDurationText(mixxx::Duration::Precision::SECONDS)); From 891d021fe8696b395ffbb24d22c17d3872f9c324 Mon Sep 17 00:00:00 2001 From: Lukas Waslowski Date: Thu, 16 May 2024 17:06:35 +0000 Subject: [PATCH 18/38] DlgTrackInfo/Sizing: Add WMultiLineTextEdit to allow for correct resizing Also fix the sizePolicy of other widgets, such that the "Comments" field gets all available remaining vertical space. --- CMakeLists.txt | 1 + src/library/dlgtrackinfo.ui | 23 ++++++++++++++++++++--- src/widget/wmultilinetextedit.cpp | 27 +++++++++++++++++++++++++++ src/widget/wmultilinetextedit.h | 17 +++++++++++++++++ 4 files changed, 65 insertions(+), 3 deletions(-) create mode 100644 src/widget/wmultilinetextedit.cpp create mode 100644 src/widget/wmultilinetextedit.h diff --git a/CMakeLists.txt b/CMakeLists.txt index 8b836179f73..d8993d6b949 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1285,6 +1285,7 @@ add_library(mixxx-lib STATIC EXCLUDE_FROM_ALL src/widget/wlibrarytableview.cpp src/widget/wlibrarytextbrowser.cpp src/widget/wmainmenubar.cpp + src/widget/wmultilinetextedit.cpp src/widget/wnumber.cpp src/widget/wnumberdb.cpp src/widget/wnumberpos.cpp diff --git a/src/library/dlgtrackinfo.ui b/src/library/dlgtrackinfo.ui index 6506f75f5d6..480a42564bc 100644 --- a/src/library/dlgtrackinfo.ui +++ b/src/library/dlgtrackinfo.ui @@ -387,10 +387,22 @@
- + true + + Qt::ScrollBarAlwaysOff + + + Qt::ScrollBarAsNeeded + + + + 0 + 0 + + @@ -437,7 +449,7 @@ - + 0 0 @@ -715,7 +727,7 @@ Qt::Vertical - QSizePolicy::MinimumExpanding + QSizePolicy::Minimum @@ -1050,6 +1062,11 @@ Often results in higher quality beatgrids, but will not do well on tracks that h + + WMultiLineTextEdit + QLineEdit +
widget/wmultilinetextedit.h
+
WStarRating QWidget diff --git a/src/widget/wmultilinetextedit.cpp b/src/widget/wmultilinetextedit.cpp new file mode 100644 index 00000000000..092439f1640 --- /dev/null +++ b/src/widget/wmultilinetextedit.cpp @@ -0,0 +1,27 @@ +#include "widget/wmultilinetextedit.h" + +#include + +#include "moc_wmultilinetextedit.cpp" + +WMultiLineTextEdit::WMultiLineTextEdit(QWidget* parent) + : QPlainTextEdit(parent) { +} + +QSize WMultiLineTextEdit::minimumSizeHint() const { + const int minLines = 2; + return sizeHintImpl(minLines); +} + +QSize WMultiLineTextEdit::sizeHint() const { + const int minLines = 2; + return sizeHintImpl(minLines); +} + +QSize WMultiLineTextEdit::sizeHintImpl(const int minLines) const { + const auto w = 0.0; + const auto h = 2 * frameWidth() + 2 * document()->documentMargin() + + QFontMetrics(font()).lineSpacing() * minLines; + + return QSizeF(w, h).toSize(); +} diff --git a/src/widget/wmultilinetextedit.h b/src/widget/wmultilinetextedit.h new file mode 100644 index 00000000000..a24de83bf97 --- /dev/null +++ b/src/widget/wmultilinetextedit.h @@ -0,0 +1,17 @@ +#pragma once + +#include + +/// An implementation of QPlainTextTedit with a more sensible minimum +/// size of 2 text lines. +class WMultiLineTextEdit : public QPlainTextEdit { + Q_OBJECT + + public: + WMultiLineTextEdit(QWidget* parent = nullptr); + QSize minimumSizeHint() const override; + QSize sizeHint() const override; + + private: + QSize sizeHintImpl(const int minLines) const; +}; From 3fba16494311686c937f75051cea24cafbaa61f2 Mon Sep 17 00:00:00 2001 From: Lukas Waslowski Date: Mon, 20 May 2024 21:18:56 +0000 Subject: [PATCH 19/38] WMultiLineTextEdit: Style like QLineEdit (including the focus frame) --- src/widget/wmultilinetextedit.cpp | 68 +++++++++++++++++++++++++++++++ src/widget/wmultilinetextedit.h | 4 ++ 2 files changed, 72 insertions(+) diff --git a/src/widget/wmultilinetextedit.cpp b/src/widget/wmultilinetextedit.cpp index 092439f1640..2c7dd4fdce8 100644 --- a/src/widget/wmultilinetextedit.cpp +++ b/src/widget/wmultilinetextedit.cpp @@ -1,11 +1,22 @@ #include "widget/wmultilinetextedit.h" #include +#include +#include +#include #include "moc_wmultilinetextedit.cpp" +#include "wmultilinetextedit.h" WMultiLineTextEdit::WMultiLineTextEdit(QWidget* parent) : QPlainTextEdit(parent) { + // The added viewportMargin is required to ensure the inner + // content of the text editor does not accidentally overwrite + // the focus frame of the whole control. The documentMargin is + // reduced by an equal amount so the total amount of padding + // stays the same. + setViewportMargins(4, 4, 4, 4); + document()->setDocumentMargin(0); } QSize WMultiLineTextEdit::minimumSizeHint() const { @@ -25,3 +36,60 @@ QSize WMultiLineTextEdit::sizeHintImpl(const int minLines) const { return QSizeF(w, h).toSize(); } + +bool WMultiLineTextEdit::event(QEvent* e) { + switch (e->type()) { + case QEvent::Paint: { + QStylePainter p(this); + QStyleOptionFrame option; + initStyleOption(&option); + if (isReadOnly()) { + option.state |= QStyle::State_ReadOnly; + } + style()->drawPrimitive(QStyle::PE_PanelLineEdit, &option, &p, this); + return true; + } + default: { + return QPlainTextEdit::event(e); + } + } +} + +void WMultiLineTextEdit::keyPressEvent(QKeyEvent* event) { + const bool isUp = event->key() == Qt::Key_Up; + const bool isDown = event->key() == Qt::Key_Down; + + // Do not interpret as navigation if any modifier key is pressed + const bool anyModifiersPressed = event->modifiers() & + (Qt::ControlModifier | Qt::AltModifier | + Qt::ShiftModifier | Qt::MetaModifier); + + // Holding down a key to scroll all the way to the + // top or bottom of the text edit should not cause + // the focus to leave the text edit control. + const bool isAutoRepeat = event->isAutoRepeat(); + + if (!m_upDownChangesFocus || !(isUp || isDown) || + isAutoRepeat || anyModifiersPressed) { + QPlainTextEdit::keyPressEvent(event); + } else { + // Up/Down should only cause a focus change when the edge + // of the text box has been reached i.e. when the text + // cursor position didn't change due to the keypress. + auto oldCursor = textCursor(); + QPlainTextEdit::keyPressEvent(event); + auto newCursor = textCursor(); + + const bool cursorHasNotChanged = oldCursor.position() == newCursor.position() && + oldCursor.anchor() == newCursor.anchor(); + + if (cursorHasNotChanged && isUp && focusPreviousChild()) { + event->accept(); + return; + } + if (cursorHasNotChanged && isDown && focusNextChild()) { + event->accept(); + return; + } + } +} diff --git a/src/widget/wmultilinetextedit.h b/src/widget/wmultilinetextedit.h index a24de83bf97..1ba414fbbea 100644 --- a/src/widget/wmultilinetextedit.h +++ b/src/widget/wmultilinetextedit.h @@ -12,6 +12,10 @@ class WMultiLineTextEdit : public QPlainTextEdit { QSize minimumSizeHint() const override; QSize sizeHint() const override; + protected: + bool event(QEvent* e) override; + void keyPressEvent(QKeyEvent* event) override; + private: QSize sizeHintImpl(const int minLines) const; }; From fe5c1f91c711a624f34b5db483afeaef529252c2 Mon Sep 17 00:00:00 2001 From: Lukas Waslowski Date: Fri, 17 May 2024 17:37:54 +0000 Subject: [PATCH 20/38] DlgTrackInfo/Sizing: Add WBasicPushButton to elide text --- CMakeLists.txt | 1 + src/library/dlgtrackinfo.ui | 29 ++++++++++++-- src/widget/wbasicpushbutton.cpp | 68 +++++++++++++++++++++++++++++++++ src/widget/wbasicpushbutton.h | 28 ++++++++++++++ 4 files changed, 123 insertions(+), 3 deletions(-) create mode 100644 src/widget/wbasicpushbutton.cpp create mode 100644 src/widget/wbasicpushbutton.h diff --git a/CMakeLists.txt b/CMakeLists.txt index d8993d6b949..c91139282ed 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1251,6 +1251,7 @@ add_library(mixxx-lib STATIC EXCLUDE_FROM_ALL src/widget/paintable.cpp src/widget/wanalysislibrarytableview.cpp src/widget/wbasewidget.cpp + src/widget/wbasicpushbutton.cpp src/widget/wbattery.cpp src/widget/wbeatspinbox.cpp src/widget/wcolorpicker.cpp diff --git a/src/library/dlgtrackinfo.ui b/src/library/dlgtrackinfo.ui index 480a42564bc..bcf5f948e5d 100644 --- a/src/library/dlgtrackinfo.ui +++ b/src/library/dlgtrackinfo.ui @@ -408,17 +408,35 @@ - + Import Metadata from MusicBrainz + + Qt::ElideLeft + + + + 0 + 0 + + - + Re-Import Metadata from file + + Qt::ElideLeft + + + + 0 + 0 + + @@ -428,7 +446,7 @@ - 40 + 0 10 @@ -1062,6 +1080,11 @@ Often results in higher quality beatgrids, but will not do well on tracks that h + + WBasicPushButton + QPushButton +
widget/wbasicpushbutton.h
+
WMultiLineTextEdit QLineEdit diff --git a/src/widget/wbasicpushbutton.cpp b/src/widget/wbasicpushbutton.cpp new file mode 100644 index 00000000000..bbb93c5370a --- /dev/null +++ b/src/widget/wbasicpushbutton.cpp @@ -0,0 +1,68 @@ +#include "widget/wbasicpushbutton.h" + +#include +#include +#include + +#include "moc_wbasicpushbutton.cpp" + +namespace { +void elideButtonLabelIfNeeded(QStyleOptionButton& option, + QStyle* style, + QWidget* widget, + Qt::TextElideMode elideMode) { + if (elideMode == Qt::ElideNone) { + return; + } + + // Calculate how much space we have left for the text + QSize textSize = style->subElementRect(QStyle::SE_PushButtonContents, &option, widget).size(); + + if (option.features & QStyleOptionButton::HasMenu) { + int indicatorSize = style->pixelMetric(QStyle::PM_MenuButtonIndicator, &option, widget); + textSize.setWidth(textSize.width() - indicatorSize); + } + + if (!option.icon.isNull()) { + int iconSpacing = 4; // ### 4 is currently hardcoded in QPushButton::sizeHint() + textSize.setWidth(textSize.width() - option.iconSize.width() - iconSpacing); + } + + // Replace overflowing text with ellipsis ("...") + option.text = option.fontMetrics.elidedText(option.text, elideMode, textSize.width()); +} +} // namespace + +WBasicPushButton::WBasicPushButton(QWidget* pParent) + : QPushButton(pParent), + m_elideMode(Qt::ElideNone) { +} + +void WBasicPushButton::setElideMode(Qt::TextElideMode elideMode) { + if (elideMode != m_elideMode) { + m_elideMode = elideMode; + updateGeometry(); + } +} + +QSize WBasicPushButton::minimumSizeHint() const { + QSize fullSize = sizeHint(); + + if (m_elideMode == Qt::ElideNone) { + // Elision of overflowing text is disabled, + // so this button cannot be collapsed beyond + // its default size. + return fullSize; + } else { + // Elision of overflowing text is enabled. + return QSize(0, fullSize.height()); + } +} + +void WBasicPushButton::paintEvent(QPaintEvent* /*unused*/) { + QStylePainter p(this); + QStyleOptionButton option; + initStyleOption(&option); + elideButtonLabelIfNeeded(option, p.style(), this, m_elideMode); + p.drawControl(QStyle::CE_PushButton, option); +} diff --git a/src/widget/wbasicpushbutton.h b/src/widget/wbasicpushbutton.h new file mode 100644 index 00000000000..25ef50954c5 --- /dev/null +++ b/src/widget/wbasicpushbutton.h @@ -0,0 +1,28 @@ +#pragma once + +#include + +/// Subclass of QPushButton that replaces a portion of the button label +/// with an ellipsis (according to Qt::TextElideMode) when the text would +/// otherwise overflow the available space. +/// +/// See WPushButton when you need to connect to a ControlObject. +class WBasicPushButton : public QPushButton { + Q_OBJECT + Q_PROPERTY(Qt::TextElideMode elideMode READ elideMode WRITE setElideMode); + + public: + explicit WBasicPushButton(QWidget* pParent = nullptr); + + void setElideMode(Qt::TextElideMode elideMode); + Qt::TextElideMode elideMode() const { + return m_elideMode; + }; + + QSize minimumSizeHint() const override; + + protected: + void paintEvent(QPaintEvent* e) override; + + Qt::TextElideMode m_elideMode; +}; From 395697b4ea47bc710e0e9c09d056a6b8f35a0a9c Mon Sep 17 00:00:00 2001 From: Lukas Waslowski Date: Fri, 17 May 2024 19:44:29 +0000 Subject: [PATCH 21/38] WBasicPushButton: Automatically generate tooltips when button is smaller than contents --- src/widget/wbasicpushbutton.cpp | 47 +++++++++++++++++++++++++++++++++ src/widget/wbasicpushbutton.h | 2 ++ 2 files changed, 49 insertions(+) diff --git a/src/widget/wbasicpushbutton.cpp b/src/widget/wbasicpushbutton.cpp index bbb93c5370a..e5ad31a1b60 100644 --- a/src/widget/wbasicpushbutton.cpp +++ b/src/widget/wbasicpushbutton.cpp @@ -3,6 +3,7 @@ #include #include #include +#include #include "moc_wbasicpushbutton.cpp" @@ -66,3 +67,49 @@ void WBasicPushButton::paintEvent(QPaintEvent* /*unused*/) { elideButtonLabelIfNeeded(option, p.style(), this, m_elideMode); p.drawControl(QStyle::CE_PushButton, option); } + +QString WBasicPushButton::buildToolTip() const { + // Show the button label as a tooltip when the label text + // is partially hidden due to the button's size + + QString txtToolTip = toolTip(); + + if (!txtToolTip.isEmpty()) { + return txtToolTip; + } + + QString txtLabel = text(); + QSize currentSize = size(); + QSize fullSize = sizeHint(); + + if ((currentSize.height() < fullSize.height() || + currentSize.width() < fullSize.width()) && + !txtLabel.isEmpty()) { + // The label text is not fully visible, + // so show it as a tooltip + return txtLabel; + } + + return QString(); +} + +bool WBasicPushButton::event(QEvent* e) { + switch (e->type()) { + case QEvent::ToolTip: { + QString toolTipToShow = buildToolTip(); + if (!toolTipToShow.isEmpty()) { + QToolTip::showText(static_cast(e)->globalPos(), + toolTipToShow, + this, + QRect(), + toolTipDuration()); + } else { + e->ignore(); + } + return true; + } + default: { + return QPushButton::event(e); + } + } +} diff --git a/src/widget/wbasicpushbutton.h b/src/widget/wbasicpushbutton.h index 25ef50954c5..99750d0de8a 100644 --- a/src/widget/wbasicpushbutton.h +++ b/src/widget/wbasicpushbutton.h @@ -22,6 +22,8 @@ class WBasicPushButton : public QPushButton { QSize minimumSizeHint() const override; protected: + QString buildToolTip() const; + bool event(QEvent* e) override; void paintEvent(QPaintEvent* e) override; Qt::TextElideMode m_elideMode; From 4085793ff5f14a9f3bb6646bebf26073a7d1a70b Mon Sep 17 00:00:00 2001 From: Lukas Waslowski Date: Sun, 19 May 2024 18:27:34 +0000 Subject: [PATCH 22/38] DlgTrackInfo/UpDown: Change focus when pressing Up/Down on WBasicLineEdit --- CMakeLists.txt | 1 + src/library/dlgtrackinfo.ui | 25 +++++++++++++++---------- src/widget/wbasiclineedit.cpp | 33 +++++++++++++++++++++++++++++++++ src/widget/wbasiclineedit.h | 15 +++++++++++++++ 4 files changed, 64 insertions(+), 10 deletions(-) create mode 100644 src/widget/wbasiclineedit.cpp create mode 100644 src/widget/wbasiclineedit.h diff --git a/CMakeLists.txt b/CMakeLists.txt index c91139282ed..ecb7f84620e 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1251,6 +1251,7 @@ add_library(mixxx-lib STATIC EXCLUDE_FROM_ALL src/widget/paintable.cpp src/widget/wanalysislibrarytableview.cpp src/widget/wbasewidget.cpp + src/widget/wbasiclineedit.cpp src/widget/wbasicpushbutton.cpp src/widget/wbattery.cpp src/widget/wbeatspinbox.cpp diff --git a/src/library/dlgtrackinfo.ui b/src/library/dlgtrackinfo.ui index bcf5f948e5d..2b33cfdd55e 100644 --- a/src/library/dlgtrackinfo.ui +++ b/src/library/dlgtrackinfo.ui @@ -75,7 +75,7 @@
- + 0 @@ -131,7 +131,7 @@ - + 0 @@ -163,7 +163,7 @@ - + 0 @@ -195,7 +195,7 @@ - + 0 @@ -237,7 +237,7 @@ - + 0 @@ -263,7 +263,7 @@ - + 0 @@ -283,7 +283,7 @@ - + 0 @@ -309,7 +309,7 @@ - + 0 @@ -335,7 +335,7 @@ - + 0 @@ -361,7 +361,7 @@ - + 0 @@ -1080,6 +1080,11 @@ Often results in higher quality beatgrids, but will not do well on tracks that h + + WBasicLineEdit + QLineEdit +
widget/wbasiclineedit.h
+
WBasicPushButton QPushButton diff --git a/src/widget/wbasiclineedit.cpp b/src/widget/wbasiclineedit.cpp new file mode 100644 index 00000000000..ce579c2e331 --- /dev/null +++ b/src/widget/wbasiclineedit.cpp @@ -0,0 +1,33 @@ +#include "widget/wbasiclineedit.h" + +#include + +#include "moc_wbasiclineedit.cpp" + +WBasicLineEdit::WBasicLineEdit(QWidget* parent) + : QLineEdit(parent) { +} + +WBasicLineEdit::WBasicLineEdit(const QString& text, QWidget* parent) + : QLineEdit(text, parent) { +} + +void WBasicLineEdit::keyPressEvent(QKeyEvent* event) { + bool noModifiersPressed = !(event->modifiers() & + (Qt::ControlModifier | Qt::AltModifier | + Qt::ShiftModifier | Qt::MetaModifier)); + + if (event->key() == Qt::Key_Up && noModifiersPressed) { + if (focusPreviousChild()) { + event->accept(); + return; + } + } else if (event->key() == Qt::Key_Down && noModifiersPressed) { + if (focusNextChild()) { + event->accept(); + return; + } + } + + QLineEdit::keyPressEvent(event); +} diff --git a/src/widget/wbasiclineedit.h b/src/widget/wbasiclineedit.h new file mode 100644 index 00000000000..2df30c9253a --- /dev/null +++ b/src/widget/wbasiclineedit.h @@ -0,0 +1,15 @@ +#pragma once + +#include + +/// Subclass of QLineEdit that allows the Up and Down arrow keys +/// to be used like the Tab/Backtab keys. +class WBasicLineEdit : public QLineEdit { + Q_OBJECT + public: + explicit WBasicLineEdit(QWidget* parent = nullptr); + explicit WBasicLineEdit(const QString& text, QWidget* parent = nullptr); + + protected: + void keyPressEvent(QKeyEvent* event) override; +}; From 239717d135964288973fdca1e2865bbeccc214ca Mon Sep 17 00:00:00 2001 From: Lukas Waslowski Date: Mon, 20 May 2024 10:46:51 +0000 Subject: [PATCH 23/38] DlgTrackInfo/UpDown: Change focus when pressing Up/Down on WMultiLineTextField --- src/library/dlgtrackinfo.ui | 3 +++ src/widget/wmultilinetextedit.cpp | 3 ++- src/widget/wmultilinetextedit.h | 13 +++++++++++++ 3 files changed, 18 insertions(+), 1 deletion(-) diff --git a/src/library/dlgtrackinfo.ui b/src/library/dlgtrackinfo.ui index 2b33cfdd55e..6e471767491 100644 --- a/src/library/dlgtrackinfo.ui +++ b/src/library/dlgtrackinfo.ui @@ -391,6 +391,9 @@ true + + true + Qt::ScrollBarAlwaysOff diff --git a/src/widget/wmultilinetextedit.cpp b/src/widget/wmultilinetextedit.cpp index 2c7dd4fdce8..4e2dd8e38d2 100644 --- a/src/widget/wmultilinetextedit.cpp +++ b/src/widget/wmultilinetextedit.cpp @@ -9,7 +9,8 @@ #include "wmultilinetextedit.h" WMultiLineTextEdit::WMultiLineTextEdit(QWidget* parent) - : QPlainTextEdit(parent) { + : QPlainTextEdit(parent), + m_upDownChangesFocus(false) { // The added viewportMargin is required to ensure the inner // content of the text editor does not accidentally overwrite // the focus frame of the whole control. The documentMargin is diff --git a/src/widget/wmultilinetextedit.h b/src/widget/wmultilinetextedit.h index 1ba414fbbea..127dceaa44e 100644 --- a/src/widget/wmultilinetextedit.h +++ b/src/widget/wmultilinetextedit.h @@ -6,9 +6,21 @@ /// size of 2 text lines. class WMultiLineTextEdit : public QPlainTextEdit { Q_OBJECT + Q_PROPERTY(bool upDownChangesFocus READ upDownChangesFocus WRITE setUpDownChangesFocus) public: WMultiLineTextEdit(QWidget* parent = nullptr); + + /// Sets whether to change focus to the next/previous sibling control + /// when the Up/Down arrow keys are pressed while the cursor is at + /// the very end or very start of the control. + void setUpDownChangesFocus(bool enable) { + m_upDownChangesFocus = enable; + } + bool upDownChangesFocus() const { + return m_upDownChangesFocus; + } + QSize minimumSizeHint() const override; QSize sizeHint() const override; @@ -18,4 +30,5 @@ class WMultiLineTextEdit : public QPlainTextEdit { private: QSize sizeHintImpl(const int minLines) const; + bool m_upDownChangesFocus; }; From c6a016dfdb487be735502a7179fd3eff24456e00 Mon Sep 17 00:00:00 2001 From: Lukas Waslowski Date: Mon, 20 May 2024 14:26:46 +0200 Subject: [PATCH 24/38] DlgTrackInfo/UpDown: Change focus when pressing Up/Down on WStarRating --- src/library/dlgtrackinfo.ui | 3 +++ src/widget/wstarrating.cpp | 17 +++++++++++++++++ src/widget/wstarrating.h | 14 ++++++++++++++ 3 files changed, 34 insertions(+) diff --git a/src/library/dlgtrackinfo.ui b/src/library/dlgtrackinfo.ui index 6e471767491..97ed8c234fe 100644 --- a/src/library/dlgtrackinfo.ui +++ b/src/library/dlgtrackinfo.ui @@ -215,6 +215,9 @@ true + + true + Qt::StrongFocus diff --git a/src/widget/wstarrating.cpp b/src/widget/wstarrating.cpp index 8bb37bcceaf..680d0079a1d 100644 --- a/src/widget/wstarrating.cpp +++ b/src/widget/wstarrating.cpp @@ -11,6 +11,7 @@ class QWidgets; WStarRating::WStarRating(QWidget* pParent) : WWidget(pParent), + m_upDownChangesFocus(false), m_focusedViaKeyboard(false), m_starCount(0), m_visualStarRating(m_starCount) { @@ -146,6 +147,22 @@ void WStarRating::keyPressEvent(QKeyEvent* event) { newRating--; break; } + case Qt::Key_Up: { + if (m_upDownChangesFocus && focusPreviousChild()) { + event->accept(); + } else { + event->ignore(); + } + return; + } + case Qt::Key_Down: { + if (m_upDownChangesFocus && focusNextChild()) { + event->accept(); + } else { + event->ignore(); + } + return; + } default: { event->ignore(); return; diff --git a/src/widget/wstarrating.h b/src/widget/wstarrating.h index ef18246fdb1..07c18c721be 100644 --- a/src/widget/wstarrating.h +++ b/src/widget/wstarrating.h @@ -8,10 +8,23 @@ class SkinContext; class WStarRating : public WWidget { Q_OBJECT + Q_PROPERTY(bool upDownChangesFocus READ upDownChangesFocus WRITE setUpDownChangesFocus) + public: WStarRating(QWidget* pParent); virtual void setup(const QDomNode& node, const SkinContext& context); + + /// Sets whether to change focus to the next/previous sibling control + /// when the Up/Down arrow keys are pressed while the cursor is at + /// the very end or very start of the control. + void setUpDownChangesFocus(bool enable) { + m_upDownChangesFocus = enable; + } + bool upDownChangesFocus() const { + return m_upDownChangesFocus; + } + QSize sizeHint() const override; public slots: @@ -31,6 +44,7 @@ class WStarRating : public WWidget { void fillDebugTooltip(QStringList* debug) override; private: + bool m_upDownChangesFocus; bool m_focusedViaKeyboard; int m_starCount; From c83f4cb349cb30d472b20e084f9a78cbe4ca5218 Mon Sep 17 00:00:00 2001 From: Lukas Waslowski Date: Mon, 20 May 2024 21:35:04 +0000 Subject: [PATCH 25/38] DlgTrackInfo/UpDown: Change focus when pressing Up/Down on WBasicTabWidget --- CMakeLists.txt | 1 + src/library/dlgtrackinfo.ui | 7 ++++++- src/widget/wbasictabwidget.cpp | 29 +++++++++++++++++++++++++++++ src/widget/wbasictabwidget.h | 14 ++++++++++++++ 4 files changed, 50 insertions(+), 1 deletion(-) create mode 100644 src/widget/wbasictabwidget.cpp create mode 100644 src/widget/wbasictabwidget.h diff --git a/CMakeLists.txt b/CMakeLists.txt index ecb7f84620e..f057251ac2c 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1253,6 +1253,7 @@ add_library(mixxx-lib STATIC EXCLUDE_FROM_ALL src/widget/wbasewidget.cpp src/widget/wbasiclineedit.cpp src/widget/wbasicpushbutton.cpp + src/widget/wbasictabwidget.cpp src/widget/wbattery.cpp src/widget/wbeatspinbox.cpp src/widget/wcolorpicker.cpp diff --git a/src/library/dlgtrackinfo.ui b/src/library/dlgtrackinfo.ui index 97ed8c234fe..cefecdc5af3 100644 --- a/src/library/dlgtrackinfo.ui +++ b/src/library/dlgtrackinfo.ui @@ -27,7 +27,7 @@ - + 0 @@ -1096,6 +1096,11 @@ Often results in higher quality beatgrids, but will not do well on tracks that h QPushButton
widget/wbasicpushbutton.h
+ + WBasicTabWidget + QTabWidget +
widget/wbasictabwidget.h
+
WMultiLineTextEdit QLineEdit diff --git a/src/widget/wbasictabwidget.cpp b/src/widget/wbasictabwidget.cpp new file mode 100644 index 00000000000..7f8ede1e92f --- /dev/null +++ b/src/widget/wbasictabwidget.cpp @@ -0,0 +1,29 @@ +#include "widget/wbasictabwidget.h" + +#include + +#include "moc_wbasictabwidget.cpp" + +WBasicTabWidget::WBasicTabWidget(QWidget* parent) + : QTabWidget(parent) { +} + +void WBasicTabWidget::keyPressEvent(QKeyEvent* event) { + bool noModifiersPressed = !(event->modifiers() & + (Qt::ControlModifier | Qt::AltModifier | + Qt::ShiftModifier | Qt::MetaModifier)); + + if (event->key() == Qt::Key_Up && noModifiersPressed) { + if (focusPreviousChild()) { + event->accept(); + return; + } + } else if (event->key() == Qt::Key_Down && noModifiersPressed) { + if (focusNextChild()) { + event->accept(); + return; + } + } + + QTabWidget::keyPressEvent(event); +} diff --git a/src/widget/wbasictabwidget.h b/src/widget/wbasictabwidget.h new file mode 100644 index 00000000000..3c66b10f6ee --- /dev/null +++ b/src/widget/wbasictabwidget.h @@ -0,0 +1,14 @@ +#pragma once + +#include + +/// Subclass of QTabWidget that allows the Up and Down arrow keys +/// to be used like the Tab/Backtab keys. +class WBasicTabWidget : public QTabWidget { + Q_OBJECT + public: + explicit WBasicTabWidget(QWidget* parent = nullptr); + + protected: + void keyPressEvent(QKeyEvent* event) override; +}; From c0ff99571f7b3192dcd14545307cc9901fce643f Mon Sep 17 00:00:00 2001 From: Lukas Waslowski Date: Tue, 21 May 2024 12:03:43 +0200 Subject: [PATCH 26/38] DlgTrackInfo/UpDown: Change focus when pressing Up/Down on WBasicLabel --- CMakeLists.txt | 1 + src/library/dlgtrackinfo.ui | 23 ++++++++++++++--------- src/widget/wbasiclabel.cpp | 32 ++++++++++++++++++++++++++++++++ src/widget/wbasiclabel.h | 19 +++++++++++++++++++ 4 files changed, 66 insertions(+), 9 deletions(-) create mode 100644 src/widget/wbasiclabel.cpp create mode 100644 src/widget/wbasiclabel.h diff --git a/CMakeLists.txt b/CMakeLists.txt index f057251ac2c..426e1e00558 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1251,6 +1251,7 @@ add_library(mixxx-lib STATIC EXCLUDE_FROM_ALL src/widget/paintable.cpp src/widget/wanalysislibrarytableview.cpp src/widget/wbasewidget.cpp + src/widget/wbasiclabel.cpp src/widget/wbasiclineedit.cpp src/widget/wbasicpushbutton.cpp src/widget/wbasictabwidget.cpp diff --git a/src/library/dlgtrackinfo.ui b/src/library/dlgtrackinfo.ui index cefecdc5af3..f0765541544 100644 --- a/src/library/dlgtrackinfo.ui +++ b/src/library/dlgtrackinfo.ui @@ -524,7 +524,7 @@
- + 75 @@ -550,7 +550,7 @@ - + @@ -601,7 +601,7 @@
- + 75 @@ -617,7 +617,7 @@ - + 75 @@ -633,7 +633,7 @@ - + 75 @@ -656,7 +656,7 @@ - + 75 @@ -686,7 +686,7 @@ - + 75 @@ -702,7 +702,7 @@ - + 75 @@ -725,7 +725,7 @@ - + 75 @@ -1086,6 +1086,11 @@ Often results in higher quality beatgrids, but will not do well on tracks that h + + WBasicLabel + QLabel +
widget/wbasiclabel.h
+
WBasicLineEdit QLineEdit diff --git a/src/widget/wbasiclabel.cpp b/src/widget/wbasiclabel.cpp new file mode 100644 index 00000000000..21934feea26 --- /dev/null +++ b/src/widget/wbasiclabel.cpp @@ -0,0 +1,32 @@ +#include "widget/wbasiclabel.h" + +#include + +#include "moc_wbasiclabel.cpp" + +WBasicLabel::WBasicLabel(QWidget* parent, Qt::WindowFlags f) + : QLabel(parent, f) { +} +WBasicLabel::WBasicLabel(const QString& text, QWidget* parent, Qt::WindowFlags f) + : QLabel(text, parent, f) { +} + +void WBasicLabel::keyPressEvent(QKeyEvent* event) { + bool noModifiersPressed = !(event->modifiers() & + (Qt::ControlModifier | Qt::AltModifier | + Qt::ShiftModifier | Qt::MetaModifier)); + + if (event->key() == Qt::Key_Up && noModifiersPressed) { + if (focusPreviousChild()) { + event->accept(); + return; + } + } else if (event->key() == Qt::Key_Down && noModifiersPressed) { + if (focusNextChild()) { + event->accept(); + return; + } + } + + QLabel::keyPressEvent(event); +} diff --git a/src/widget/wbasiclabel.h b/src/widget/wbasiclabel.h new file mode 100644 index 00000000000..cb6538e51e9 --- /dev/null +++ b/src/widget/wbasiclabel.h @@ -0,0 +1,19 @@ +#pragma once + +#include + +/// Subclass of QLabel that allows the Up and Down arrow keys +/// to be used like the Tab/Backtab keys. +/// +/// See WLabel when you need to connect to a ControlObject. +class WBasicLabel : public QLabel { + Q_OBJECT + public: + explicit WBasicLabel(QWidget* parent = nullptr, Qt::WindowFlags f = Qt::WindowFlags()); + explicit WBasicLabel(const QString& text, + QWidget* parent = nullptr, + Qt::WindowFlags f = Qt::WindowFlags()); + + protected: + void keyPressEvent(QKeyEvent* event) override; +}; From a169351a8cbe83abf6f649791e47173963d81632 Mon Sep 17 00:00:00 2001 From: Lukas Waslowski Date: Tue, 21 May 2024 11:18:18 +0000 Subject: [PATCH 27/38] DlgTrackInfo/UpDown: Sort WBasicLabel controls by visual & tab order This is needed to avoid breaking keyboard navigation in a few cases. --- src/library/dlgtrackinfo.ui | 212 +++++++++++++++++++----------------- 1 file changed, 111 insertions(+), 101 deletions(-) diff --git a/src/library/dlgtrackinfo.ui b/src/library/dlgtrackinfo.ui index f0765541544..ab9cfc81d36 100644 --- a/src/library/dlgtrackinfo.ui +++ b/src/library/dlgtrackinfo.ui @@ -509,22 +509,15 @@ - - - - BPM: - - - - - + + - Filetype: + Duration: - - + + 75 @@ -539,69 +532,38 @@ - - + + - Location: - - - Qt::AlignLeading|Qt::AlignLeft|Qt::AlignTop + BPM: - - + + + + + 75 + true + + - - true - Qt::LinksAccessibleByMouse|Qt::TextSelectableByKeyboard|Qt::TextSelectableByMouse - - - - Bitrate: - - - - - + + - Duration: + Date added: - - - - - - Open in File Browser - - - - - - - Qt::Horizontal - - - - 40 - 10 - - - - - - - - + + 75 @@ -616,8 +578,15 @@ - - + + + + Last played: + + + + + 75 @@ -632,8 +601,15 @@ - - + + + + Filetype: + + + + + 75 @@ -648,15 +624,15 @@ - - + + - Last played: + Bitrate: - - + + 75 @@ -671,22 +647,15 @@ - - - - ReplayGain: - - - - - + + - Date added: + Samplerate: - - + + 75 @@ -701,8 +670,15 @@ - - + + + + ReplayGain: + + + + + 75 @@ -717,29 +693,53 @@ - - + + - Samplerate: + Location: + + + Qt::AlignLeading|Qt::AlignLeft|Qt::AlignTop - - - - - 75 - true - - + + + + true + Qt::LinksAccessibleByMouse|Qt::TextSelectableByKeyboard|Qt::TextSelectableByMouse + + + + + + Open in File Browser + + + + + + + Qt::Horizontal + + + + 40 + 10 + + + + + + @@ -811,7 +811,7 @@ Often results in higher quality beatgrids, but will not do well on tracks that h
- + 125 @@ -827,7 +827,7 @@ Often results in higher quality beatgrids, but will not do well on tracks that h - + 125 @@ -843,7 +843,7 @@ Often results in higher quality beatgrids, but will not do well on tracks that h - + 125 @@ -859,7 +859,7 @@ Often results in higher quality beatgrids, but will not do well on tracks that h - + 125 @@ -875,7 +875,7 @@ Often results in higher quality beatgrids, but will not do well on tracks that h - + 125 @@ -891,7 +891,7 @@ Often results in higher quality beatgrids, but will not do well on tracks that h - + 125 @@ -907,7 +907,7 @@ Often results in higher quality beatgrids, but will not do well on tracks that h - + 121 @@ -940,7 +940,7 @@ Often results in higher quality beatgrids, but will not do well on tracks that h - + Clear BPM and Beatgrid @@ -1134,6 +1134,16 @@ Often results in higher quality beatgrids, but will not do well on tracks that h btnImportMetadataFromMusicBrainz btnImportMetadataFromFile btnColorPicker + txtDuration + txtBpm + txtDateAdded + txtDateLastPlayed + txtType + txtBpm + txtBitrate + txtSamplerate + txtReplayGain + txtLocation btnOpenFileBrowser spinBpm bpmConst From 5b2424d5b5d6b0b2ccc7c34851f8b49782fdf88c Mon Sep 17 00:00:00 2001 From: Lukas Waslowski Date: Mon, 20 May 2024 22:02:06 +0000 Subject: [PATCH 28/38] DlgTrackInfo/ColorPicker: Avoid double-triggering the color picker popup The menu is already automatically opened by QPushButton::pressed, no need to do it twice. This caused problems when Enter is used to open the color picker popup. --- src/library/dlgtrackinfo.cpp | 11 ----------- src/library/dlgtrackinfo.h | 1 - 2 files changed, 12 deletions(-) diff --git a/src/library/dlgtrackinfo.cpp b/src/library/dlgtrackinfo.cpp index a7d26069503..12f974022bb 100644 --- a/src/library/dlgtrackinfo.cpp +++ b/src/library/dlgtrackinfo.cpp @@ -293,10 +293,6 @@ void DlgTrackInfo::init() { pColorPickerMenu->addAction(m_pColorPicker); btnColorPicker->setMenu(pColorPickerMenu); - connect(btnColorPicker, - &QPushButton::clicked, - this, - &DlgTrackInfo::slotColorButtonClicked); connect(m_pColorPicker.get(), &WColorPickerAction::colorPicked, this, @@ -599,13 +595,6 @@ void DlgTrackInfo::slotOpenInFileBrowser() { mixxx::DesktopHelper::openInFileBrowser(QStringList(m_pLoadedTrack->getLocation())); } -void DlgTrackInfo::slotColorButtonClicked() { - if (!m_pLoadedTrack) { - return; - } - btnColorPicker->showMenu(); -} - void DlgTrackInfo::trackColorDialogSetColor(const mixxx::RgbColor::optional_t& newColor) { m_pColorPicker->setSelectedColor(newColor); btnColorPicker->menu()->close(); diff --git a/src/library/dlgtrackinfo.h b/src/library/dlgtrackinfo.h index 81f55995d1d..e33e79e1157 100644 --- a/src/library/dlgtrackinfo.h +++ b/src/library/dlgtrackinfo.h @@ -67,7 +67,6 @@ class DlgTrackInfo : public QDialog, public Ui::DlgTrackInfo { void slotTrackChanged(TrackId trackId); void slotOpenInFileBrowser(); - void slotColorButtonClicked(); void slotCoverFound( const QObject* pRequester, From d23e53d8ae2203a3c58f5000f80381a3188343b7 Mon Sep 17 00:00:00 2001 From: Lukas Waslowski Date: Mon, 20 May 2024 22:26:08 +0000 Subject: [PATCH 29/38] WColorPicker: Fix oversight in idealColumnCount --- src/widget/wcolorpicker.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/widget/wcolorpicker.cpp b/src/widget/wcolorpicker.cpp index ebcf2262338..38ffa21ab71 100644 --- a/src/widget/wcolorpicker.cpp +++ b/src/widget/wcolorpicker.cpp @@ -29,7 +29,7 @@ inline int idealColumnCount(int numItems) { break; } if (remainder > numColumnsRemainder) { - numColumnsRemainder = numColumnsCandidate; + numColumnsRemainder = remainder; numColumns = numColumnsCandidate; } } From 42f0b145da7074f93b83cc4e20ae74f4136c9fc8 Mon Sep 17 00:00:00 2001 From: Lukas Waslowski Date: Sun, 19 May 2024 19:30:21 +0000 Subject: [PATCH 30/38] WColorPicker: Allow keyboard navigation in the color picker popup --- CMakeLists.txt | 1 + src/library/dlgtrackinfo.cpp | 16 ++- src/library/dlgtrackinfo.h | 7 +- src/widget/wcolorpicker.cpp | 144 +++++++++++++++++++++----- src/widget/wcolorpicker.h | 25 ++++- src/widget/wcolorpickeractionmenu.cpp | 58 +++++++++++ src/widget/wcolorpickeractionmenu.h | 33 ++++++ 7 files changed, 246 insertions(+), 38 deletions(-) create mode 100644 src/widget/wcolorpickeractionmenu.cpp create mode 100644 src/widget/wcolorpickeractionmenu.h diff --git a/CMakeLists.txt b/CMakeLists.txt index 426e1e00558..739edb78747 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1259,6 +1259,7 @@ add_library(mixxx-lib STATIC EXCLUDE_FROM_ALL src/widget/wbeatspinbox.cpp src/widget/wcolorpicker.cpp src/widget/wcolorpickeraction.cpp + src/widget/wcolorpickeractionmenu.cpp src/widget/wcombobox.cpp src/widget/wcoverart.cpp src/widget/wcoverartlabel.cpp diff --git a/src/library/dlgtrackinfo.cpp b/src/library/dlgtrackinfo.cpp index 12f974022bb..9df47494588 100644 --- a/src/library/dlgtrackinfo.cpp +++ b/src/library/dlgtrackinfo.cpp @@ -20,6 +20,7 @@ #include "util/datetime.h" #include "util/desktophelper.h" #include "util/duration.h" +#include "widget/wcolorpickeractionmenu.h" #include "widget/wcoverartlabel.h" #include "widget/wcoverartmenu.h" #include "widget/wstarrating.h" @@ -46,7 +47,7 @@ DlgTrackInfo::DlgTrackInfo( m_tapFilter(this, kFilterLength, kMaxInterval), m_pWCoverArtMenu(make_parented(this)), m_pWCoverArtLabel(make_parented(this, m_pWCoverArtMenu)), - m_pColorPicker(make_parented( + m_pColorPicker(make_parented( WColorPicker::Option::AllowNoColor | // TODO(xxx) remove this once the preferences are themed via QSS WColorPicker::Option::NoExtStyleSheet, @@ -55,6 +56,13 @@ DlgTrackInfo::DlgTrackInfo( init(); } +DlgTrackInfo::~DlgTrackInfo() { + // ~parented_ptr() needs the definition of the wrapped type + // upon deletion! Otherwise the behavior is undefined. + // The wrapped types of some parented_ptr members are only + // forward declared in the header file. +} + void DlgTrackInfo::init() { setupUi(this); setWindowIcon(QIcon(MIXXX_ICON_PATH)); @@ -289,12 +297,10 @@ void DlgTrackInfo::init() { &DlgTrackInfo::slotRatingChanged); btnColorPicker->setStyle(QStyleFactory::create(QStringLiteral("fusion"))); - QMenu* pColorPickerMenu = new QMenu(this); - pColorPickerMenu->addAction(m_pColorPicker); - btnColorPicker->setMenu(pColorPickerMenu); + btnColorPicker->setMenu(m_pColorPicker.get()); connect(m_pColorPicker.get(), - &WColorPickerAction::colorPicked, + &WColorPickerActionMenu::colorPicked, this, [this](const mixxx::RgbColor::optional_t& newColor) { trackColorDialogSetColor(newColor); diff --git a/src/library/dlgtrackinfo.h b/src/library/dlgtrackinfo.h index e33e79e1157..9975787df38 100644 --- a/src/library/dlgtrackinfo.h +++ b/src/library/dlgtrackinfo.h @@ -12,10 +12,9 @@ #include "track/trackrecord.h" #include "util/parented_ptr.h" #include "util/tapfilter.h" -#include "widget/wcolorpickeraction.h" class TrackModel; -class WColorPickerAction; +class WColorPickerActionMenu; class WStarRating; class WCoverArtMenu; class WCoverArtLabel; @@ -32,7 +31,7 @@ class DlgTrackInfo : public QDialog, public Ui::DlgTrackInfo { explicit DlgTrackInfo( UserSettingsPointer pUserSettings, const TrackModel* trackModel = nullptr); - ~DlgTrackInfo() override = default; + ~DlgTrackInfo() override; public slots: // Not thread safe. Only invoke via AutoConnection or QueuedConnection, not @@ -120,7 +119,7 @@ class DlgTrackInfo : public QDialog, public Ui::DlgTrackInfo { parented_ptr m_pWCoverArtMenu; parented_ptr m_pWCoverArtLabel; - parented_ptr m_pColorPicker; + parented_ptr m_pColorPicker; std::unique_ptr m_pDlgTagFetcher; }; diff --git a/src/widget/wcolorpicker.cpp b/src/widget/wcolorpicker.cpp index 38ffa21ab71..615714f218b 100644 --- a/src/widget/wcolorpicker.cpp +++ b/src/widget/wcolorpicker.cpp @@ -2,11 +2,13 @@ #include #include +#include #include #include #include #include "moc_wcolorpicker.cpp" +#include "util/optional.h" #include "util/parented_ptr.h" namespace { @@ -37,6 +39,106 @@ inline int idealColumnCount(int numItems) { return numColumns; } +WColorGridButton::WColorGridButton(const mixxx::RgbColor::optional_t& color, + int row, + int column, + QWidget* parent) + : QPushButton(parent), m_color(color), m_row(row), m_column(column) { + if (color) { + // Set the background color of the button. + // This can't be overridden in skin stylesheets. + setStyleSheet( + QString("QPushButton { background-color: %1; }") + .arg(mixxx::RgbColor::toQString(color.value()))); + setToolTip(mixxx::RgbColor::toQString(color.value())); + } else { + setProperty("noColor", true); + setToolTip(tr("No color")); + } + + setCheckable(true); + + // Without this the button might shrink when setting the checkmark icon, + // both here or via external stylesheets. + setSizePolicy(QSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding)); +} + +void WColorGridButton::keyPressEvent(QKeyEvent* event) { + if (handleNavigation(event)) { + // Already handled completely + } else if (event->key() == Qt::Key_Return) { + // Key_Return should act the same as Key_Space + setDown(true); + } else { + QPushButton::keyPressEvent(event); + } +} + +void WColorGridButton::keyReleaseEvent(QKeyEvent* event) { + if (event->key() == Qt::Key_Return && !event->isAutoRepeat() && isDown()) { + click(); + } else { + QPushButton::keyReleaseEvent(event); + } +} + +bool WColorGridButton::handleNavigation(QKeyEvent* event) { + QWidget* pParent = qobject_cast(parent()); + if (!pParent) { + return false; + } + + QGridLayout* pGridLayout = qobject_cast(pParent->layout()); + if (!pGridLayout) { + return false; + } + + const int maxRow = pGridLayout->rowCount() - 1; + const int maxColumn = pGridLayout->columnCount() - 1; + int newRow = m_row; + int newColumn = m_column; + + switch (event->key()) { + case Qt::Key_Up: { + newRow = qBound(0, newRow - 1, maxRow); + break; + } + case Qt::Key_Down: { + newRow = qBound(0, newRow + 1, maxRow); + break; + } + case Qt::Key_Left: { + newColumn = qBound(0, newColumn - 1, maxColumn); + break; + } + case Qt::Key_Right: { + newColumn = qBound(0, newColumn + 1, maxColumn); + break; + } + default: { + return false; + } + } + + // Show the keyboard focus frame (if not yet visible) + window()->setAttribute(Qt::WA_KeyboardFocusChange); + + QLayoutItem* pNewItem = pGridLayout->itemAtPosition(newRow, newColumn); + if (!pNewItem) { + // May happen when itemCount < (rowCount * columnCount), + // i.e. when some cells in the grid are empty. + return false; + } + + QWidget* pNewFocus = pNewItem->widget(); + if (!pNewFocus) { + return false; + } + + pNewFocus->setFocus(); + return true; +} + WColorPicker::WColorPicker(Options options, const ColorPalette& palette, QWidget* parent) : QWidget(parent), m_options(options), @@ -138,21 +240,11 @@ void WColorPicker::addColorButtons() { } void WColorPicker::addColorButton(mixxx::RgbColor color, QGridLayout* pLayout, int row, int column) { - parented_ptr pButton = make_parented("", this); + auto pButton = make_parented(color, row, column, 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, @@ -163,25 +255,21 @@ void WColorPicker::addColorButton(mixxx::RgbColor color, QGridLayout* pLayout, i } void WColorPicker::addNoColorButton(QGridLayout* pLayout, int row, int column) { - QPushButton* pButton = m_pNoColorButton; - if (!pButton) { - pButton = make_parented("", this); - if (m_pStyle) { - pButton->setStyle(m_pStyle); - } + VERIFY_OR_DEBUG_ASSERT(!m_pNoColorButton) { + return; + } - 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; + auto pButton = make_parented(std::nullopt, row, column, this); + if (m_pStyle) { + pButton->setStyle(m_pStyle); } + connect(pButton, + &QPushButton::clicked, + this, + [this]() { + emit colorPicked(std::nullopt); + }); + m_pNoColorButton = pButton; pLayout->addWidget(pButton, row, column); } diff --git a/src/widget/wcolorpicker.h b/src/widget/wcolorpicker.h index 0250f87a6e0..7f8016c3ae7 100644 --- a/src/widget/wcolorpicker.h +++ b/src/widget/wcolorpicker.h @@ -1,5 +1,7 @@ #pragma once +#include +#include #include #include @@ -7,7 +9,28 @@ #include "util/parented_ptr.h" class QGridLayout; -class QPushButton; +class WColorPicker; + +/// Customized button used internally by WColorPicker +class WColorGridButton : public QPushButton { + Q_OBJECT + public: + WColorGridButton(const mixxx::RgbColor::optional_t& color, + int row, + int column, + QWidget* parent = nullptr); + + protected: + void keyPressEvent(QKeyEvent* event) override; + void keyReleaseEvent(QKeyEvent* event) override; + + private: + bool handleNavigation(QKeyEvent* event); + + mixxx::RgbColor::optional_t m_color; + int m_row; + int m_column; +}; class WColorPicker : public QWidget { Q_OBJECT diff --git a/src/widget/wcolorpickeractionmenu.cpp b/src/widget/wcolorpickeractionmenu.cpp new file mode 100644 index 00000000000..4d47eac41cc --- /dev/null +++ b/src/widget/wcolorpickeractionmenu.cpp @@ -0,0 +1,58 @@ +#include "widget/wcolorpickeractionmenu.h" + +#include + +#include "moc_wcolorpickeractionmenu.cpp" +#include "widget/wcolorpickeraction.h" + +WColorPickerActionMenu::WColorPickerActionMenu( + WColorPicker::Options options, + const ColorPalette& palette, + QWidget* parent) + : QMenu(parent), + m_pColorPickerAction( + make_parented(options, palette, this)) { + connect(m_pColorPickerAction.get(), + &WColorPickerAction::colorPicked, + this, + &WColorPickerActionMenu::colorPicked); + + addAction(m_pColorPickerAction.get()); +} + +void WColorPickerActionMenu::setColorPalette(const ColorPalette& palette) { + m_pColorPickerAction->setColorPalette(palette); + updateGeometry(); +} + +void WColorPickerActionMenu::setSelectedColor(const mixxx::RgbColor::optional_t& color) { + m_pColorPickerAction->setSelectedColor(color); +} + +void WColorPickerActionMenu::resetSelectedColor() { + m_pColorPickerAction->resetSelectedColor(); +} + +bool WColorPickerActionMenu::focusNextPrevChild(bool next) { + // Override the behavior of QMenu::focusNextPrevChild + // which would convert this into a keyPressEvent() + return QWidget::focusNextPrevChild(next); +} + +void WColorPickerActionMenu::keyPressEvent(QKeyEvent* event) { + qDebug() << "WColorPickerActionMenu::keyPressEvent()" << event << focusWidget() + << m_pColorPickerAction->defaultWidget()->hasFocus() + << m_pColorPickerAction->defaultWidget()->focusPolicy() + << m_pColorPickerAction->defaultWidget()->focusWidget(); + if (event->key() == Qt::Key_F) { + m_pColorPickerAction->defaultWidget()->setFocus(); + event->accept(); + return; + } + if (event->key() == Qt::Key_A) { + setActiveAction(m_pColorPickerAction); + event->accept(); + return; + } + QWidget::keyPressEvent(event); +} diff --git a/src/widget/wcolorpickeractionmenu.h b/src/widget/wcolorpickeractionmenu.h new file mode 100644 index 00000000000..989796aa655 --- /dev/null +++ b/src/widget/wcolorpickeractionmenu.h @@ -0,0 +1,33 @@ +#pragma once + +#include + +#include "util/color/colorpalette.h" +#include "util/color/rgbcolor.h" +#include "widget/wcolorpicker.h" + +class WColorPickerAction; + +class WColorPickerActionMenu : public QMenu { + Q_OBJECT + public: + explicit WColorPickerActionMenu( + WColorPicker::Options options, + const ColorPalette& palette, + QWidget* parent = nullptr); + + /// Set a new color palette for the underlying color picker. + void setColorPalette(const ColorPalette& palette); + void setSelectedColor(const mixxx::RgbColor::optional_t& color); + void resetSelectedColor(); + + signals: + void colorPicked(const mixxx::RgbColor::optional_t& color); + + protected: + bool focusNextPrevChild(bool next) override; + void keyPressEvent(QKeyEvent* event) override; + + private: + parented_ptr m_pColorPickerAction; +}; From 3589e575e8869aee0123ca9ee7cefa68bc63dc2d Mon Sep 17 00:00:00 2001 From: Lukas Waslowski Date: Tue, 21 May 2024 09:48:31 +0000 Subject: [PATCH 31/38] WColorPicker: Set initially focused widget of color picker popup --- src/widget/wcolorpicker.cpp | 19 +++++++++++++++++++ src/widget/wcolorpicker.h | 1 + src/widget/wcolorpickeraction.cpp | 4 ++++ src/widget/wcolorpickeraction.h | 1 + src/widget/wcolorpickeractionmenu.cpp | 1 + 5 files changed, 26 insertions(+) diff --git a/src/widget/wcolorpicker.cpp b/src/widget/wcolorpicker.cpp index 615714f218b..53bb9d32da7 100644 --- a/src/widget/wcolorpicker.cpp +++ b/src/widget/wcolorpicker.cpp @@ -347,3 +347,22 @@ void WColorPicker::setColorPalette(const ColorPalette& palette) { void WColorPicker::slotColorPicked(const mixxx::RgbColor::optional_t& color) { setSelectedColor(color); } + +void WColorPicker::setInitialFocus() { + QGridLayout* pLayout = qobject_cast(layout()); + VERIFY_OR_DEBUG_ASSERT(pLayout) { + qWarning() << "Color Picker has no layout!"; + return; + } + + // Focus the top left button when the color picker + // popup is opened, so that keyboard navigation + // can be used. + auto* topLeftItem = pLayout->itemAtPosition(0, 0); + if (topLeftItem) { + auto* topLeftWidget = topLeftItem->widget(); + if (topLeftWidget) { + topLeftWidget->setFocus(); + } + } +} diff --git a/src/widget/wcolorpicker.h b/src/widget/wcolorpicker.h index 7f8016c3ae7..bf4e867f3c1 100644 --- a/src/widget/wcolorpicker.h +++ b/src/widget/wcolorpicker.h @@ -53,6 +53,7 @@ class WColorPicker : public QWidget { void resetSelectedColor(); void setSelectedColor(const mixxx::RgbColor::optional_t& color); void setColorPalette(const ColorPalette& palette); + void setInitialFocus(); signals: void colorPicked(const mixxx::RgbColor::optional_t& color); diff --git a/src/widget/wcolorpickeraction.cpp b/src/widget/wcolorpickeraction.cpp index 21cbb48ae22..8c7dee7178c 100644 --- a/src/widget/wcolorpickeraction.cpp +++ b/src/widget/wcolorpickeraction.cpp @@ -35,3 +35,7 @@ void WColorPickerAction::setColorPalette(const ColorPalette& palette) { } pWidget->adjustSize(); } + +void WColorPickerAction::setInitialFocus() { + m_pColorPicker->setInitialFocus(); +} diff --git a/src/widget/wcolorpickeraction.h b/src/widget/wcolorpickeraction.h index 9cd491b86d5..74fecf29333 100644 --- a/src/widget/wcolorpickeraction.h +++ b/src/widget/wcolorpickeraction.h @@ -15,6 +15,7 @@ class WColorPickerAction : public QWidgetAction { void resetSelectedColor(); void setSelectedColor(const mixxx::RgbColor::optional_t& color); + void setInitialFocus(); /// Set a new color palette for the underlying color picker. /// diff --git a/src/widget/wcolorpickeractionmenu.cpp b/src/widget/wcolorpickeractionmenu.cpp index 4d47eac41cc..03cb6a9fabb 100644 --- a/src/widget/wcolorpickeractionmenu.cpp +++ b/src/widget/wcolorpickeractionmenu.cpp @@ -18,6 +18,7 @@ WColorPickerActionMenu::WColorPickerActionMenu( &WColorPickerActionMenu::colorPicked); addAction(m_pColorPickerAction.get()); + m_pColorPickerAction->setInitialFocus(); } void WColorPickerActionMenu::setColorPalette(const ColorPalette& palette) { From dbf2da034851338b6b00dad0e15c2323590ab892 Mon Sep 17 00:00:00 2001 From: Lukas Waslowski Date: Fri, 7 Jun 2024 13:16:43 +0000 Subject: [PATCH 32/38] DlgTrackInfo: Add tooltip for cover image --- src/library/dlgtrackinfo.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/library/dlgtrackinfo.cpp b/src/library/dlgtrackinfo.cpp index 9df47494588..984c60d31f4 100644 --- a/src/library/dlgtrackinfo.cpp +++ b/src/library/dlgtrackinfo.cpp @@ -273,6 +273,10 @@ void DlgTrackInfo::init() { &DlgTrackInfo::slotOpenInFileBrowser); // Cover art + m_pWCoverArtLabel->setToolTip( + tr("Left-click to show larger preview") + "\n" + + tr("Right-click for more options")); + CoverArtCache* pCache = CoverArtCache::instance(); if (pCache) { connect(pCache, From a5ae64e599fa6153a3ae83f7a1bd3ad5fe9cf251 Mon Sep 17 00:00:00 2001 From: Lukas Waslowski Date: Thu, 31 Oct 2024 17:50:30 +0100 Subject: [PATCH 33/38] DlgTrackInfo: Rename meatdata_buttons_layout to metadata_buttons_layout --- src/library/dlgtrackinfo.ui | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/library/dlgtrackinfo.ui b/src/library/dlgtrackinfo.ui index ef6e74c24fe..a7290f34e9f 100644 --- a/src/library/dlgtrackinfo.ui +++ b/src/library/dlgtrackinfo.ui @@ -445,7 +445,7 @@ - + From 5ad242bcf15c0b5a2ff4091106c1c0d9083e5b7b Mon Sep 17 00:00:00 2001 From: Lukas Waslowski Date: Thu, 31 Oct 2024 18:26:32 +0100 Subject: [PATCH 34/38] WColorPicker: Fix code formatting issue in WColorGridButton constructor --- src/widget/wcolorpicker.cpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/widget/wcolorpicker.cpp b/src/widget/wcolorpicker.cpp index 53bb9d32da7..807b8bce47f 100644 --- a/src/widget/wcolorpicker.cpp +++ b/src/widget/wcolorpicker.cpp @@ -43,7 +43,10 @@ WColorGridButton::WColorGridButton(const mixxx::RgbColor::optional_t& color, int row, int column, QWidget* parent) - : QPushButton(parent), m_color(color), m_row(row), m_column(column) { + : QPushButton(parent), + m_color(color), + m_row(row), + m_column(column) { if (color) { // Set the background color of the button. // This can't be overridden in skin stylesheets. From 25c005f65f9f09aca00a16947a5ce1e36f594eab Mon Sep 17 00:00:00 2001 From: Lukas Waslowski Date: Thu, 31 Oct 2024 17:57:10 +0000 Subject: [PATCH 35/38] DlgTrackInfo/Cleanup: Associate "rating" and "color" property names with their corresponding edit controls --- src/library/dlgtrackinfo.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/library/dlgtrackinfo.cpp b/src/library/dlgtrackinfo.cpp index b161ab49722..b3d5f50ff2e 100644 --- a/src/library/dlgtrackinfo.cpp +++ b/src/library/dlgtrackinfo.cpp @@ -77,12 +77,14 @@ void DlgTrackInfo::init() { m_propertyWidgets.insert("album_artist", txtAlbumArtist); m_propertyWidgets.insert("composer", txtComposer); m_propertyWidgets.insert("genre", txtGenre); + m_propertyWidgets.insert("rating", starRating); m_propertyWidgets.insert("year", txtYear); m_propertyWidgets.insert("bpm", spinBpm); m_propertyWidgets.insert("tracknumber", txtTrackNumber); m_propertyWidgets.insert("key", txtKey); m_propertyWidgets.insert("grouping", txtGrouping); m_propertyWidgets.insert("comment", txtComment); + m_propertyWidgets.insert("color", btnColorPicker); m_propertyWidgets.insert("datetime_added", txtDateAdded); m_propertyWidgets.insert("duration", txtDuration); m_propertyWidgets.insert("timesplayed", txtDateLastPlayed); From 0f3fefd4d40bfa663e731b0bfcd9a5ef3b26ff2c Mon Sep 17 00:00:00 2001 From: Lukas Waslowski Date: Thu, 31 Oct 2024 21:10:59 +0100 Subject: [PATCH 36/38] DlgTrackInfoMulti/StarRating: Integrate WStarRating into the tab order --- src/library/dlgtrackinfomulti.cpp | 18 +++++------------- src/library/dlgtrackinfomulti.h | 1 - src/library/dlgtrackinfomulti.ui | 27 ++++++++++++++++++--------- 3 files changed, 23 insertions(+), 23 deletions(-) diff --git a/src/library/dlgtrackinfomulti.cpp b/src/library/dlgtrackinfomulti.cpp index 80326da771e..3aa63642134 100644 --- a/src/library/dlgtrackinfomulti.cpp +++ b/src/library/dlgtrackinfomulti.cpp @@ -102,7 +102,6 @@ DlgTrackInfoMulti::DlgTrackInfoMulti(UserSettingsPointer pUserSettings) m_pUserSettings(std::move(pUserSettings)), m_pWCoverArtMenu(make_parented(this)), m_pWCoverArtLabel(make_parented(this, m_pWCoverArtMenu)), - m_pWStarRating(make_parented(this)), m_starRatingModified(false), m_newRating(0), m_colorChanged(false), @@ -223,14 +222,7 @@ void DlgTrackInfoMulti::init() { this, &DlgTrackInfoMulti::slotColorPicked); - // Insert the star rating widget - starsLayout->setAlignment(Qt::AlignRight | Qt::AlignVCenter); - starsLayout->setSpacing(0); - starsLayout->setContentsMargins(0, 0, 0, 0); - starsLayout->insertWidget(0, m_pWStarRating.get()); - // This is necessary to pass on mouseMove events to WStarRating - m_pWStarRating->setMouseTracking(true); - connect(m_pWStarRating, + connect(starRating, &WStarRating::ratingChangeRequest, this, &DlgTrackInfoMulti::slotStarRatingChanged); @@ -303,8 +295,8 @@ void DlgTrackInfoMulti::updateFromTracks() { replaceTrackRecords(trackRecords); // Collect star ratings and track colors - // If track value differs from the current value, add it to the list. - // If new and current are identical, keep only one. + // Check if all tracks have the same value for the rating (resp. color). + // If yes, show that value, if no, show a placeholder value instead. int commonRating = m_trackRecords.first().getRating(); for (const auto& rec : std::as_const(m_trackRecords)) { if (commonRating != rec.getRating()) { @@ -313,7 +305,7 @@ void DlgTrackInfoMulti::updateFromTracks() { } } // Update the star widget - m_pWStarRating->slotSetRating(commonRating); + starRating->slotSetRating(commonRating); m_starRatingModified = false; // Same procedure for the track color @@ -887,7 +879,7 @@ void DlgTrackInfoMulti::trackColorDialogSetColorStyleButton( void DlgTrackInfoMulti::slotStarRatingChanged(int rating) { if (!m_pLoadedTracks.isEmpty() && mixxx::TrackRecord::isValidRating(rating)) { m_starRatingModified = true; - m_pWStarRating->slotSetRating(rating); + starRating->slotSetRating(rating); m_newRating = rating; } } diff --git a/src/library/dlgtrackinfomulti.h b/src/library/dlgtrackinfomulti.h index 5c531127972..bbe943848ed 100644 --- a/src/library/dlgtrackinfomulti.h +++ b/src/library/dlgtrackinfomulti.h @@ -101,7 +101,6 @@ class DlgTrackInfoMulti : public QDialog, public Ui::DlgTrackInfoMulti { parented_ptr m_pWCoverArtMenu; parented_ptr m_pWCoverArtLabel; - parented_ptr m_pWStarRating; bool m_starRatingModified; int m_newRating; bool m_colorChanged; diff --git a/src/library/dlgtrackinfomulti.ui b/src/library/dlgtrackinfomulti.ui index 04b35a92cb4..1949b9a46d1 100644 --- a/src/library/dlgtrackinfomulti.ui +++ b/src/library/dlgtrackinfomulti.ui @@ -194,21 +194,22 @@ - + + + true + + + true + + + Qt::StrongFocus + 0 0 - - - 0 - - - QLayout::SetDefaultConstraint - - @@ -735,6 +736,13 @@ + + + WStarRating + QWidget +
widget/wstarrating.h
+
+
txtTitle txtArtist @@ -744,6 +752,7 @@ txtGenre txtGrouping txtComment + starRating txtYear txtKey txtTrackNumber From 335c4cb07e19b71b9b9a814fe5781e5fd950dea5 Mon Sep 17 00:00:00 2001 From: Lukas Waslowski Date: Sat, 2 Nov 2024 00:47:29 +0100 Subject: [PATCH 37/38] Use QKeyEvent::text() for handling Key_0..9 Co-authored-by: ronso0 --- src/widget/wstarrating.cpp | 51 +++++++++++--------------------------- 1 file changed, 14 insertions(+), 37 deletions(-) diff --git a/src/widget/wstarrating.cpp b/src/widget/wstarrating.cpp index d75ef82642d..8bdce242918 100644 --- a/src/widget/wstarrating.cpp +++ b/src/widget/wstarrating.cpp @@ -96,44 +96,21 @@ void WStarRating::keyPressEvent(QKeyEvent* event) { QKeyEvent* ke = static_cast(event); int newRating = m_visualStarRating.starCount(); switch (ke->key()) { - case Qt::Key_0: { - newRating = 0; - break; - } - case Qt::Key_1: { - newRating = 1; - break; - } - case Qt::Key_2: { - newRating = 2; - break; - } - case Qt::Key_3: { - newRating = 3; - break; - } - case Qt::Key_4: { - newRating = 4; - break; - } - case Qt::Key_5: { - newRating = 5; - break; - } - case Qt::Key_6: { - newRating = 6; - break; - } - case Qt::Key_7: { - newRating = 7; - break; - } - case Qt::Key_8: { - newRating = 8; - break; - } + case Qt::Key_0: + case Qt::Key_1: + case Qt::Key_2: + case Qt::Key_3: + case Qt::Key_4: + case Qt::Key_5: + case Qt::Key_6: + case Qt::Key_7: + case Qt::Key_8: case Qt::Key_9: { - newRating = 9; + bool ok = false; + int keyInt = ke->text().toInt(&ok); + if (ok) { + newRating = keyInt; + } break; } case Qt::Key_Right: From 7266f4d2c120f2caee3359baa00958423efe0f22 Mon Sep 17 00:00:00 2001 From: Lukas Waslowski Date: Sat, 2 Nov 2024 01:18:23 +0100 Subject: [PATCH 38/38] Use 'const' and QStringLiteral where possible Co-authored-by: ronso0 --- src/widget/wbasicpushbutton.cpp | 12 +++++------- src/widget/wcolorpicker.cpp | 2 +- 2 files changed, 6 insertions(+), 8 deletions(-) diff --git a/src/widget/wbasicpushbutton.cpp b/src/widget/wbasicpushbutton.cpp index e5ad31a1b60..9076087c99c 100644 --- a/src/widget/wbasicpushbutton.cpp +++ b/src/widget/wbasicpushbutton.cpp @@ -71,16 +71,14 @@ void WBasicPushButton::paintEvent(QPaintEvent* /*unused*/) { QString WBasicPushButton::buildToolTip() const { // Show the button label as a tooltip when the label text // is partially hidden due to the button's size - - QString txtToolTip = toolTip(); - + const QString txtToolTip = toolTip(); if (!txtToolTip.isEmpty()) { return txtToolTip; } - QString txtLabel = text(); - QSize currentSize = size(); - QSize fullSize = sizeHint(); + const QString txtLabel = text(); + const QSize currentSize = size(); + const QSize fullSize = sizeHint(); if ((currentSize.height() < fullSize.height() || currentSize.width() < fullSize.width()) && @@ -96,7 +94,7 @@ QString WBasicPushButton::buildToolTip() const { bool WBasicPushButton::event(QEvent* e) { switch (e->type()) { case QEvent::ToolTip: { - QString toolTipToShow = buildToolTip(); + const QString toolTipToShow = buildToolTip(); if (!toolTipToShow.isEmpty()) { QToolTip::showText(static_cast(e)->globalPos(), toolTipToShow, diff --git a/src/widget/wcolorpicker.cpp b/src/widget/wcolorpicker.cpp index 807b8bce47f..9325578a2b4 100644 --- a/src/widget/wcolorpicker.cpp +++ b/src/widget/wcolorpicker.cpp @@ -51,7 +51,7 @@ WColorGridButton::WColorGridButton(const mixxx::RgbColor::optional_t& color, // Set the background color of the button. // This can't be overridden in skin stylesheets. setStyleSheet( - QString("QPushButton { background-color: %1; }") + QStringLiteral("QPushButton { background-color: %1; }") .arg(mixxx::RgbColor::toQString(color.value()))); setToolTip(mixxx::RgbColor::toQString(color.value())); } else {