From d1a0c3bb34eb5d697ba43492821c564ba4854109 Mon Sep 17 00:00:00 2001 From: Daniel Poelzleithner Date: Tue, 13 Oct 2020 00:53:22 +0200 Subject: [PATCH 01/23] Use a combobox instead of a lineedit widget and utalize the combobox selection mechanism for restoring and saving search queries. This allows to go back to earlier queries easily and also allows to restore the last search from a different feature. Entries in the combobox are added after a 5 second timeout or when the search is changed via api. Properly query the frame width from the stylesheet and not assume 1. The current data model is only in memory and not saved to disk. --- src/preferences/dialog/dlgpreflibrary.cpp | 2 + src/widget/wsearchlineedit.cpp | 89 +++++++++++++++++------ src/widget/wsearchlineedit.h | 9 ++- 3 files changed, 76 insertions(+), 24 deletions(-) diff --git a/src/preferences/dialog/dlgpreflibrary.cpp b/src/preferences/dialog/dlgpreflibrary.cpp index 5ec3482b91b..5c44684c233 100644 --- a/src/preferences/dialog/dlgpreflibrary.cpp +++ b/src/preferences/dialog/dlgpreflibrary.cpp @@ -277,6 +277,8 @@ void DlgPrefLibrary::slotRemoveDir() { } else if (removeMsgBox.clickedButton() == deleteAllButton) { removalType = Library::RemovalType::PurgeTracks; } else { + // prevent warning depending on build type + Q_UNUSED(leaveUnchangedButton); DEBUG_ASSERT(removeMsgBox.clickedButton() == leaveUnchangedButton); removalType = Library::RemovalType::KeepTracks; } diff --git a/src/widget/wsearchlineedit.cpp b/src/widget/wsearchlineedit.cpp index 89b9ed03414..acf39fccf20 100644 --- a/src/widget/wsearchlineedit.cpp +++ b/src/widget/wsearchlineedit.cpp @@ -1,15 +1,16 @@ +#include "wsearchlineedit.h" + #include +#include #include +#include #include -#include "wsearchlineedit.h" -#include "wskincolor.h" -#include "wwidget.h" - #include "skin/skincontext.h" - #include "util/assert.h" #include "util/logger.h" +#include "wskincolor.h" +#include "wwidget.h" #define ENABLE_TRACE_LOG false @@ -26,7 +27,7 @@ const QString kDisabledText = QStringLiteral("- - -"); inline QString clearButtonStyleSheet(int pxPaddingRight) { DEBUG_ASSERT(pxPaddingRight >= 0); return QString( - QStringLiteral("QLineEdit { padding-right: %1px; }")) + QStringLiteral("WSearchLineEdit { padding-right: %1px; }")) .arg(pxPaddingRight); } @@ -51,6 +52,12 @@ constexpr int WSearchLineEdit::kDefaultDebouncingTimeoutMillis; //static constexpr int WSearchLineEdit::kMaxDebouncingTimeoutMillis; +//static +constexpr int WSearchLineEdit::kSaveTimout; + +//static +constexpr int WSearchLineEdit::kMaxSearchEntries; + //static int WSearchLineEdit::s_debouncingTimeoutMillis = kDefaultDebouncingTimeoutMillis; @@ -60,21 +67,32 @@ void WSearchLineEdit::setDebouncingTimeoutMillis(int debouncingTimeoutMillis) { } WSearchLineEdit::WSearchLineEdit(QWidget* pParent) - : QLineEdit(pParent), - WBaseWidget(this), - m_clearButton(make_parented(this)) { + : QComboBox(pParent), + WBaseWidget(this), + m_clearButton(make_parented(this)) { DEBUG_ASSERT(kEmptySearch.isEmpty()); DEBUG_ASSERT(!kEmptySearch.isNull()); setAcceptDrops(false); + setEditable(true); + setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Fixed); + setIconSize(QSize(0, 0)); + setInsertPolicy(QComboBox::InsertAtTop); //: Shown in the library search bar when it is empty. - setPlaceholderText(tr("Search...")); + lineEdit()->setPlaceholderText(tr("Search...")); m_clearButton->setCursor(Qt::ArrowCursor); m_clearButton->setObjectName(QStringLiteral("SearchClearButton")); - // Assume the qss border is at least 1px wide - m_frameWidth = 1; + // Query style for arrow width and frame border + QStyleOptionComboBox styleArrow; + styleArrow.initFrom(this); + QRect rectArrow(style()->subControlRect( + QStyle::CC_ComboBox, &styleArrow, QStyle::SC_ComboBoxArrow, this)); + + m_dropButtonWidth = rectArrow.width() + 1; + m_frameWidth = style()->pixelMetric(QStyle::PM_DefaultFrameWidth, nullptr, this); + m_clearButton->hide(); connect(m_clearButton, &QAbstractButton::clicked, @@ -94,17 +112,22 @@ WSearchLineEdit::WSearchLineEdit(QWidget* pParent) // Set up a timer to search after a few hundred milliseconds timeout. This // stops us from thrashing the database if you type really fast. m_debouncingTimer.setSingleShot(true); + m_saveTimer.setSingleShot(true); connect(&m_debouncingTimer, &QTimer::timeout, this, &WSearchLineEdit::slotTriggerSearch); + connect(&m_saveTimer, + &QTimer::timeout, + this, + &WSearchLineEdit::slotSaveSearch); connect(this, - &QLineEdit::textChanged, + &QComboBox::currentTextChanged, this, &WSearchLineEdit::slotTextChanged); // When you hit enter, it will trigger or clear the search. - connect(this, + connect(this->lineEdit(), &QLineEdit::returnPressed, this, [this] { @@ -199,7 +222,7 @@ void WSearchLineEdit::setup(const QDomNode& node, const SkinContext& context) { } void WSearchLineEdit::resizeEvent(QResizeEvent* e) { - QLineEdit::resizeEvent(e); + QComboBox::resizeEvent(e); m_innerHeight = this->height() - 2 * m_frameWidth; // Test if this is a vertical resize due to changed library font. // Assuming current button height is innerHeight from last resize, @@ -214,7 +237,7 @@ void WSearchLineEdit::resizeEvent(QResizeEvent* e) { } int top = rect().top() + m_frameWidth; if (layoutDirection() == Qt::LeftToRight) { - m_clearButton->move(rect().right() - m_innerHeight - m_frameWidth, top); + m_clearButton->move(rect().right() - m_innerHeight - m_frameWidth - m_dropButtonWidth, top); } else { m_clearButton->move(m_frameWidth, top); } @@ -223,7 +246,7 @@ void WSearchLineEdit::resizeEvent(QResizeEvent* e) { QString WSearchLineEdit::getSearchText() const { if (isEnabled()) { DEBUG_ASSERT(!text().isNull()); - return text(); + return currentText(); } else { return QString(); } @@ -234,7 +257,7 @@ void WSearchLineEdit::focusInEvent(QFocusEvent* event) { kLogger.trace() << "focusInEvent"; #endif // ENABLE_TRACE_LOG - QLineEdit::focusInEvent(event); + QComboBox::focusInEvent(event); } void WSearchLineEdit::focusOutEvent(QFocusEvent* event) { @@ -242,7 +265,7 @@ void WSearchLineEdit::focusOutEvent(QFocusEvent* event) { kLogger.trace() << "focusOutEvent"; #endif // ENABLE_TRACE_LOG - QLineEdit::focusOutEvent(event); + QComboBox::focusOutEvent(event); if (m_debouncingTimer.isActive()) { // Trigger a pending search before leaving the edit box. // Otherwise the entered text might be ignored and get lost @@ -258,7 +281,7 @@ void WSearchLineEdit::setTextBlockSignals(const QString& text) { << text; #endif // ENABLE_TRACE_LOG blockSignals(true); - setText(text); + setCurrentText(text); blockSignals(false); } @@ -294,6 +317,8 @@ void WSearchLineEdit::slotRestoreSearch(const QString& text) { if (text.isNull()) { slotDisableSearch(); } else { + // we save the current search before we switch to a new text + slotSaveSearch(); enableSearch(text); } } @@ -309,6 +334,25 @@ void WSearchLineEdit::slotTriggerSearch() { emit search(getSearchText()); } +/// saves the current query as selection +void WSearchLineEdit::slotSaveSearch() { + qDebug() << "save search" << findData(currentText(), Qt::DisplayRole); + DEBUG_ASSERT(isEnabled()); + m_saveTimer.stop(); + if (currentText().length()) { + int cIndex = findData(currentText(), Qt::DisplayRole); + if (cIndex == -1) { + insertItem(0, currentText()); + setCurrentIndex(0); + while (count() > kMaxSearchEntries) { + removeItem(kMaxSearchEntries); + } + } else { + setCurrentIndex(cIndex); + } + } +} + void WSearchLineEdit::refreshState() { #if ENABLE_TRACE_LOG kLogger.trace() @@ -365,7 +409,7 @@ bool WSearchLineEdit::event(QEvent* pEvent) { if (pEvent->type() == QEvent::ToolTip) { updateTooltip(); } - return QLineEdit::event(pEvent); + return QComboBox::event(pEvent); } void WSearchLineEdit::slotClearSearch() { @@ -379,7 +423,7 @@ void WSearchLineEdit::slotClearSearch() { // before returning the whole (and probably huge) library. // No need to manually trigger a search at this point! // See also: https://bugs.launchpad.net/mixxx/+bug/1635087 - setText(kEmptySearch); + setCurrentText(kEmptySearch); // Refocus the edit field setFocus(Qt::OtherFocusReason); } @@ -413,6 +457,7 @@ void WSearchLineEdit::slotTextChanged(const QString& text) { // to an invalid value is an expected and valid use case. DEBUG_ASSERT(!m_debouncingTimer.isActive()); } + m_saveTimer.start(kSaveTimout); } void WSearchLineEdit::slotSetShortcutFocus() { diff --git a/src/widget/wsearchlineedit.h b/src/widget/wsearchlineedit.h index f3807ce0032..c4d929c50c4 100644 --- a/src/widget/wsearchlineedit.h +++ b/src/widget/wsearchlineedit.h @@ -1,8 +1,8 @@ #pragma once +#include #include #include -#include #include #include @@ -11,13 +11,15 @@ class SkinContext; -class WSearchLineEdit : public QLineEdit, public WBaseWidget { +class WSearchLineEdit : public QComboBox, public WBaseWidget { Q_OBJECT public: // Delay for triggering a search while typing static constexpr int kMinDebouncingTimeoutMillis = 100; static constexpr int kDefaultDebouncingTimeoutMillis = 300; static constexpr int kMaxDebouncingTimeoutMillis = 9999; + static constexpr int kSaveTimout = 5000; + static constexpr int kMaxSearchEntries = 500; // TODO(XXX): Replace with a public slot static void setDebouncingTimeoutMillis(int debouncingTimeoutMillis); @@ -50,6 +52,7 @@ class WSearchLineEdit : public QLineEdit, public WBaseWidget { void slotTextChanged(const QString& text); void slotTriggerSearch(); + void slotSaveSearch(); private: // TODO(XXX): This setting shouldn't be static and the widget @@ -74,6 +77,8 @@ class WSearchLineEdit : public QLineEdit, public WBaseWidget { int m_frameWidth; int m_innerHeight; + int m_dropButtonWidth; QTimer m_debouncingTimer; + QTimer m_saveTimer; }; From 0d491add4a501ee3e3cd0e7ad7d9f82f219fe865 Mon Sep 17 00:00:00 2001 From: ronso0 Date: Tue, 13 Oct 2020 02:57:44 +0200 Subject: [PATCH 02/23] WSearchLineEdit: apply library font to both QLineEdit and QListView --- res/skins/LateNight/style.qss | 2 +- src/widget/wsearchlineedit.cpp | 3 +++ 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/res/skins/LateNight/style.qss b/res/skins/LateNight/style.qss index 15914816ac9..521282fd8ba 100644 --- a/res/skins/LateNight/style.qss +++ b/res/skins/LateNight/style.qss @@ -15,7 +15,6 @@ WTrackText, WTrackProperty, WBeatSpinBox, QSpinBox, -QComboBox, WLibrary QHeaderView, WLibrary QHeaderView::item, QToolTip, @@ -27,6 +26,7 @@ WCoverArtMenu, WTrackMenu, WTrackMenu QMenu, WOverview /* Hotcue labels in the overview */, +WBeatSpinBox, #spinBoxTransition, WEffectSelector, WEffectSelector QAbstractScrollArea, #fadeModeCombobox, diff --git a/src/widget/wsearchlineedit.cpp b/src/widget/wsearchlineedit.cpp index acf39fccf20..a0b52515cb2 100644 --- a/src/widget/wsearchlineedit.cpp +++ b/src/widget/wsearchlineedit.cpp @@ -467,4 +467,7 @@ void WSearchLineEdit::slotSetShortcutFocus() { // Use the same font as the library table and the sidebar void WSearchLineEdit::slotSetFont(const QFont& font) { setFont(font); + if (lineEdit()) { + lineEdit()->setFont(font); + } } From b992c1716ac7fa278813ce749204e4c8240fafbd Mon Sep 17 00:00:00 2001 From: Daniel Poelzleithner Date: Tue, 13 Oct 2020 11:10:15 +0200 Subject: [PATCH 03/23] Fix resize problem, update history behaviour Update internal metrics to calculate button positions on font changes. Move the new entry to the top of the list when an old entry was found. This way the search behaves more like expected. Avoid duplicates when Enter is pressed. Save new query term if keydown is pressed or popup opened. --- src/widget/wsearchlineedit.cpp | 80 +++++++++++++++++++++++++--------- src/widget/wsearchlineedit.h | 3 ++ 2 files changed, 63 insertions(+), 20 deletions(-) diff --git a/src/widget/wsearchlineedit.cpp b/src/widget/wsearchlineedit.cpp index acf39fccf20..824b7d53698 100644 --- a/src/widget/wsearchlineedit.cpp +++ b/src/widget/wsearchlineedit.cpp @@ -81,17 +81,12 @@ WSearchLineEdit::WSearchLineEdit(QWidget* pParent) //: Shown in the library search bar when it is empty. lineEdit()->setPlaceholderText(tr("Search...")); + installEventFilter(this); m_clearButton->setCursor(Qt::ArrowCursor); m_clearButton->setObjectName(QStringLiteral("SearchClearButton")); // Query style for arrow width and frame border - QStyleOptionComboBox styleArrow; - styleArrow.initFrom(this); - QRect rectArrow(style()->subControlRect( - QStyle::CC_ComboBox, &styleArrow, QStyle::SC_ComboBoxArrow, this)); - - m_dropButtonWidth = rectArrow.width() + 1; - m_frameWidth = style()->pixelMetric(QStyle::PM_DefaultFrameWidth, nullptr, this); + updateStyleMetrics(); m_clearButton->hide(); connect(m_clearButton, @@ -221,8 +216,19 @@ void WSearchLineEdit::setup(const QDomNode& node, const SkinContext& context) { tr("Esc") + " " + tr("Exit search", "Exit search bar and leave focus")); } +void WSearchLineEdit::updateStyleMetrics() { + QStyleOptionComboBox styleArrow; + styleArrow.initFrom(this); + QRect rectArrow(style()->subControlRect( + QStyle::CC_ComboBox, &styleArrow, QStyle::SC_ComboBoxArrow, this)); + + m_dropButtonWidth = rectArrow.width() + 1; + m_frameWidth = style()->pixelMetric(QStyle::PM_DefaultFrameWidth, nullptr, this); +} + void WSearchLineEdit::resizeEvent(QResizeEvent* e) { QComboBox::resizeEvent(e); + updateStyleMetrics(); m_innerHeight = this->height() - 2 * m_frameWidth; // Test if this is a vertical resize due to changed library font. // Assuming current button height is innerHeight from last resize, @@ -239,7 +245,7 @@ void WSearchLineEdit::resizeEvent(QResizeEvent* e) { if (layoutDirection() == Qt::LeftToRight) { m_clearButton->move(rect().right() - m_innerHeight - m_frameWidth - m_dropButtonWidth, top); } else { - m_clearButton->move(m_frameWidth, top); + m_clearButton->move(m_frameWidth + m_dropButtonWidth, top); } } @@ -252,6 +258,25 @@ QString WSearchLineEdit::getSearchText() const { } } +bool WSearchLineEdit::eventFilter(QObject* obj, QEvent* event) { + if (event->type() == QEvent::KeyPress) { + QKeyEvent* keyEvent = static_cast(event); + if (keyEvent->key() == Qt::Key_Down) { + // in case the user entered a new search query + // und presses the down key, save the query for later recall + if (findData(currentText(), Qt::DisplayRole) == -1) { + slotSaveSearch(); + } + } else if (keyEvent->key() == Qt::Key_Enter) { + if (findData(currentText(), Qt::DisplayRole) == -1) { + slotSaveSearch(); + } + return true; + } + } + return QComboBox::eventFilter(obj, event); +} + void WSearchLineEdit::focusInEvent(QFocusEvent* event) { #if ENABLE_TRACE_LOG kLogger.trace() @@ -336,19 +361,22 @@ void WSearchLineEdit::slotTriggerSearch() { /// saves the current query as selection void WSearchLineEdit::slotSaveSearch() { - qDebug() << "save search" << findData(currentText(), Qt::DisplayRole); - DEBUG_ASSERT(isEnabled()); + int cIndex = findData(currentText(), Qt::DisplayRole); + qDebug() << "save search. Index: " << cIndex; m_saveTimer.stop(); - if (currentText().length()) { - int cIndex = findData(currentText(), Qt::DisplayRole); - if (cIndex == -1) { - insertItem(0, currentText()); - setCurrentIndex(0); - while (count() > kMaxSearchEntries) { - removeItem(kMaxSearchEntries); - } - } else { - setCurrentIndex(cIndex); + // entry already exists and is on top + if (cIndex == 0) { + return; + } + if (currentText().length() && isEnabled()) { + // we remove the existing item and add a new one at the top + if (cIndex != -1) { + removeItem(cIndex); + } + insertItem(0, currentText()); + setCurrentIndex(0); + while (count() > kMaxSearchEntries) { + removeItem(kMaxSearchEntries); } } } @@ -365,6 +393,17 @@ void WSearchLineEdit::refreshState() { } } +void WSearchLineEdit::showPopup() { + int cIndex = findData(currentText(), Qt::DisplayRole); + if (cIndex == -1) { + slotSaveSearch(); + } else { + m_saveTimer.stop(); + setCurrentIndex(cIndex); + } + QComboBox::showPopup(); +} + void WSearchLineEdit::updateEditBox(const QString& text) { #if ENABLE_TRACE_LOG kLogger.trace() @@ -466,5 +505,6 @@ void WSearchLineEdit::slotSetShortcutFocus() { // Use the same font as the library table and the sidebar void WSearchLineEdit::slotSetFont(const QFont& font) { + updateStyleMetrics(); setFont(font); } diff --git a/src/widget/wsearchlineedit.h b/src/widget/wsearchlineedit.h index c4d929c50c4..cca0d5237cd 100644 --- a/src/widget/wsearchlineedit.h +++ b/src/widget/wsearchlineedit.h @@ -23,6 +23,7 @@ class WSearchLineEdit : public QComboBox, public WBaseWidget { // TODO(XXX): Replace with a public slot static void setDebouncingTimeoutMillis(int debouncingTimeoutMillis); + virtual void showPopup(); explicit WSearchLineEdit(QWidget* pParent); ~WSearchLineEdit() override = default; @@ -34,6 +35,7 @@ class WSearchLineEdit : public QComboBox, public WBaseWidget { void focusInEvent(QFocusEvent*) override; void focusOutEvent(QFocusEvent*) override; bool event(QEvent*) override; + bool eventFilter(QObject* obj, QEvent* event) override; signals: void search(const QString& text); @@ -67,6 +69,7 @@ class WSearchLineEdit : public QComboBox, public WBaseWidget { void enableSearch(const QString& text); void updateEditBox(const QString& text); void updateClearButton(const QString& text); + void updateStyleMetrics(); QString getSearchText() const; From b74f8501b563b373f06fb5e6a311599dab4b25b4 Mon Sep 17 00:00:00 2001 From: Daniel Poelzleithner Date: Tue, 13 Oct 2020 14:17:36 +0200 Subject: [PATCH 04/23] Implement control object for navigating history Cancle timer when selection changes to prevent history being messed up with arrow keys/controls. --- src/controllers/controlpickermenu.cpp | 23 ++++++++++++++++++- src/library/librarycontrol.cpp | 32 +++++++++++++++++++++++++++ src/library/librarycontrol.h | 5 +++++ src/widget/wsearchlineedit.cpp | 21 ++++++++++++++++++ src/widget/wsearchlineedit.h | 4 ++++ 5 files changed, 84 insertions(+), 1 deletion(-) diff --git a/src/controllers/controlpickermenu.cpp b/src/controllers/controlpickermenu.cpp index 1d03cb0ddbd..abb40ba4ede 100644 --- a/src/controllers/controlpickermenu.cpp +++ b/src/controllers/controlpickermenu.cpp @@ -434,7 +434,28 @@ ControlPickerMenu::ControlPickerMenu(QWidget* pParent) tr("Add to Auto DJ Queue (replace)"), tr("Replace Auto DJ Queue with selected tracks"), libraryMenu, false, m_libraryStr); - + addControl("[Library]", + "search_history_next", + tr("Select next search history"), + tr("Selects the next search history entry"), + libraryMenu, + false, + m_libraryStr); + addControl("[Library]", + "search_history_prev", + tr("Select previous search history"), + tr("Selects the previous search history entry"), + libraryMenu, + false, + m_libraryStr); + addControl("[Library]", + "search_history", + tr("Move selected search entry"), + tr("Moves the seleceted search history item into given direction " + "and steps"), + libraryMenu, + false, + m_libraryStr); // Load track (these can be loaded into any channel) addDeckAndSamplerControl("LoadSelectedTrack", diff --git a/src/library/librarycontrol.cpp b/src/library/librarycontrol.cpp index fb1e5da22a5..8b75e8b7792 100644 --- a/src/library/librarycontrol.cpp +++ b/src/library/librarycontrol.cpp @@ -211,6 +211,38 @@ LibraryControl::LibraryControl(Library* pLibrary) this, &LibraryControl::slotTrackColorNext); + // Control to navigate between widgets (tab/shit+tab button) + m_pSelectHistroyNext = std::make_unique( + ConfigKey("[Library]", "search_history_next")); + m_pSelectHistoryPrev = std::make_unique( + ConfigKey("[Library]", "search_history_prev")); + m_pSelectHistory = std::make_unique( + ConfigKey("[Library]", "search_history_move"), false); + connect(m_pSelectHistroyNext.get(), + &ControlPushButton::valueChanged, + this, + [this]() { + if (m_pSearchbox) { + m_pSearchbox->slotMoveSelectedHistory(1); + } + }); + connect(m_pSelectHistoryPrev.get(), + &ControlPushButton::valueChanged, + this, + [this]() { + if (m_pSearchbox) { + m_pSearchbox->slotMoveSelectedHistory(-1); + } + }); + connect(m_pSelectHistory.get(), + &ControlEncoder::valueChanged, + this, + [this](double direction) { + if (m_pSearchbox) { + m_pSearchbox->slotMoveSelectedHistory(static_cast(direction)); + } + }); + /// Deprecated controls m_pSelectNextTrack = std::make_unique(ConfigKey("[Playlist]", "SelectNextTrack")); connect(m_pSelectNextTrack.get(), diff --git a/src/library/librarycontrol.h b/src/library/librarycontrol.h index dd8046c89ed..647009312d9 100644 --- a/src/library/librarycontrol.h +++ b/src/library/librarycontrol.h @@ -144,6 +144,11 @@ class LibraryControl : public QObject { std::unique_ptr m_pTrackColorPrev; std::unique_ptr m_pTrackColorNext; + // Controls to navigate search history + std::unique_ptr m_pSelectHistroyNext; + std::unique_ptr m_pSelectHistoryPrev; + std::unique_ptr m_pSelectHistory; + // Font sizes std::unique_ptr m_pFontSizeIncrement; std::unique_ptr m_pFontSizeDecrement; diff --git a/src/widget/wsearchlineedit.cpp b/src/widget/wsearchlineedit.cpp index c1dfad0dab3..47a75f60468 100644 --- a/src/widget/wsearchlineedit.cpp +++ b/src/widget/wsearchlineedit.cpp @@ -120,6 +120,10 @@ WSearchLineEdit::WSearchLineEdit(QWidget* pParent) &QComboBox::currentTextChanged, this, &WSearchLineEdit::slotTextChanged); + connect(this, + QOverload::of(&QComboBox::currentIndexChanged), + this, + &WSearchLineEdit::slotIndexChanged); // When you hit enter, it will trigger or clear the search. connect(this->lineEdit(), @@ -381,6 +385,16 @@ void WSearchLineEdit::slotSaveSearch() { } } +void WSearchLineEdit::slotMoveSelectedHistory(int direction) { + int nIndex = currentIndex() + direction; + // we wrap around to the last entry on backwards direction + if (nIndex < -1) { + nIndex = count() - 1; + } + setCurrentIndex(nIndex); + m_saveTimer.stop(); +} + void WSearchLineEdit::refreshState() { #if ENABLE_TRACE_LOG kLogger.trace() @@ -475,6 +489,13 @@ bool WSearchLineEdit::slotClearSearchIfClearButtonHasFocus() { return true; } +void WSearchLineEdit::slotIndexChanged(int index) { + qDebug() << "index changed " << index; + if (index != -1) { + m_saveTimer.stop(); + } +} + void WSearchLineEdit::slotTextChanged(const QString& text) { #if ENABLE_TRACE_LOG kLogger.trace() diff --git a/src/widget/wsearchlineedit.h b/src/widget/wsearchlineedit.h index cca0d5237cd..b85647c98f7 100644 --- a/src/widget/wsearchlineedit.h +++ b/src/widget/wsearchlineedit.h @@ -49,9 +49,13 @@ class WSearchLineEdit : public QComboBox, public WBaseWidget { void slotClearSearch(); bool slotClearSearchIfClearButtonHasFocus(); + /// Select the next/previous entry from the history + void slotMoveSelectedHistory(int direction); + private slots: void slotSetShortcutFocus(); void slotTextChanged(const QString& text); + void slotIndexChanged(int index); void slotTriggerSearch(); void slotSaveSearch(); From 407ae68dba2953749cb3ec00a4ecb3d91991962e Mon Sep 17 00:00:00 2001 From: Daniel Poelzleithner Date: Wed, 14 Oct 2020 22:01:07 +0200 Subject: [PATCH 05/23] Allow tab key emulation to reach search bar again. With combobox reaching the search field is usefull again since it allows you to scroll previous filters. --- src/widget/wsearchlineedit.cpp | 4 ---- 1 file changed, 4 deletions(-) diff --git a/src/widget/wsearchlineedit.cpp b/src/widget/wsearchlineedit.cpp index 47a75f60468..9cde4aeee6d 100644 --- a/src/widget/wsearchlineedit.cpp +++ b/src/widget/wsearchlineedit.cpp @@ -94,10 +94,6 @@ WSearchLineEdit::WSearchLineEdit(QWidget* pParent) this, &WSearchLineEdit::slotClearSearch); - // This prevents the searchbox from being focused by Tab key (real or emulated) - // so it is skipped when using the library controls 'MoveFocus[...]' - // The Clear button can still be focused by Tab. - setFocusPolicy(Qt::ClickFocus); QShortcut* setFocusShortcut = new QShortcut(QKeySequence(tr("Ctrl+F", "Search|Focus")), this); connect(setFocusShortcut, &QShortcut::activated, From 118f4e51adc972584ffce8c26fb2999db73dc7bf Mon Sep 17 00:00:00 2001 From: ronso0 Date: Thu, 15 Oct 2020 21:06:32 +0200 Subject: [PATCH 06/23] WSearchLineEdit: fully enable controllers to scroll previous search queries with [Library],MoveVertical, ..MoveDown & MoveUp controls. --- src/library/librarycontrol.cpp | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/src/library/librarycontrol.cpp b/src/library/librarycontrol.cpp index 8b75e8b7792..fbe78dadab7 100644 --- a/src/library/librarycontrol.cpp +++ b/src/library/librarycontrol.cpp @@ -569,19 +569,27 @@ void LibraryControl::emitKeyEvent(QKeyEvent&& event) { VERIFY_OR_DEBUG_ASSERT(m_pLibraryWidget) { return; } + VERIFY_OR_DEBUG_ASSERT(m_pSearchbox) { + return; + } if (!QApplication::focusWindow()) { qDebug() << "Mixxx window is not focused, don't send key events"; return; } bool keyIsTab = event.key() == static_cast(Qt::Key_Tab); + bool keyIsUpDown = event.key() == static_cast(Qt::Key_Up) || + event.key() == static_cast(Qt::Key_Down); // If the main window has focus, any widget can receive Tab. // Other keys should be sent to library widgets only to not // accidentally alter spinboxes etc. + // If the searchbox has focus allow only Up/Down to select previous queries. if (!keyIsTab && !m_pSidebarWidget->hasFocus() && !m_pLibraryWidget->getActiveView()->hasFocus()) { - setLibraryFocus(); + if (keyIsUpDown && !m_pSearchbox->hasFocus()) { + setLibraryFocus(); + } } if (keyIsTab && !QApplication::focusWidget()){ setLibraryFocus(); From 5797c1455475f003f75dbcfe16af0519beccfad8 Mon Sep 17 00:00:00 2001 From: ronso0 Date: Thu, 15 Oct 2020 21:33:38 +0200 Subject: [PATCH 07/23] WSearchLineEdit: when focused use [Library],GoToItem to jump to tracks table --- src/library/librarycontrol.cpp | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/library/librarycontrol.cpp b/src/library/librarycontrol.cpp index fbe78dadab7..98169df0b79 100644 --- a/src/library/librarycontrol.cpp +++ b/src/library/librarycontrol.cpp @@ -680,6 +680,11 @@ void LibraryControl::slotGoToItem(double v) { return slotLoadSelectedIntoFirstStopped(v); } + // If searchbox has focus jump to the tracks table + if (m_pSearchbox->hasFocus()) { + return setLibraryFocus(); + } + // Clear the search if the searchbox has focus emit clearSearchIfClearButtonHasFocus(); From 11a4a34f7b3322cea376ed927a74bd5ac62fb388 Mon Sep 17 00:00:00 2001 From: Daniel Poelzleithner Date: Sat, 17 Oct 2020 17:59:34 +0200 Subject: [PATCH 08/23] Fix debug assert in searchbox text() does not exist anymore --- src/widget/wsearchlineedit.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/widget/wsearchlineedit.cpp b/src/widget/wsearchlineedit.cpp index 9cde4aeee6d..c6f7a9f1d34 100644 --- a/src/widget/wsearchlineedit.cpp +++ b/src/widget/wsearchlineedit.cpp @@ -251,7 +251,7 @@ void WSearchLineEdit::resizeEvent(QResizeEvent* e) { QString WSearchLineEdit::getSearchText() const { if (isEnabled()) { - DEBUG_ASSERT(!text().isNull()); + DEBUG_ASSERT(!currentText().isNull()); return currentText(); } else { return QString(); From 9424035c629ca7d94692cfdeaea076bcc3f580e1 Mon Sep 17 00:00:00 2001 From: Daniel Poelzleithner Date: Sat, 17 Oct 2020 18:45:10 +0200 Subject: [PATCH 09/23] fix wrong control name --- src/controllers/controlpickermenu.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/controllers/controlpickermenu.cpp b/src/controllers/controlpickermenu.cpp index abb40ba4ede..9705148f25f 100644 --- a/src/controllers/controlpickermenu.cpp +++ b/src/controllers/controlpickermenu.cpp @@ -449,9 +449,9 @@ ControlPickerMenu::ControlPickerMenu(QWidget* pParent) false, m_libraryStr); addControl("[Library]", - "search_history", + "search_history_move", tr("Move selected search entry"), - tr("Moves the seleceted search history item into given direction " + tr("Moves the selected search history item into given direction " "and steps"), libraryMenu, false, From e711dafde849a6f1532f4302937c8e99e7f382ed Mon Sep 17 00:00:00 2001 From: Daniel Poelzleithner Date: Sat, 17 Oct 2020 18:45:41 +0200 Subject: [PATCH 10/23] Clearer variable naming. Remove spam log entries. --- src/preferences/dialog/dlgpreflibrary.cpp | 2 +- src/widget/wsearchlineedit.cpp | 15 ++++++++++----- src/widget/wsearchlineedit.h | 4 ++-- 3 files changed, 13 insertions(+), 8 deletions(-) diff --git a/src/preferences/dialog/dlgpreflibrary.cpp b/src/preferences/dialog/dlgpreflibrary.cpp index 5c44684c233..b9316ac14ea 100644 --- a/src/preferences/dialog/dlgpreflibrary.cpp +++ b/src/preferences/dialog/dlgpreflibrary.cpp @@ -277,7 +277,7 @@ void DlgPrefLibrary::slotRemoveDir() { } else if (removeMsgBox.clickedButton() == deleteAllButton) { removalType = Library::RemovalType::PurgeTracks; } else { - // prevent warning depending on build type + // Only used in DEBUG_ASSERT Q_UNUSED(leaveUnchangedButton); DEBUG_ASSERT(removeMsgBox.clickedButton() == leaveUnchangedButton); removalType = Library::RemovalType::KeepTracks; diff --git a/src/widget/wsearchlineedit.cpp b/src/widget/wsearchlineedit.cpp index c6f7a9f1d34..2e1c0336939 100644 --- a/src/widget/wsearchlineedit.cpp +++ b/src/widget/wsearchlineedit.cpp @@ -53,7 +53,7 @@ constexpr int WSearchLineEdit::kDefaultDebouncingTimeoutMillis; constexpr int WSearchLineEdit::kMaxDebouncingTimeoutMillis; //static -constexpr int WSearchLineEdit::kSaveTimout; +constexpr int WSearchLineEdit::kSaveTimoutMillis; //static constexpr int WSearchLineEdit::kMaxSearchEntries; @@ -271,6 +271,8 @@ bool WSearchLineEdit::eventFilter(QObject* obj, QEvent* event) { if (findData(currentText(), Qt::DisplayRole) == -1) { slotSaveSearch(); } + // The default handler will add the entry to the list, + // this already happened in slotSaveSearch return true; } } @@ -362,13 +364,17 @@ void WSearchLineEdit::slotTriggerSearch() { /// saves the current query as selection void WSearchLineEdit::slotSaveSearch() { int cIndex = findData(currentText(), Qt::DisplayRole); - qDebug() << "save search. Index: " << cIndex; +#if ENABLE_TRACE_LOG + kLogger.trace() + << "save search. Index: " + << cIndex; +#endif // ENABLE_TRACE_LOG m_saveTimer.stop(); // entry already exists and is on top if (cIndex == 0) { return; } - if (currentText().length() && isEnabled()) { + if (!currentText().isEmpty() && isEnabled()) { // we remove the existing item and add a new one at the top if (cIndex != -1) { removeItem(cIndex); @@ -486,7 +492,6 @@ bool WSearchLineEdit::slotClearSearchIfClearButtonHasFocus() { } void WSearchLineEdit::slotIndexChanged(int index) { - qDebug() << "index changed " << index; if (index != -1) { m_saveTimer.stop(); } @@ -513,7 +518,7 @@ void WSearchLineEdit::slotTextChanged(const QString& text) { // to an invalid value is an expected and valid use case. DEBUG_ASSERT(!m_debouncingTimer.isActive()); } - m_saveTimer.start(kSaveTimout); + m_saveTimer.start(kSaveTimoutMillis); } void WSearchLineEdit::slotSetShortcutFocus() { diff --git a/src/widget/wsearchlineedit.h b/src/widget/wsearchlineedit.h index b85647c98f7..17d1221f466 100644 --- a/src/widget/wsearchlineedit.h +++ b/src/widget/wsearchlineedit.h @@ -18,8 +18,8 @@ class WSearchLineEdit : public QComboBox, public WBaseWidget { static constexpr int kMinDebouncingTimeoutMillis = 100; static constexpr int kDefaultDebouncingTimeoutMillis = 300; static constexpr int kMaxDebouncingTimeoutMillis = 9999; - static constexpr int kSaveTimout = 5000; - static constexpr int kMaxSearchEntries = 500; + static constexpr int kSaveTimoutMillis = 5000; + static constexpr int kMaxSearchEntries = 50; // TODO(XXX): Replace with a public slot static void setDebouncingTimeoutMillis(int debouncingTimeoutMillis); From 824bc57d4e567c8881c87f3a817f28ab71548d26 Mon Sep 17 00:00:00 2001 From: Daniel Poelzleithner Date: Sat, 17 Oct 2020 23:04:26 +0200 Subject: [PATCH 11/23] fix typo, rename variable --- src/library/librarycontrol.cpp | 4 ++-- src/library/librarycontrol.h | 2 +- src/widget/wsearchlineedit.cpp | 4 ++-- src/widget/wsearchlineedit.h | 2 +- 4 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/library/librarycontrol.cpp b/src/library/librarycontrol.cpp index 98169df0b79..866b4bc3255 100644 --- a/src/library/librarycontrol.cpp +++ b/src/library/librarycontrol.cpp @@ -216,7 +216,7 @@ LibraryControl::LibraryControl(Library* pLibrary) ConfigKey("[Library]", "search_history_next")); m_pSelectHistoryPrev = std::make_unique( ConfigKey("[Library]", "search_history_prev")); - m_pSelectHistory = std::make_unique( + m_pSelectHistoryMove = std::make_unique( ConfigKey("[Library]", "search_history_move"), false); connect(m_pSelectHistroyNext.get(), &ControlPushButton::valueChanged, @@ -234,7 +234,7 @@ LibraryControl::LibraryControl(Library* pLibrary) m_pSearchbox->slotMoveSelectedHistory(-1); } }); - connect(m_pSelectHistory.get(), + connect(m_pSelectHistoryMove.get(), &ControlEncoder::valueChanged, this, [this](double direction) { diff --git a/src/library/librarycontrol.h b/src/library/librarycontrol.h index 647009312d9..6961cc48edd 100644 --- a/src/library/librarycontrol.h +++ b/src/library/librarycontrol.h @@ -147,7 +147,7 @@ class LibraryControl : public QObject { // Controls to navigate search history std::unique_ptr m_pSelectHistroyNext; std::unique_ptr m_pSelectHistoryPrev; - std::unique_ptr m_pSelectHistory; + std::unique_ptr m_pSelectHistoryMove; // Font sizes std::unique_ptr m_pFontSizeIncrement; diff --git a/src/widget/wsearchlineedit.cpp b/src/widget/wsearchlineedit.cpp index 2e1c0336939..ee18c50824b 100644 --- a/src/widget/wsearchlineedit.cpp +++ b/src/widget/wsearchlineedit.cpp @@ -53,7 +53,7 @@ constexpr int WSearchLineEdit::kDefaultDebouncingTimeoutMillis; constexpr int WSearchLineEdit::kMaxDebouncingTimeoutMillis; //static -constexpr int WSearchLineEdit::kSaveTimoutMillis; +constexpr int WSearchLineEdit::kSaveTimeoutMillis; //static constexpr int WSearchLineEdit::kMaxSearchEntries; @@ -518,7 +518,7 @@ void WSearchLineEdit::slotTextChanged(const QString& text) { // to an invalid value is an expected and valid use case. DEBUG_ASSERT(!m_debouncingTimer.isActive()); } - m_saveTimer.start(kSaveTimoutMillis); + m_saveTimer.start(kSaveTimeoutMillis); } void WSearchLineEdit::slotSetShortcutFocus() { diff --git a/src/widget/wsearchlineedit.h b/src/widget/wsearchlineedit.h index 17d1221f466..94f1610becf 100644 --- a/src/widget/wsearchlineedit.h +++ b/src/widget/wsearchlineedit.h @@ -18,7 +18,7 @@ class WSearchLineEdit : public QComboBox, public WBaseWidget { static constexpr int kMinDebouncingTimeoutMillis = 100; static constexpr int kDefaultDebouncingTimeoutMillis = 300; static constexpr int kMaxDebouncingTimeoutMillis = 9999; - static constexpr int kSaveTimoutMillis = 5000; + static constexpr int kSaveTimeoutMillis = 5000; static constexpr int kMaxSearchEntries = 50; // TODO(XXX): Replace with a public slot From 6d26c2685c3efc2ec89d64690b9313dc6d7e7bd8 Mon Sep 17 00:00:00 2001 From: Daniel Poelzleithner Date: Mon, 26 Oct 2020 23:45:28 +0100 Subject: [PATCH 12/23] Take layout direction into account when writing stylesheet --- src/widget/wsearchlineedit.cpp | 27 ++++++++++++++++++++------- src/widget/wsearchlineedit.h | 2 +- 2 files changed, 21 insertions(+), 8 deletions(-) diff --git a/src/widget/wsearchlineedit.cpp b/src/widget/wsearchlineedit.cpp index 300bd949ce8..b1ebeb2718c 100644 --- a/src/widget/wsearchlineedit.cpp +++ b/src/widget/wsearchlineedit.cpp @@ -24,11 +24,19 @@ const QString kEmptySearch = QStringLiteral(""); const QString kDisabledText = QStringLiteral("- - -"); -inline QString clearButtonStyleSheet(int pxPaddingRight) { +constexpr int kClearbuttonClearence = 1; + +inline QString clearButtonStyleSheet(int pxPaddingRight, Qt::LayoutDirection direction) { DEBUG_ASSERT(pxPaddingRight >= 0); - return QString( - QStringLiteral("WSearchLineEdit { padding-right: %1px; }")) - .arg(pxPaddingRight); + if (direction == Qt::RightToLeft) { + return QString( + QStringLiteral("WSearchLineEdit { padding-left: %1px; }")) + .arg(pxPaddingRight); + } else { + return QString( + QStringLiteral("WSearchLineEdit { padding-right: %1px; }")) + .arg(pxPaddingRight); + } } int verifyDebouncingTimeoutMillis(int debouncingTimeoutMillis) { @@ -134,7 +142,9 @@ WSearchLineEdit::WSearchLineEdit(QWidget* pParent) QSize clearButtonSize = m_clearButton->sizeHint(); // Ensures the text does not obscure the clear image. - setStyleSheet(clearButtonStyleSheet(clearButtonSize.width() + m_frameWidth + 1)); + setStyleSheet(clearButtonStyleSheet( + clearButtonSize.width() + m_frameWidth + kClearbuttonClearence, + layoutDirection())); refreshState(); } @@ -451,12 +461,15 @@ void WSearchLineEdit::updateClearButton(const QString& text) { // Disable while placeholder is shown m_clearButton->setVisible(false); // no right padding - setStyleSheet(clearButtonStyleSheet(0)); + setStyleSheet(clearButtonStyleSheet(0, layoutDirection())); } else { // Enable otherwise m_clearButton->setVisible(true); // make sure the text won't be drawn behind the Clear button icon - setStyleSheet(clearButtonStyleSheet(m_innerHeight + m_frameWidth)); + setStyleSheet(clearButtonStyleSheet( + m_innerHeight + m_dropButtonWidth + + m_frameWidth + kClearbuttonClearence, + layoutDirection())); } } diff --git a/src/widget/wsearchlineedit.h b/src/widget/wsearchlineedit.h index 94f1610becf..50ad28eea23 100644 --- a/src/widget/wsearchlineedit.h +++ b/src/widget/wsearchlineedit.h @@ -23,7 +23,7 @@ class WSearchLineEdit : public QComboBox, public WBaseWidget { // TODO(XXX): Replace with a public slot static void setDebouncingTimeoutMillis(int debouncingTimeoutMillis); - virtual void showPopup(); + virtual void showPopup() override; explicit WSearchLineEdit(QWidget* pParent); ~WSearchLineEdit() override = default; From cec5382cec75ee2a8205baa793637b363e3c63d1 Mon Sep 17 00:00:00 2001 From: Daniel Poelzleithner Date: Tue, 27 Oct 2020 00:15:06 +0100 Subject: [PATCH 13/23] Add ctrl + space to open/close search history --- src/widget/wsearchlineedit.cpp | 30 ++++++++++++++++++++++++------ 1 file changed, 24 insertions(+), 6 deletions(-) diff --git a/src/widget/wsearchlineedit.cpp b/src/widget/wsearchlineedit.cpp index b1ebeb2718c..88630bcbdf0 100644 --- a/src/widget/wsearchlineedit.cpp +++ b/src/widget/wsearchlineedit.cpp @@ -1,5 +1,6 @@ #include "wsearchlineedit.h" +#include #include #include #include @@ -90,6 +91,7 @@ WSearchLineEdit::WSearchLineEdit(QWidget* pParent) //: Shown in the library search bar when it is empty. lineEdit()->setPlaceholderText(tr("Search...")); installEventFilter(this); + view()->installEventFilter(this); m_clearButton->setCursor(Qt::ArrowCursor); m_clearButton->setObjectName(QStringLiteral("SearchClearButton")); @@ -217,12 +219,17 @@ void WSearchLineEdit::setup(const QDomNode& node, const SkinContext& context) { setToolTip(tr("Search", "noun") + "\n" + tr("Enter a string to search for") + "\n" + - tr("Use operators like bpm:115-128, artist:BooFar, -year:1990") + "\n" + - tr("For more information see User Manual > Mixxx Library") + "\n\n" + - - tr("Shortcut") + ": \n" + - tr("Ctrl+F") + " " + tr("Focus", "Give search bar input focus") + "\n" + - tr("Ctrl+Backspace") + " " + tr("Clear input", "Clear the search bar input field") + "\n" + + tr("Use operators like bpm:115-128, artist:BooFar, -year:1990") + + "\n" + tr("For more information see User Manual > Mixxx Library") + + "\n\n" + + tr("Shortcut") + ": \n" + tr("Ctrl+F") + " " + + tr("Focus", "Give search bar input focus") + "\n" + + tr("Ctrl+Backspace") + " " + + tr("Clear input", "Clear the search bar input field") + "\n" + + tr("Ctrl+Space") + " " + + tr("Toggle search history", + "Shows/hides the search history entries") + + "\n" + tr("Esc") + " " + tr("Exit search", "Exit search bar and leave focus")); } @@ -284,6 +291,17 @@ bool WSearchLineEdit::eventFilter(QObject* obj, QEvent* event) { // The default handler will add the entry to the list, // this already happened in slotSaveSearch return true; + } else if (keyEvent->key() == Qt::Key_Space && + keyEvent->modifiers() == Qt::ControlModifier) { + // open popup on ctrl + space + if (view()->isVisible()) { + qDebug() << "should hide"; + hidePopup(); + } else { + qDebug() << "showme"; + showPopup(); + } + return true; } } return QComboBox::eventFilter(obj, event); From db327fdf8fe42e3476937a4d7ae7b818bf2327ee Mon Sep 17 00:00:00 2001 From: Daniel Poelzleithner Date: Tue, 27 Oct 2020 00:19:39 +0100 Subject: [PATCH 14/23] Start search on enter --- src/widget/wsearchlineedit.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/widget/wsearchlineedit.cpp b/src/widget/wsearchlineedit.cpp index 88630bcbdf0..617a04b21e3 100644 --- a/src/widget/wsearchlineedit.cpp +++ b/src/widget/wsearchlineedit.cpp @@ -290,15 +290,14 @@ bool WSearchLineEdit::eventFilter(QObject* obj, QEvent* event) { } // The default handler will add the entry to the list, // this already happened in slotSaveSearch + slotTriggerSearch(); return true; } else if (keyEvent->key() == Qt::Key_Space && keyEvent->modifiers() == Qt::ControlModifier) { // open popup on ctrl + space if (view()->isVisible()) { - qDebug() << "should hide"; hidePopup(); } else { - qDebug() << "showme"; showPopup(); } return true; From 9d995a6e98a0fd66c2f90709c6c99201dee158fa Mon Sep 17 00:00:00 2001 From: Daniel Poelzleithner Date: Tue, 27 Oct 2020 00:51:54 +0100 Subject: [PATCH 15/23] Use function to return current history index. rename directions to steps --- src/library/librarycontrol.cpp | 10 +++++----- src/widget/wsearchlineedit.cpp | 12 ++++++------ src/widget/wsearchlineedit.h | 10 ++++++++-- 3 files changed, 19 insertions(+), 13 deletions(-) diff --git a/src/library/librarycontrol.cpp b/src/library/librarycontrol.cpp index f59b503bb22..464e2717e28 100644 --- a/src/library/librarycontrol.cpp +++ b/src/library/librarycontrol.cpp @@ -222,7 +222,7 @@ LibraryControl::LibraryControl(Library* pLibrary) &ControlPushButton::valueChanged, this, [this]() { - if (m_pSearchbox) { + VERIFY_OR_DEBUG_ASSERT(m_pSearchbox) { m_pSearchbox->slotMoveSelectedHistory(1); } }); @@ -230,16 +230,16 @@ LibraryControl::LibraryControl(Library* pLibrary) &ControlPushButton::valueChanged, this, [this]() { - if (m_pSearchbox) { + VERIFY_OR_DEBUG_ASSERT(m_pSearchbox) { m_pSearchbox->slotMoveSelectedHistory(-1); } }); connect(m_pSelectHistoryMove.get(), &ControlEncoder::valueChanged, this, - [this](double direction) { - if (m_pSearchbox) { - m_pSearchbox->slotMoveSelectedHistory(static_cast(direction)); + [this](double steps) { + VERIFY_OR_DEBUG_ASSERT(m_pSearchbox) { + m_pSearchbox->slotMoveSelectedHistory(static_cast(steps)); } }); diff --git a/src/widget/wsearchlineedit.cpp b/src/widget/wsearchlineedit.cpp index 617a04b21e3..6f004c4e7ee 100644 --- a/src/widget/wsearchlineedit.cpp +++ b/src/widget/wsearchlineedit.cpp @@ -281,11 +281,11 @@ bool WSearchLineEdit::eventFilter(QObject* obj, QEvent* event) { if (keyEvent->key() == Qt::Key_Down) { // in case the user entered a new search query // und presses the down key, save the query for later recall - if (findData(currentText(), Qt::DisplayRole) == -1) { + if (findCurrentTextIndex() == -1) { slotSaveSearch(); } } else if (keyEvent->key() == Qt::Key_Enter) { - if (findData(currentText(), Qt::DisplayRole) == -1) { + if (findCurrentTextIndex() == -1) { slotSaveSearch(); } // The default handler will add the entry to the list, @@ -390,7 +390,7 @@ void WSearchLineEdit::slotTriggerSearch() { /// saves the current query as selection void WSearchLineEdit::slotSaveSearch() { - int cIndex = findData(currentText(), Qt::DisplayRole); + int cIndex = findCurrentTextIndex(); #if ENABLE_TRACE_LOG kLogger.trace() << "save search. Index: " @@ -414,8 +414,8 @@ void WSearchLineEdit::slotSaveSearch() { } } -void WSearchLineEdit::slotMoveSelectedHistory(int direction) { - int nIndex = currentIndex() + direction; +void WSearchLineEdit::slotMoveSelectedHistory(int steps) { + int nIndex = currentIndex() + steps; // we wrap around to the last entry on backwards direction if (nIndex < -1) { nIndex = count() - 1; @@ -437,7 +437,7 @@ void WSearchLineEdit::refreshState() { } void WSearchLineEdit::showPopup() { - int cIndex = findData(currentText(), Qt::DisplayRole); + int cIndex = findCurrentTextIndex(); if (cIndex == -1) { slotSaveSearch(); } else { diff --git a/src/widget/wsearchlineedit.h b/src/widget/wsearchlineedit.h index 50ad28eea23..9709cc8a579 100644 --- a/src/widget/wsearchlineedit.h +++ b/src/widget/wsearchlineedit.h @@ -49,8 +49,10 @@ class WSearchLineEdit : public QComboBox, public WBaseWidget { void slotClearSearch(); bool slotClearSearchIfClearButtonHasFocus(); - /// Select the next/previous entry from the history - void slotMoveSelectedHistory(int direction); + /// The function selects an entry relative to the currently selected + /// entry in the history and executes the search. + /// The parameter specifies the distance in steps (positive/negative = downward/upward) + void slotMoveSelectedHistory(int steps); private slots: void slotSetShortcutFocus(); @@ -75,6 +77,10 @@ class WSearchLineEdit : public QComboBox, public WBaseWidget { void updateClearButton(const QString& text); void updateStyleMetrics(); + inline int findCurrentTextIndex() { + return findData(currentText(), Qt::DisplayRole); + } + QString getSearchText() const; // Update the displayed text without (re-)starting the timer From 0c78b61934f08aea3234dca66e14b3806f442275 Mon Sep 17 00:00:00 2001 From: Daniel Poelzleithner Date: Tue, 27 Oct 2020 00:55:40 +0100 Subject: [PATCH 16/23] remove unnecessary casts --- src/library/librarycontrol.cpp | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/library/librarycontrol.cpp b/src/library/librarycontrol.cpp index 464e2717e28..27f25b0cc3a 100644 --- a/src/library/librarycontrol.cpp +++ b/src/library/librarycontrol.cpp @@ -577,9 +577,8 @@ void LibraryControl::emitKeyEvent(QKeyEvent&& event) { return; } - bool keyIsTab = event.key() == static_cast(Qt::Key_Tab); - bool keyIsUpDown = event.key() == static_cast(Qt::Key_Up) || - event.key() == static_cast(Qt::Key_Down); + bool keyIsTab = event.key() == Qt::Key_Tab; + bool keyIsUpDown = event.key() == Qt::Key_Up || event.key() == Qt::Key_Down; // If the main window has focus, any widget can receive Tab. // Other keys should be sent to library widgets only to not From d108955f42a4ae1cedfbc33b543bb28bb6c58430 Mon Sep 17 00:00:00 2001 From: Daniel Poelzleithner Date: Tue, 27 Oct 2020 01:21:40 +0100 Subject: [PATCH 17/23] fix selection after clearing the search field --- src/widget/wsearchlineedit.cpp | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/src/widget/wsearchlineedit.cpp b/src/widget/wsearchlineedit.cpp index 6f004c4e7ee..3fde5a4c15e 100644 --- a/src/widget/wsearchlineedit.cpp +++ b/src/widget/wsearchlineedit.cpp @@ -279,6 +279,12 @@ bool WSearchLineEdit::eventFilter(QObject* obj, QEvent* event) { if (event->type() == QEvent::KeyPress) { QKeyEvent* keyEvent = static_cast(event); if (keyEvent->key() == Qt::Key_Down) { + // after clearing the text field the down key is expected to + // show the last entry + if (currentText().isEmpty()) { + setCurrentIndex(0); + return true; + } // in case the user entered a new search query // und presses the down key, save the query for later recall if (findCurrentTextIndex() == -1) { @@ -503,6 +509,9 @@ void WSearchLineEdit::slotClearSearch() { << "slotClearSearch"; #endif // ENABLE_TRACE_LOG DEBUG_ASSERT(isEnabled()); + // select the last entry as current before cleaning the text field + // so arrow keys will work as expected + setCurrentIndex(-1); // Clearing the edit field will engage the debouncing timer // and gives the user the chance for entering a new search // before returning the whole (and probably huge) library. From 0b5adb233e32627f4ce76612757f5f29a646974e Mon Sep 17 00:00:00 2001 From: Daniel Poelzleithner Date: Tue, 27 Oct 2020 11:49:38 +0100 Subject: [PATCH 18/23] Rename history search control, fix typo --- src/controllers/controlpickermenu.cpp | 2 +- src/library/librarycontrol.cpp | 23 ++++++++++++++++------- src/library/librarycontrol.h | 4 ++-- 3 files changed, 19 insertions(+), 10 deletions(-) diff --git a/src/controllers/controlpickermenu.cpp b/src/controllers/controlpickermenu.cpp index 89dfee06c86..6c10e95f4da 100644 --- a/src/controllers/controlpickermenu.cpp +++ b/src/controllers/controlpickermenu.cpp @@ -660,7 +660,7 @@ ControlPickerMenu::ControlPickerMenu(QWidget* pParent) false, m_libraryStr); addControl("[Library]", - "search_history_move", + "search_history_selector", tr("Move selected search entry"), tr("Moves the selected search history item into given direction " "and steps"), diff --git a/src/library/librarycontrol.cpp b/src/library/librarycontrol.cpp index 27f25b0cc3a..bc6393e461a 100644 --- a/src/library/librarycontrol.cpp +++ b/src/library/librarycontrol.cpp @@ -212,33 +212,42 @@ LibraryControl::LibraryControl(Library* pLibrary) &LibraryControl::slotTrackColorNext); // Control to navigate between widgets (tab/shit+tab button) - m_pSelectHistroyNext = std::make_unique( + m_pSelectHistoryNext = std::make_unique( ConfigKey("[Library]", "search_history_next")); m_pSelectHistoryPrev = std::make_unique( ConfigKey("[Library]", "search_history_prev")); - m_pSelectHistoryMove = std::make_unique( - ConfigKey("[Library]", "search_history_move"), false); - connect(m_pSelectHistroyNext.get(), + m_pSelectHistorySelect = std::make_unique( + ConfigKey("[Library]", "search_history_selector"), false); + connect(m_pSelectHistoryNext.get(), &ControlPushButton::valueChanged, this, - [this]() { + [this](double value) { VERIFY_OR_DEBUG_ASSERT(m_pSearchbox) { + return; + } + if (value != 0) { m_pSearchbox->slotMoveSelectedHistory(1); } }); connect(m_pSelectHistoryPrev.get(), &ControlPushButton::valueChanged, this, - [this]() { + [this](double value) { VERIFY_OR_DEBUG_ASSERT(m_pSearchbox) { + return; + } + if (value != 0) { m_pSearchbox->slotMoveSelectedHistory(-1); } }); - connect(m_pSelectHistoryMove.get(), + connect(m_pSelectHistorySelect.get(), &ControlEncoder::valueChanged, this, [this](double steps) { VERIFY_OR_DEBUG_ASSERT(m_pSearchbox) { + return; + } + if (steps != 0) { m_pSearchbox->slotMoveSelectedHistory(static_cast(steps)); } }); diff --git a/src/library/librarycontrol.h b/src/library/librarycontrol.h index 6961cc48edd..84d70811c94 100644 --- a/src/library/librarycontrol.h +++ b/src/library/librarycontrol.h @@ -145,9 +145,9 @@ class LibraryControl : public QObject { std::unique_ptr m_pTrackColorNext; // Controls to navigate search history - std::unique_ptr m_pSelectHistroyNext; + std::unique_ptr m_pSelectHistoryNext; std::unique_ptr m_pSelectHistoryPrev; - std::unique_ptr m_pSelectHistoryMove; + std::unique_ptr m_pSelectHistorySelect; // Font sizes std::unique_ptr m_pFontSizeIncrement; From f12cb975c6f4f3bede5272fbc98b306b60ae4d87 Mon Sep 17 00:00:00 2001 From: Daniel Poelzleithner Date: Tue, 27 Oct 2020 14:58:55 +0100 Subject: [PATCH 19/23] Check for values ge 1.0 --- src/library/librarycontrol.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/library/librarycontrol.cpp b/src/library/librarycontrol.cpp index bc6393e461a..23ad03a97e5 100644 --- a/src/library/librarycontrol.cpp +++ b/src/library/librarycontrol.cpp @@ -225,7 +225,7 @@ LibraryControl::LibraryControl(Library* pLibrary) VERIFY_OR_DEBUG_ASSERT(m_pSearchbox) { return; } - if (value != 0) { + if (value >= 1.0) { m_pSearchbox->slotMoveSelectedHistory(1); } }); @@ -236,7 +236,7 @@ LibraryControl::LibraryControl(Library* pLibrary) VERIFY_OR_DEBUG_ASSERT(m_pSearchbox) { return; } - if (value != 0) { + if (value >= 1.0) { m_pSearchbox->slotMoveSelectedHistory(-1); } }); @@ -247,7 +247,7 @@ LibraryControl::LibraryControl(Library* pLibrary) VERIFY_OR_DEBUG_ASSERT(m_pSearchbox) { return; } - if (steps != 0) { + if (steps >= 1.0 || steps <= -1.0) { m_pSearchbox->slotMoveSelectedHistory(static_cast(steps)); } }); From 94dfdb23037ddd936039f6ad3d0ec31d625e083d Mon Sep 17 00:00:00 2001 From: Daniel Poelzleithner Date: Thu, 29 Oct 2020 16:41:14 +0100 Subject: [PATCH 20/23] rename padding argument --- src/widget/wsearchlineedit.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/widget/wsearchlineedit.cpp b/src/widget/wsearchlineedit.cpp index 3fde5a4c15e..40f67285148 100644 --- a/src/widget/wsearchlineedit.cpp +++ b/src/widget/wsearchlineedit.cpp @@ -27,16 +27,16 @@ const QString kDisabledText = QStringLiteral("- - -"); constexpr int kClearbuttonClearence = 1; -inline QString clearButtonStyleSheet(int pxPaddingRight, Qt::LayoutDirection direction) { - DEBUG_ASSERT(pxPaddingRight >= 0); +inline QString clearButtonStyleSheet(int pxPadding, Qt::LayoutDirection direction) { + DEBUG_ASSERT(pxPadding >= 0); if (direction == Qt::RightToLeft) { return QString( QStringLiteral("WSearchLineEdit { padding-left: %1px; }")) - .arg(pxPaddingRight); + .arg(pxPadding); } else { return QString( QStringLiteral("WSearchLineEdit { padding-right: %1px; }")) - .arg(pxPaddingRight); + .arg(pxPadding); } } From 8fdd642bf5d4bdb07bb664309d7c85d7fb363fad Mon Sep 17 00:00:00 2001 From: Daniel Poelzleithner Date: Thu, 29 Oct 2020 16:45:52 +0100 Subject: [PATCH 21/23] make pre commit happy again --- src/controllers/controlpickermenu.cpp | 7 ------- 1 file changed, 7 deletions(-) diff --git a/src/controllers/controlpickermenu.cpp b/src/controllers/controlpickermenu.cpp index 6c10e95f4da..912240f12e8 100644 --- a/src/controllers/controlpickermenu.cpp +++ b/src/controllers/controlpickermenu.cpp @@ -668,13 +668,6 @@ ControlPickerMenu::ControlPickerMenu(QWidget* pParent) false, m_libraryStr); - // Load track (these can be loaded into any channel) - addDeckAndSamplerControl("LoadSelectedTrack", - tr("Load Track"), - tr("Load selected track"), libraryMenu); - addDeckAndSamplerAndPreviewDeckControl("LoadSelectedTrackAndPlay", tr("Track Load and Play"), - tr("Load selected track and play"), libraryMenu); - libraryMenu->addSeparator(); addControl("[Recording]", "toggle_recording", tr("Record Mix"), From 787f7701dccf2be9b416ee991e77674c1cc1995f Mon Sep 17 00:00:00 2001 From: Daniel Poelzleithner Date: Thu, 29 Oct 2020 22:47:47 +0100 Subject: [PATCH 22/23] fix camelcase --- src/widget/wsearchlineedit.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/widget/wsearchlineedit.cpp b/src/widget/wsearchlineedit.cpp index 40f67285148..c325eedecae 100644 --- a/src/widget/wsearchlineedit.cpp +++ b/src/widget/wsearchlineedit.cpp @@ -25,7 +25,7 @@ const QString kEmptySearch = QStringLiteral(""); const QString kDisabledText = QStringLiteral("- - -"); -constexpr int kClearbuttonClearence = 1; +constexpr int kClearButtonClearence = 1; inline QString clearButtonStyleSheet(int pxPadding, Qt::LayoutDirection direction) { DEBUG_ASSERT(pxPadding >= 0); @@ -145,7 +145,7 @@ WSearchLineEdit::WSearchLineEdit(QWidget* pParent) // Ensures the text does not obscure the clear image. setStyleSheet(clearButtonStyleSheet( - clearButtonSize.width() + m_frameWidth + kClearbuttonClearence, + clearButtonSize.width() + m_frameWidth + kClearButtonClearence, layoutDirection())); refreshState(); @@ -491,7 +491,7 @@ void WSearchLineEdit::updateClearButton(const QString& text) { // make sure the text won't be drawn behind the Clear button icon setStyleSheet(clearButtonStyleSheet( m_innerHeight + m_dropButtonWidth + - m_frameWidth + kClearbuttonClearence, + m_frameWidth + kClearButtonClearence, layoutDirection())); } } From 9e29613ef50f544159cbd31a0142aef49d038472 Mon Sep 17 00:00:00 2001 From: Daniel Poelzleithner Date: Thu, 29 Oct 2020 23:10:20 +0100 Subject: [PATCH 23/23] Fix widget size on very long entries in the history --- src/widget/wsearchlineedit.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/widget/wsearchlineedit.cpp b/src/widget/wsearchlineedit.cpp index c325eedecae..70c627fba52 100644 --- a/src/widget/wsearchlineedit.cpp +++ b/src/widget/wsearchlineedit.cpp @@ -87,6 +87,8 @@ WSearchLineEdit::WSearchLineEdit(QWidget* pParent) setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Fixed); setIconSize(QSize(0, 0)); setInsertPolicy(QComboBox::InsertAtTop); + setMinimumSize(0, 0); + setSizeAdjustPolicy(QComboBox::SizeAdjustPolicy::AdjustToMinimumContentsLengthWithIcon); //: Shown in the library search bar when it is empty. lineEdit()->setPlaceholderText(tr("Search..."));