]> git.sur5r.net Git - minitube/blobdiff - src/searchview.cpp
New upstream version 3.1
[minitube] / src / searchview.cpp
index bf48028953b1a01f0b66e2f1fb97adb7df614159..6536d0b4edaebb0bf69401ccec918f6b33772185 100644 (file)
@@ -19,16 +19,19 @@ along with Minitube.  If not, see <http://www.gnu.org/licenses/>.
 $END_LICENSE */
 
 #include "searchview.h"
+#include "channelsuggest.h"
 #include "constants.h"
 #include "fontutils.h"
 #include "searchparams.h"
 #include "ytsuggester.h"
-#include "channelsuggest.h"
 #ifdef APP_MAC_SEARCHFIELD
 #include "searchlineedit_mac.h"
 #else
 #include "searchlineedit.h"
 #endif
+#ifdef APP_MAC
+#include "macutils.h"
+#endif
 #ifdef APP_EXTRA
 #include "extra.h"
 #endif
@@ -36,22 +39,22 @@ $END_LICENSE */
 #include "activation.h"
 #include "activationview.h"
 #endif
+#include "clickablelabel.h"
+#include "iconutils.h"
 #include "mainwindow.h"
 #include "painterutils.h"
-#include "iconutils.h"
-#include "clickablelabel.h"
 
 namespace {
-static const QString recentKeywordsKey = "recentKeywords";
-static const QString recentChannelsKey = "recentChannels";
-}
+const QString recentKeywordsKey = "recentKeywords";
+const QString recentChannelsKey = "recentChannels";
+} // namespace
 
 SearchView::SearchView(QWidget *parent) : View(parent) {
-    const int padding = 30;
+    setBackgroundRole(QPalette::Base);
+    setForegroundRole(QPalette::Text);
+    setAutoFillBackground(true);
 
-    // speedup painting since we'll paint the whole background
-    // by ourselves anyway in paintEvent()
-    setAttribute(Qt::WA_OpaquePaintEvent);
+    const int padding = 30;
 
     QBoxLayout *vLayout = new QVBoxLayout(this);
     vLayout->setMargin(padding);
@@ -71,8 +74,12 @@ SearchView::SearchView(QWidget *parent) : View(parent) {
 
     hLayout->addStretch();
 
-    logo = new ClickableLabel(this);
-    logo->setPixmap(IconUtils::pixmap(":/images/app.png"));
+    logo = new ClickableLabel();
+    auto setLogoPixmap = [this] {
+        logo->setPixmap(IconUtils::pixmap(":/images/app.png", logo->devicePixelRatioF()));
+    };
+    setLogoPixmap();
+    connect(window()->windowHandle(), &QWindow::screenChanged, this, setLogoPixmap);
     connect(logo, &ClickableLabel::clicked, MainWindow::instance(), &MainWindow::visitSite);
     hLayout->addWidget(logo, 0, Qt::AlignTop);
     hLayout->addSpacing(padding);
@@ -81,65 +88,41 @@ SearchView::SearchView(QWidget *parent) : View(parent) {
     layout->setAlignment(Qt::AlignCenter);
     hLayout->addLayout(layout);
 
-    QColor titleColor = palette().color(QPalette::WindowText);
-    titleColor.setAlphaF(.75);
-    int r,g,b,a;
-    titleColor.getRgb(&r,&g,&b,&a);
-    QString cssColor = QString::asprintf("rgba(%d,%d,%d,%d)", r, g, b, a);
-
-    QLabel *welcomeLabel =
-            new QLabel(QString("<h1 style='font-weight:300;color:%1'>").arg(cssColor) +
-                       tr("Welcome to <a href='%1'>%2</a>,")
-                       .replace("<a ", "<a style='text-decoration:none; color:palette(text)' ")
-                       .arg(Constants::WEBSITE, Constants::NAME)
-                       + "</h1>");
+    QLabel *welcomeLabel = new QLabel();
+    auto setupWelcomeLabel = [this, welcomeLabel] {
+        QColor titleColor = palette().color(QPalette::WindowText);
+        titleColor.setAlphaF(.75);
+        int r, g, b, a;
+        titleColor.getRgb(&r, &g, &b, &a);
+        QString cssColor = QString::asprintf("rgba(%d,%d,%d,%d)", r, g, b, a);
+        QString text =
+                QString("<h1 style='font-weight:300;color:%1'>").arg(cssColor) +
+                tr("Welcome to <a href='%1'>%2</a>,")
+                        .replace("<a ", "<a style='text-decoration:none; color:palette(text)' ")
+                        .arg(Constants::WEBSITE, Constants::NAME) +
+                "</h1>";
+        welcomeLabel->setText(text);
+    };
+    setupWelcomeLabel();
+    connect(qApp, &QGuiApplication::paletteChanged, this, setupWelcomeLabel);
     welcomeLabel->setOpenExternalLinks(true);
-    welcomeLabel->setProperty("heading", true);
-    welcomeLabel->setFont(FontUtils::light(welcomeLabel->font().pointSize() * 1.25));
+    welcomeLabel->setFont(FontUtils::light(welcomeLabel->font().pointSize()));
     layout->addWidget(welcomeLabel);
 
     layout->addSpacing(padding / 2);
 
-#ifndef APP_MAC
-    const QFont &biggerFont = FontUtils::big();
-#endif
-
     //: "Enter", as in "type". The whole phrase says: "Enter a keyword to start watching videos"
     // QLabel *tipLabel = new QLabel(tr("Enter"), this);
-
     QString tip;
     if (qApp->layoutDirection() == Qt::RightToLeft) {
         tip = tr("to start watching videos.") + " " + tr("a keyword") + " " + tr("Enter");
     } else {
         tip = tr("Enter") + " " + tr("a keyword") + " " + tr("to start watching videos.");
     }
-    QLabel *tipLabel = new QLabel(tip);
-
-#ifndef APP_MAC
-    tipLabel->setFont(biggerFont);
-#endif
-    layout->addWidget(tipLabel);
-
-    /*
-    typeCombo = new QComboBox(this);
-    typeCombo->addItem(tr("a keyword"));
-    typeCombo->addItem(tr("a channel"));
-#ifndef APP_MAC
-    typeCombo->setFont(biggerFont);
-#endif
-    connect(typeCombo, SIGNAL(currentIndexChanged(int)), SLOT(searchTypeChanged(int)));
-    tipLayout->addWidget(typeCombo);
-
-    tipLabel = new QLabel(tr("to start watching videos."), this);
-#ifndef APP_MAC
-    tipLabel->setFont(biggerFont);
-#endif
-    tipLayout->addWidget(tipLabel);
-    */
 
     layout->addSpacing(padding / 2);
 
-    QHBoxLayout *searchLayout = new QHBoxLayout();
+    QBoxLayout *searchLayout = new QHBoxLayout();
     searchLayout->setAlignment(Qt::AlignVCenter);
 
 #ifdef APP_MAC_SEARCHFIELD
@@ -148,34 +131,31 @@ SearchView::SearchView(QWidget *parent) : View(parent) {
     setFocusProxy(slem);
 #else
     SearchLineEdit *sle = new SearchLineEdit(this);
-    sle->setFont(biggerFont);
+    sle->setFont(FontUtils::medium());
+    int tipWidth = sle->fontMetrics().size(Qt::TextSingleLine, tip).width();
+    sle->setMinimumWidth(tipWidth + sle->fontMetrics().width('m') * 6);
+    sle->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Preferred);
     queryEdit = sle;
 #endif
 
-    connect(queryEdit->toWidget(), SIGNAL(search(const QString&)), SLOT(watch(const QString&)));
-    connect(queryEdit->toWidget(), SIGNAL(textChanged(const QString &)), SLOT(textChanged(const QString &)));
-    connect(queryEdit->toWidget(), SIGNAL(textEdited(const QString &)), SLOT(textChanged(const QString &)));
-    connect(queryEdit->toWidget(), SIGNAL(suggestionAccepted(Suggestion*)), SLOT(suggestionAccepted(Suggestion*)));
+    connect(queryEdit->toWidget(), SIGNAL(search(const QString &)), SLOT(watch(const QString &)));
+    connect(queryEdit->toWidget(), SIGNAL(textChanged(const QString &)),
+            SLOT(textChanged(const QString &)));
+    connect(queryEdit->toWidget(), SIGNAL(textEdited(const QString &)),
+            SLOT(textChanged(const QString &)));
+    connect(queryEdit->toWidget(), SIGNAL(suggestionAccepted(Suggestion *)),
+            SLOT(suggestionAccepted(Suggestion *)));
+    queryEdit->setPlaceholderText(tip);
 
     youtubeSuggest = new YTSuggester(this);
     channelSuggest = new ChannelSuggest(this);
-    connect(channelSuggest, SIGNAL(ready(QVector<Suggestion*>)), SLOT(onChannelSuggestions(QVector<Suggestion*>)));
+    connect(channelSuggest, SIGNAL(ready(QVector<Suggestion *>)),
+            SLOT(onChannelSuggestions(QVector<Suggestion *>)));
     searchTypeChanged(0);
 
     searchLayout->addWidget(queryEdit->toWidget(), 0, Qt::AlignBaseline);
-    searchLayout->addSpacing(padding);
 
-    watchButton = new QPushButton(tr("Watch"));
-#ifndef APP_MAC
-    watchButton->setFont(biggerFont);
-#endif
-    watchButton->setDefault(true);
-    watchButton->setEnabled(false);
-    watchButton->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed);
-    connect(watchButton, SIGNAL(clicked()), this, SLOT(watch()));
-    searchLayout->addWidget(watchButton, 0, Qt::AlignBaseline);
-
-    layout->addItem(searchLayout);
+    layout->addLayout(searchLayout);
 
     layout->addSpacing(padding);
 
@@ -188,9 +168,9 @@ SearchView::SearchView(QWidget *parent) : View(parent) {
     recentKeywordsLayout->setSpacing(0);
     recentKeywordsLayout->setAlignment(Qt::AlignTop | Qt::AlignLeft);
     recentKeywordsLabel = new QLabel(tr("Recent keywords"));
-    recentKeywordsLabel->setEnabled(false);
     recentKeywordsLabel->setProperty("recentHeader", true);
     recentKeywordsLabel->hide();
+    recentKeywordsLabel->setEnabled(false);
     recentKeywordsLayout->addWidget(recentKeywordsLabel);
     recentLayout->addLayout(recentKeywordsLayout);
 
@@ -199,9 +179,9 @@ SearchView::SearchView(QWidget *parent) : View(parent) {
     recentChannelsLayout->setSpacing(0);
     recentChannelsLayout->setAlignment(Qt::AlignTop | Qt::AlignLeft);
     recentChannelsLabel = new QLabel(tr("Recent channels"));
-    recentChannelsLabel->setEnabled(false);
     recentChannelsLabel->setProperty("recentHeader", true);
     recentChannelsLabel->hide();
+    recentChannelsLabel->setEnabled(false);
     recentChannelsLayout->addWidget(recentChannelsLabel);
     recentLayout->addLayout(recentChannelsLayout);
 
@@ -213,39 +193,30 @@ SearchView::SearchView(QWidget *parent) : View(parent) {
 
 #ifdef APP_ACTIVATION
     if (!Activation::instance().isActivated())
-        vLayout->addWidget(ActivationView::buyButton(tr("Get the full version")), 0, Qt::AlignRight);
+        vLayout->addWidget(ActivationView::buyButton(tr("Get the full version")), 0,
+                           Qt::AlignRight);
 #endif
 }
 
 void SearchView::appear() {
     MainWindow *w = MainWindow::instance();
-    w->showActionInStatusBar(w->getAction("manualplay"), true);
-    w->showActionInStatusBar(w->getAction("safeSearch"), true);
-    w->showActionInStatusBar(w->getAction("definition"), true);
+    w->showActionsInStatusBar(
+            {w->getAction("manualplay"), w->getAction("safeSearch"), w->getAction("definition")},
+            true);
 
     updateRecentKeywords();
     updateRecentChannels();
 
     queryEdit->selectAll();
     queryEdit->enableSuggest();
-    if (!queryEdit->toWidget()->hasFocus()) queryEdit->toWidget()->setFocus();
-
-    connect(window()->windowHandle(), SIGNAL(screenChanged(QScreen*)), SLOT(screenChanged()), Qt::UniqueConnection);
-
-    qApp->processEvents();
-    update();
-
-#ifdef APP_MAC
-    // Workaround cursor bug on macOS
-    window()->unsetCursor();
-#endif
+    QTimer::singleShot(0, queryEdit->toWidget(), SLOT(setFocus()));
 }
 
 void SearchView::disappear() {
     MainWindow *w = MainWindow::instance();
-    w->showActionInStatusBar(w->getAction("safeSearch"), false);
-    w->showActionInStatusBar(w->getAction("definition"), false);
-    w->showActionInStatusBar(w->getAction("manualplay"), false);
+    w->showActionsInStatusBar(
+            {w->getAction("manualplay"), w->getAction("safeSearch"), w->getAction("definition")},
+            false);
 }
 
 void SearchView::updateRecentKeywords() {
@@ -257,7 +228,8 @@ void SearchView::updateRecentKeywords() {
 
     // cleanup
     QLayoutItem *item;
-    while ((item = recentKeywordsLayout->takeAt(1)) != 0) {
+    while (recentKeywordsLayout->count() - 1 > recentKeywords.size() &&
+           (item = recentKeywordsLayout->takeAt(1)) != nullptr) {
         item->widget()->close();
         delete item;
     }
@@ -267,37 +239,66 @@ void SearchView::updateRecentKeywords() {
 
     const int maxDisplayLength = 25;
 
+#ifdef APP_MAC
+    QPalette p = palette();
+    p.setColor(QPalette::Highlight, mac::accentColor());
+#endif
+
+    int counter = 1;
     for (const QString &keyword : keywords) {
         QString link = keyword;
         QString display = keyword;
-        if (keyword.startsWith(QLatin1String("http://")) || keyword.startsWith(QLatin1String("https://"))) {
+        if (keyword.startsWith(QLatin1String("http://")) ||
+            keyword.startsWith(QLatin1String("https://"))) {
             int separator = keyword.indexOf('|');
             if (separator > 0 && separator + 1 < keyword.length()) {
                 link = keyword.left(separator);
-                display = keyword.mid(separator+1);
+                display = keyword.mid(separator + 1);
             }
         }
-        bool needStatusTip = false;
-        if (display.length() > maxDisplayLength) {
+        bool needStatusTip = display.length() > maxDisplayLength;
+        if (needStatusTip) {
             display.truncate(maxDisplayLength);
             display.append(QStringLiteral("\u2026"));
-            needStatusTip = true;
         }
-        QPushButton *itemButton = new QPushButton(display);
-        itemButton->setAttribute(Qt::WA_DeleteOnClose);
-        itemButton->setProperty("recentItem", true);
-        itemButton->setCursor(Qt::PointingHandCursor);
-        itemButton->setFocusPolicy(Qt::TabFocus);
-        itemButton->setSizePolicy(QSizePolicy::MinimumExpanding, QSizePolicy::Preferred);
+
+        ClickableLabel *item;
+        if (recentKeywordsLayout->count() - 1 >= counter) {
+            item = qobject_cast<ClickableLabel *>(recentKeywordsLayout->itemAt(counter)->widget());
+
+        } else {
+            item = new ClickableLabel();
+#ifdef APP_MAC
+            item->setPalette(p);
+#endif
+            item->setAttribute(Qt::WA_DeleteOnClose);
+            item->setProperty("recentItem", true);
+            item->setFocusPolicy(Qt::TabFocus);
+            connect(item, &ClickableLabel::hovered, this, [item, this](bool value) {
+                item->setForegroundRole(value ? QPalette::Highlight : QPalette::WindowText);
+                if (value) {
+                    for (int i = 1; i < recentKeywordsLayout->count(); ++i) {
+                        QWidget *w = recentKeywordsLayout->itemAt(i)->widget();
+                        if (w != item) {
+                            w->setForegroundRole(QPalette::WindowText);
+                        }
+                    }
+                }
+            });
+            recentKeywordsLayout->addWidget(item);
+        }
+
+        item->setText(display);
         if (needStatusTip)
-            itemButton->setStatusTip(link);
-        connect(itemButton, &QPushButton::clicked, [this,link]() {
-            watchKeywords(link);
-        });
+            item->setStatusTip(link);
+        else
+            item->setStatusTip(QString());
 
-        recentKeywordsLayout->addWidget(itemButton);
-    }
+        disconnect(item, &ClickableLabel::clicked, nullptr, nullptr);
+        connect(item, &ClickableLabel::clicked, this, [this, link]() { watchKeywords(link); });
 
+        counter++;
+    }
 }
 
 void SearchView::updateRecentChannels() {
@@ -309,13 +310,17 @@ void SearchView::updateRecentChannels() {
 
     // cleanup
     QLayoutItem *item;
-    while ((item = recentChannelsLayout->takeAt(1)) != 0) {
+    while ((item = recentChannelsLayout->takeAt(1)) != nullptr) {
         item->widget()->close();
         delete item;
     }
 
     recentChannelsLabel->setVisible(!keywords.isEmpty());
-    // TODO MainWindow::instance()->getAction("clearRecentKeywords")->setEnabled(!keywords.isEmpty());
+
+#ifdef APP_MAC
+    QPalette p = palette();
+    p.setColor(QPalette::Highlight, mac::accentColor());
+#endif
 
     for (const QString &keyword : keywords) {
         QString link = keyword;
@@ -323,18 +328,21 @@ void SearchView::updateRecentChannels() {
         int separator = keyword.indexOf('|');
         if (separator > 0 && separator + 1 < keyword.length()) {
             link = keyword.left(separator);
-            display = keyword.mid(separator+1);
+            display = keyword.mid(separator + 1);
         }
-        QPushButton *itemButton = new QPushButton(display);
-        itemButton->setAttribute(Qt::WA_DeleteOnClose);
-        itemButton->setProperty("recentItem", true);
-        itemButton->setCursor(Qt::PointingHandCursor);
-        itemButton->setFocusPolicy(Qt::TabFocus);
-        itemButton->setSizePolicy(QSizePolicy::MinimumExpanding, QSizePolicy::Preferred);
-        connect(itemButton, &QPushButton::clicked, [this,link]() {
-            watchChannel(link);
+
+        ClickableLabel *item = new ClickableLabel(display);
+#ifdef APP_MAC
+        item->setPalette(p);
+#endif
+        item->setAttribute(Qt::WA_DeleteOnClose);
+        item->setProperty("recentItem", true);
+        item->setFocusPolicy(Qt::TabFocus);
+        connect(item, &ClickableLabel::clicked, [this, link]() { watchChannel(link); });
+        connect(item, &ClickableLabel::hovered, item, [item](bool value) {
+            item->setForegroundRole(value ? QPalette::Highlight : QPalette::WindowText);
         });
-        recentChannelsLayout->addWidget(itemButton);
+        recentChannelsLayout->addWidget(item);
     }
 }
 
@@ -344,7 +352,6 @@ void SearchView::watch() {
 }
 
 void SearchView::textChanged(const QString &text) {
-    watchButton->setEnabled(!text.simplified().isEmpty());
     lastChannelSuggestions.clear();
 }
 
@@ -357,14 +364,6 @@ void SearchView::watch(const QString &query) {
         return;
     }
 
-    /*
-    if (typeCombo->currentIndex() == 1) {
-        // Channel search
-        MainWindow::instance()->channelSearch(q);
-        return;
-    }
-    */
-
     SearchParams *searchParams = new SearchParams();
     searchParams->setKeywords(q);
 
@@ -401,10 +400,7 @@ void SearchView::watchKeywords(const QString &query) {
         return;
     }
 
-    // if (typeCombo->currentIndex() == 0) {
-        queryEdit->setText(q);
-        watchButton->setEnabled(true);
-    // }
+    queryEdit->setText(q);
 
     SearchParams *searchParams = new SearchParams();
     searchParams->setKeywords(q);
@@ -413,18 +409,6 @@ void SearchView::watchKeywords(const QString &query) {
     emit search(searchParams);
 }
 
-void SearchView::paintEvent(QPaintEvent *event) {
-    QWidget::paintEvent(event);
-    QBrush brush;
-    if (window()->isActiveWindow()) {
-        brush = palette().base();
-    } else {
-        brush = palette().window();
-    }
-    QPainter painter(this);
-    painter.fillRect(0, 0, width(), height(), brush);
-}
-
 void SearchView::searchTypeChanged(int index) {
     if (index == 0) {
         queryEdit->setSuggester(youtubeSuggest);
@@ -438,11 +422,8 @@ void SearchView::searchTypeChanged(int index) {
 void SearchView::suggestionAccepted(Suggestion *suggestion) {
     if (suggestion->type == QLatin1String("channel")) {
         watchChannel(suggestion->userData);
-    } else watch(suggestion->value);
-}
-
-void SearchView::screenChanged() {
-    logo->setPixmap(IconUtils::pixmap(":/images/app.png"));
+    } else
+        watch(suggestion->value);
 }
 
 void SearchView::onChannelSuggestions(const QVector<Suggestion *> &suggestions) {