Popup improvements

- ESC closes the popup.
- Up/Down arrows for navigation.
- BackTab for backwards navigation.

fixes #301
fixes #302
This commit is contained in:
Konstantinos Sideris 2018-04-14 14:12:36 +03:00
parent 96617385bc
commit ca66940ec3
4 changed files with 72 additions and 26 deletions

View file

@ -62,15 +62,27 @@ public:
public slots: public slots:
void addUsers(const QVector<SearchResult> &users); void addUsers(const QVector<SearchResult> &users);
void cycleThroughSuggestions();
void selectHoveredSuggestion(); void selectHoveredSuggestion();
//! Move to the next available suggestion item.
void selectNextSuggestion();
//! Move to the previous available suggestion item.
void selectPreviousSuggestion();
//! Remove hovering from all items.
void resetHovering();
//! Set hovering to the item in the given layout position.
void setHovering(int pos);
signals: signals:
void itemSelected(const QString &user); void itemSelected(const QString &user);
private: private:
void hoverSelection();
void resetSelection() { selectedItem_ = -1; }
void selectFirstItem() { selectedItem_ = 0; }
void selectLastItem() { selectedItem_ = layout_->count() - 1; }
QVBoxLayout *layout_; QVBoxLayout *layout_;
//! Counter for tab completion (cycling). //! Counter for tab completion (cycling).
int tab_clicks_; int selectedItem_ = -1;
}; };

View file

@ -73,7 +73,8 @@ signals:
//! Trigger the suggestion popup. //! Trigger the suggestion popup.
void showSuggestions(const QString &query); void showSuggestions(const QString &query);
void resultsRetrieved(const QVector<SearchResult> &results); void resultsRetrieved(const QVector<SearchResult> &results);
void cycleSuggestions(); void selectNextSuggestion();
void selectPreviousSuggestion();
void selectHoveredSuggestion(); void selectHoveredSuggestion();
public slots: public slots:

View file

@ -1,8 +1,8 @@
#include "SuggestionsPopup.hpp"
#include "Avatar.h" #include "Avatar.h"
#include "AvatarProvider.h" #include "AvatarProvider.h"
#include "Config.h" #include "Config.h"
#include "DropShadow.h" #include "DropShadow.h"
#include "SuggestionsPopup.hpp"
#include "Utils.h" #include "Utils.h"
#include "timeline/TimelineViewManager.h" #include "timeline/TimelineViewManager.h"
@ -72,7 +72,6 @@ PopupItem::mousePressEvent(QMouseEvent *event)
SuggestionsPopup::SuggestionsPopup(QWidget *parent) SuggestionsPopup::SuggestionsPopup(QWidget *parent)
: QWidget(parent) : QWidget(parent)
, tab_clicks_(0)
{ {
setAttribute(Qt::WA_ShowWithoutActivating, true); setAttribute(Qt::WA_ShowWithoutActivating, true);
setWindowFlags(Qt::ToolTip | Qt::NoDropShadowWindowHint); setWindowFlags(Qt::ToolTip | Qt::NoDropShadowWindowHint);
@ -103,41 +102,69 @@ SuggestionsPopup::addUsers(const QVector<SearchResult> &users)
connect(user, &PopupItem::clicked, this, &SuggestionsPopup::itemSelected); connect(user, &PopupItem::clicked, this, &SuggestionsPopup::itemSelected);
} }
tab_clicks_ = 0; // Reset to start from the beginning of pop-up window on next invocation. resetSelection();
resize(geometry().width(), 40 * users.size()); resize(geometry().width(), 40 * users.size());
} }
void void
SuggestionsPopup::cycleThroughSuggestions() SuggestionsPopup::hoverSelection()
{ {
tab_clicks_ %= layout_->count(); // Stay within the number of items in layout. resetHovering();
setHovering(selectedItem_);
// Reset flag for hovering effect first. update();
for (int i = 0; i < layout_->count(); ++i) {
const auto &p = qobject_cast<PopupItem *>(layout_->itemAt(i)->widget());
p->setHovering(false);
} }
const auto &item = layout_->itemAt(tab_clicks_); void
SuggestionsPopup::selectNextSuggestion()
{
selectedItem_++;
if (selectedItem_ >= layout_->count())
selectFirstItem();
hoverSelection();
}
void
SuggestionsPopup::selectPreviousSuggestion()
{
selectedItem_--;
if (selectedItem_ < 0)
selectLastItem();
hoverSelection();
}
void
SuggestionsPopup::resetHovering()
{
for (int i = 0; i < layout_->count(); ++i) {
const auto item = qobject_cast<PopupItem *>(layout_->itemAt(i)->widget());
if (item)
item->setHovering(false);
}
}
void
SuggestionsPopup::setHovering(int pos)
{
const auto &item = layout_->itemAt(pos);
const auto &widget = qobject_cast<PopupItem *>(item->widget()); const auto &widget = qobject_cast<PopupItem *>(item->widget());
if (widget)
widget->setHovering(true); widget->setHovering(true);
++tab_clicks_;
update(); // Request to update the paint event.
} }
void void
SuggestionsPopup::selectHoveredSuggestion() SuggestionsPopup::selectHoveredSuggestion()
{ {
// Each tab press increments the counter by one, so the element desired is one off. const auto item = layout_->itemAt(selectedItem_);
const auto item = layout_->itemAt(tab_clicks_ - 1);
if (!item) if (!item)
return; return;
const auto &widget = qobject_cast<PopupItem *>(item->widget()); const auto &widget = qobject_cast<PopupItem *>(item->widget());
emit itemSelected(TimelineViewManager::displayName(widget->user())); emit itemSelected(TimelineViewManager::displayName(widget->user()));
tab_clicks_ = 0; // Reset to start from the beginning of pop-up window on next invocation. resetSelection();
} }

View file

@ -88,9 +88,13 @@ FilteredTextEdit::FilteredTextEdit(QWidget *parent)
// For cycling through the suggestions by hitting tab. // For cycling through the suggestions by hitting tab.
connect(this, connect(this,
&FilteredTextEdit::cycleSuggestions, &FilteredTextEdit::selectNextSuggestion,
&popup_, &popup_,
&SuggestionsPopup::cycleThroughSuggestions); &SuggestionsPopup::selectNextSuggestion);
connect(this,
&FilteredTextEdit::selectPreviousSuggestion,
&popup_,
&SuggestionsPopup::selectPreviousSuggestion);
connect(this, connect(this,
&FilteredTextEdit::selectHoveredSuggestion, &FilteredTextEdit::selectHoveredSuggestion,
&popup_, &popup_,
@ -138,19 +142,21 @@ FilteredTextEdit::keyPressEvent(QKeyEvent *event)
if (popup_.isVisible()) { if (popup_.isVisible()) {
switch (event->key()) { switch (event->key()) {
case Qt::Key_Down:
case Qt::Key_Tab: case Qt::Key_Tab:
emit cycleSuggestions(); emit selectNextSuggestion();
return; return;
case Qt::Key_Enter: case Qt::Key_Enter:
case Qt::Key_Return: case Qt::Key_Return:
emit selectHoveredSuggestion(); emit selectHoveredSuggestion();
return; return;
case Qt::Key_Escape: case Qt::Key_Escape:
break;
case Qt::Key_Space:
case Qt::Key_Backtab: {
closeSuggestions(); closeSuggestions();
break; return;
case Qt::Key_Up:
case Qt::Key_Backtab: {
emit selectPreviousSuggestion();
return;
} }
default: default:
break; break;