From b3a0542ba75632eea93112bfbd813442f8b6ace0 Mon Sep 17 00:00:00 2001 From: Nikhil Tanwar <2002nikhiltanwar@gmail.com> Date: Sat, 19 Aug 2023 12:21:41 +0530 Subject: [PATCH] Navigate through choices using up,down keys This change allows one to navigate through the choices using up and down arrow keys from keyboard Enter/Return key can be pressed to select the current item --- kiwix-desktop.pro | 2 + resources/css/choiceBox.css | 6 -- src/kiwixchoicebox.cpp | 9 ++- src/kiwixchoicebox.h | 3 +- src/kiwixlistwidget.cpp | 108 ++++++++++++++++++++++++++++++++++++ src/kiwixlistwidget.h | 36 ++++++++++++ src/klistwidgetitem.cpp | 30 ++++++++-- src/klistwidgetitem.h | 3 + 8 files changed, 184 insertions(+), 13 deletions(-) create mode 100644 src/kiwixlistwidget.cpp create mode 100644 src/kiwixlistwidget.h diff --git a/kiwix-desktop.pro b/kiwix-desktop.pro index e9a148c..3290343 100644 --- a/kiwix-desktop.pro +++ b/kiwix-desktop.pro @@ -45,6 +45,7 @@ SOURCES += \ src/kiwixchoicebox.cpp \ src/kiwixconfirmbox.cpp \ src/kiwixlineedit.cpp \ + src/kiwixlistwidget.cpp \ src/kiwixloader.cpp \ src/rownode.cpp \ src/suggestionlistworker.cpp \ @@ -90,6 +91,7 @@ HEADERS += \ src/kiwixchoicebox.h \ src/kiwixconfirmbox.h \ src/kiwixlineedit.h \ + src/kiwixlistwidget.h \ src/kiwixloader.h \ src/node.h \ src/rownode.h \ diff --git a/resources/css/choiceBox.css b/resources/css/choiceBox.css index 0c6b180..20d85de 100644 --- a/resources/css/choiceBox.css +++ b/resources/css/choiceBox.css @@ -1,5 +1,4 @@ QListWidget::item { - color: #666666; padding: 0; padding-top: 6px; padding-bottom: 6px; @@ -16,11 +15,6 @@ QListWidget::item::selected { background-color: transparent; } -QListWidget::item::hover { - color: white; - background-color: #4e63ad; -} - QLineEdit { padding: 4px; border: 0; diff --git a/src/kiwixchoicebox.cpp b/src/kiwixchoicebox.cpp index acb00e4..e6d6cb7 100644 --- a/src/kiwixchoicebox.cpp +++ b/src/kiwixchoicebox.cpp @@ -11,6 +11,7 @@ #include #include #include "kiwixlineedit.h" +#include "kiwixlistwidget.h" KiwixChoiceBox::KiwixChoiceBox(QWidget *parent) : QWidget(parent), @@ -28,7 +29,7 @@ KiwixChoiceBox::KiwixChoiceBox(QWidget *parent) : choiceLabel = ui->choiceLabel; choiceLabel->setText(gt("undefined")); - choiceSelector = new QListWidget(parent); + choiceSelector = new KiwixListWidget(parent); choiceSelector->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Minimum); choiceSelector->setMaximumWidth(250); choiceSelector->setMaximumHeight(200); @@ -110,6 +111,12 @@ void KiwixChoiceBox::keyPressEvent(QKeyEvent *event) { if (event->key() == Qt::Key_Escape) { searcher->clearFocus(); + } else if (event->key() == Qt::Key_Down) { + choiceSelector->moveDown(); + } else if (event->key() == Qt::Key_Up) { + choiceSelector->moveUp(); + } else if ((event->key() == Qt::Key_Enter) || (event->key() == Qt::Key_Return)) { + choiceSelector->selectCurrent(); } } diff --git a/src/kiwixchoicebox.h b/src/kiwixchoicebox.h index b788a15..313c0dd 100644 --- a/src/kiwixchoicebox.h +++ b/src/kiwixchoicebox.h @@ -14,6 +14,7 @@ class ChoiceItem; class KiwixLineEdit; +class KiwixListWidget; namespace Ui { class kiwixchoicebox; @@ -43,7 +44,7 @@ private: Ui::kiwixchoicebox *ui; QLabel *choiceLabel; QLineEdit *choiceSearch; - QListWidget *choiceSelector; + KiwixListWidget *choiceSelector; FlowLayout *currentChoicesLayout; KiwixLineEdit *searcher; QStringList getCurrentSelected(); diff --git a/src/kiwixlistwidget.cpp b/src/kiwixlistwidget.cpp new file mode 100644 index 0000000..0d1f58b --- /dev/null +++ b/src/kiwixlistwidget.cpp @@ -0,0 +1,108 @@ +#include "kiwixlistwidget.h" +#include +#include +#include +#include +#include "kiwixapp.h" +#include "klistwidgetitem.h" + +KiwixListWidget::KiwixListWidget(QWidget *parent) + : QListWidget(parent), currRow(0), m_visibleItems(count()) +{ + connect(this, &KiwixListWidget::currRowChanged, this, &KiwixListWidget::handleCurrRowChange); + setMouseTracking(true); +} + +void KiwixListWidget::mousePressEvent(QMouseEvent *event) +{ + if (event->button() == Qt::LeftButton) { + selectCurrent(item(m_mouseIndex)); + } +} + +void KiwixListWidget::mouseMoveEvent(QMouseEvent *event) +{ + int oldRow = currRow; + m_mouseIndex = row(itemAt(event->pos())); + currRow = m_mouseIndex; + emit(currRowChanged(oldRow, currRow)); +} + +void KiwixListWidget::hideEvent(QHideEvent *event) +{ + auto currItem = dynamic_cast(item(currRow)); + if (currItem) + currItem->disableHighlight(); + QListWidget::hideEvent(event); +} + +void KiwixListWidget::resizeEvent(QResizeEvent *e) +{ + int oldRow = currRow; + for (auto i = 0; i < count(); i++) { + auto itemAtRow = item(i); + if (!itemAtRow->isHidden() && !itemAtRow->isSelected()) { + currRow = i; + break; + } + } + emit(currRowChanged(oldRow, currRow)); + QListWidget::resizeEvent(e); +} + +void KiwixListWidget::handleCurrRowChange(int oldRow, int newRow) +{ + auto prevItem = dynamic_cast(item(oldRow)); + if (prevItem) { + prevItem->disableHighlight(); + } + auto currItem = dynamic_cast(item(newRow)); + if (currItem) { + currItem->enableHighlight(); + scrollToItem(currItem, QAbstractItemView::EnsureVisible); + } + emit(dataChanged(QModelIndex(), QModelIndex())); +} + +void KiwixListWidget::moveUp() +{ + if (selectedItems().size() == count()) + return; + KListWidgetItem *currItem = dynamic_cast(item(currRow)); + int oldRow = currRow; + do { + currRow--; + if (currRow < 0) currRow = count() - 1; + currItem = dynamic_cast(item(currRow)); + } while (currItem->isSelected() || currItem->isHidden()); + emit(currRowChanged(oldRow, currRow)); +} + +void KiwixListWidget::moveDown() +{ + if (selectedItems().size() == count()) + return; + KListWidgetItem *currItem = dynamic_cast(item(currRow)); + int oldRow = currRow; + do { + currRow++; + if (currRow == count()) currRow = 0; + currItem = dynamic_cast(item(currRow)); + } while (currItem->isSelected() || currItem->isHidden()); + emit(currRowChanged(oldRow, currRow)); +} + +void KiwixListWidget::selectCurrent() +{ + selectCurrent(item(currRow)); +} + +void KiwixListWidget::selectCurrent(QListWidgetItem *item) +{ + auto currItem = dynamic_cast(item); + if (currItem && !currItem->isSelected() && !currItem->isHidden()) { + currItem->disableHighlight(); + currItem->setSelected(!currItem->isSelected()); + emit(itemPressed(currItem)); + } +} diff --git a/src/kiwixlistwidget.h b/src/kiwixlistwidget.h new file mode 100644 index 0000000..0f4cd07 --- /dev/null +++ b/src/kiwixlistwidget.h @@ -0,0 +1,36 @@ +#ifndef KIWIXLISTWIDGET_H +#define KIWIXLISTWIDGET_H + +#include + +class KiwixListWidget : public QListWidget { + Q_OBJECT + +public: + KiwixListWidget(QWidget *parent = nullptr); + void moveUp(); + void moveDown(); + void selectCurrent(); + void selectCurrent(QListWidgetItem *item); + void setVisibleItems(int visibleItems) { m_visibleItems = visibleItems; } + int getVisibleItems() { return m_visibleItems; } + +protected: + void hideEvent(QHideEvent *event) override; + void resizeEvent(QResizeEvent *event) override; + void mousePressEvent(QMouseEvent *event) override; + void mouseMoveEvent(QMouseEvent *event) override; + +signals: + void currRowChanged(int oldRow, int newRow); + +private slots: + void handleCurrRowChange(int oldRow, int newRow); + +private: + int currRow; + int m_visibleItems; + int m_mouseIndex; +}; + +#endif // KIWIXLISTWIDGET_H diff --git a/src/klistwidgetitem.cpp b/src/klistwidgetitem.cpp index 6891394..b77ef60 100644 --- a/src/klistwidgetitem.cpp +++ b/src/klistwidgetitem.cpp @@ -6,16 +6,36 @@ KListWidgetItem::KListWidgetItem(QString text) : QListWidgetItem (text) { setSizeHint(QSize(200, m_itemHeight)); + setBackground(QColor("white")); + setForeground(QColor("#666666")); +} + +void KListWidgetItem::disableHighlight() +{ + isHighlighted = false; +} + +void KListWidgetItem::enableHighlight() +{ + isHighlighted = true; } QVariant KListWidgetItem::data(int role) const { QVariant v = QListWidgetItem::data(role); - if( isSelected() && role == Qt::FontRole ) - { - QFont font = v.value(); - font.setBold( true ); - v = QVariant::fromValue( font ); + if( isSelected()) { + if (role == Qt::FontRole) { + QFont font = v.value(); + font.setBold( true ); + v = QVariant::fromValue( font ); + } + } + if (isHighlighted) { + if (role == Qt::BackgroundRole) { + v = QVariant::fromValue(QColor("#4e63ad")); + } else if (role == Qt::ForegroundRole) { + v = QVariant::fromValue(QColor("white")); + } } return v; } diff --git a/src/klistwidgetitem.h b/src/klistwidgetitem.h index 66bdd1e..493fe07 100644 --- a/src/klistwidgetitem.h +++ b/src/klistwidgetitem.h @@ -9,8 +9,11 @@ public: KListWidgetItem(QString text); QVariant data(int role) const; static int getItemHeight() { return m_itemHeight; }; + void disableHighlight(); + void enableHighlight(); private: static int m_itemHeight; + bool isHighlighted = false; }; #endif // KLISTWIDGETITEM_H