Implement pressing tab to navigate auto completion (#294)
Fixes #287 * Fix pop-up not showing when less than max * Select suggestion by pressing Enter
This commit is contained in:
parent
5125433552
commit
0b3029b3c4
@ -21,13 +21,18 @@ class PopupItem : public QWidget
|
|||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
|
|
||||||
Q_PROPERTY(QColor hoverColor READ hoverColor WRITE setHoverColor)
|
Q_PROPERTY(QColor hoverColor READ hoverColor WRITE setHoverColor)
|
||||||
|
Q_PROPERTY(bool hovering READ hovering WRITE setHovering)
|
||||||
|
|
||||||
public:
|
public:
|
||||||
PopupItem(QWidget *parent, const QString &user_id);
|
PopupItem(QWidget *parent, const QString &user_id);
|
||||||
|
|
||||||
|
QString user() const { return user_id_; }
|
||||||
QColor hoverColor() const { return hoverColor_; }
|
QColor hoverColor() const { return hoverColor_; }
|
||||||
void setHoverColor(QColor &color) { hoverColor_ = color; }
|
void setHoverColor(QColor &color) { hoverColor_ = color; }
|
||||||
|
|
||||||
|
bool hovering() const { return hovering_; }
|
||||||
|
void setHovering(const bool hover) { hovering_ = hover; };
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
void paintEvent(QPaintEvent *event) override;
|
void paintEvent(QPaintEvent *event) override;
|
||||||
void mousePressEvent(QMouseEvent *event) override;
|
void mousePressEvent(QMouseEvent *event) override;
|
||||||
@ -43,6 +48,9 @@ private:
|
|||||||
QString user_id_;
|
QString user_id_;
|
||||||
|
|
||||||
QColor hoverColor_;
|
QColor hoverColor_;
|
||||||
|
|
||||||
|
//! Set if the item is currently being hovered during tab completion (cycling).
|
||||||
|
bool hovering_;
|
||||||
};
|
};
|
||||||
|
|
||||||
class SuggestionsPopup : public QWidget
|
class SuggestionsPopup : public QWidget
|
||||||
@ -54,10 +62,15 @@ public:
|
|||||||
|
|
||||||
public slots:
|
public slots:
|
||||||
void addUsers(const QVector<SearchResult> &users);
|
void addUsers(const QVector<SearchResult> &users);
|
||||||
|
void cycleThroughSuggestions();
|
||||||
|
void selectHoveredSuggestion();
|
||||||
|
|
||||||
signals:
|
signals:
|
||||||
void itemSelected(const QString &user);
|
void itemSelected(const QString &user);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
QVBoxLayout *layout_;
|
QVBoxLayout *layout_;
|
||||||
|
|
||||||
|
//! Counter for tab completion (cycling).
|
||||||
|
int tab_clicks_;
|
||||||
};
|
};
|
||||||
|
@ -73,6 +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 selectHoveredSuggestion();
|
||||||
|
|
||||||
public slots:
|
public slots:
|
||||||
void showResults(const QVector<SearchResult> &results);
|
void showResults(const QVector<SearchResult> &results);
|
||||||
|
@ -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"
|
||||||
|
|
||||||
@ -18,6 +18,7 @@ PopupItem::PopupItem(QWidget *parent, const QString &user_id)
|
|||||||
: QWidget(parent)
|
: QWidget(parent)
|
||||||
, avatar_{new Avatar(this)}
|
, avatar_{new Avatar(this)}
|
||||||
, user_id_{user_id}
|
, user_id_{user_id}
|
||||||
|
, hovering_{false}
|
||||||
{
|
{
|
||||||
setMouseTracking(true);
|
setMouseTracking(true);
|
||||||
setAttribute(Qt::WA_Hover);
|
setAttribute(Qt::WA_Hover);
|
||||||
@ -56,7 +57,7 @@ PopupItem::paintEvent(QPaintEvent *)
|
|||||||
QPainter p(this);
|
QPainter p(this);
|
||||||
style()->drawPrimitive(QStyle::PE_Widget, &opt, &p, this);
|
style()->drawPrimitive(QStyle::PE_Widget, &opt, &p, this);
|
||||||
|
|
||||||
if (underMouse())
|
if (underMouse() || hovering_)
|
||||||
p.fillRect(rect(), hoverColor_);
|
p.fillRect(rect(), hoverColor_);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -71,6 +72,7 @@ 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);
|
||||||
@ -101,5 +103,41 @@ 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.
|
||||||
|
|
||||||
resize(geometry().width(), 40 * users.size());
|
resize(geometry().width(), 40 * users.size());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
SuggestionsPopup::cycleThroughSuggestions()
|
||||||
|
{
|
||||||
|
tab_clicks_ %= layout_->count(); // Stay within the number of items in layout.
|
||||||
|
|
||||||
|
// Reset flag for hovering effect first.
|
||||||
|
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_);
|
||||||
|
const auto &widget = qobject_cast<PopupItem *>(item->widget());
|
||||||
|
widget->setHovering(true);
|
||||||
|
|
||||||
|
++tab_clicks_;
|
||||||
|
|
||||||
|
update(); // Request to update the paint event.
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
SuggestionsPopup::selectHoveredSuggestion()
|
||||||
|
{
|
||||||
|
// Each tab press increments the counter by one, so the element desired is one off.
|
||||||
|
const auto item = layout_->itemAt(tab_clicks_ - 1);
|
||||||
|
if (!item)
|
||||||
|
return;
|
||||||
|
|
||||||
|
const auto &widget = qobject_cast<PopupItem *>(item->widget());
|
||||||
|
emit itemSelected(TimelineViewManager::displayName(widget->user()));
|
||||||
|
|
||||||
|
tab_clicks_ = 0; // Reset to start from the beginning of pop-up window on next invocation.
|
||||||
|
}
|
||||||
|
@ -86,6 +86,16 @@ FilteredTextEdit::FilteredTextEdit(QWidget *parent)
|
|||||||
cursor.insertText(text);
|
cursor.insertText(text);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// For cycling through the suggestions by hitting tab.
|
||||||
|
connect(this,
|
||||||
|
&FilteredTextEdit::cycleSuggestions,
|
||||||
|
&popup_,
|
||||||
|
&SuggestionsPopup::cycleThroughSuggestions);
|
||||||
|
connect(this,
|
||||||
|
&FilteredTextEdit::selectHoveredSuggestion,
|
||||||
|
&popup_,
|
||||||
|
&SuggestionsPopup::selectHoveredSuggestion);
|
||||||
|
|
||||||
previewDialog_.hide();
|
previewDialog_.hide();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -128,10 +138,15 @@ FilteredTextEdit::keyPressEvent(QKeyEvent *event)
|
|||||||
|
|
||||||
if (popup_.isVisible()) {
|
if (popup_.isVisible()) {
|
||||||
switch (event->key()) {
|
switch (event->key()) {
|
||||||
|
case Qt::Key_Tab:
|
||||||
|
emit cycleSuggestions();
|
||||||
|
return;
|
||||||
case Qt::Key_Enter:
|
case Qt::Key_Enter:
|
||||||
case Qt::Key_Return:
|
case Qt::Key_Return:
|
||||||
|
emit selectHoveredSuggestion();
|
||||||
|
return;
|
||||||
case Qt::Key_Escape:
|
case Qt::Key_Escape:
|
||||||
case Qt::Key_Tab:
|
break;
|
||||||
case Qt::Key_Space:
|
case Qt::Key_Space:
|
||||||
case Qt::Key_Backtab: {
|
case Qt::Key_Backtab: {
|
||||||
closeSuggestions();
|
closeSuggestions();
|
||||||
@ -464,6 +479,8 @@ TextInputWidget::TextInputWidget(QWidget *parent)
|
|||||||
|
|
||||||
if (items.size() >= MaxPopupItems)
|
if (items.size() >= MaxPopupItems)
|
||||||
std::advance(end, MaxPopupItems);
|
std::advance(end, MaxPopupItems);
|
||||||
|
else if (items.size() > 0)
|
||||||
|
std::advance(end, items.size());
|
||||||
|
|
||||||
for (auto it = items.begin(); it != end; it++) {
|
for (auto it = items.begin(); it != end; it++) {
|
||||||
const auto user = it->second;
|
const auto user = it->second;
|
||||||
|
Loading…
Reference in New Issue
Block a user