]> git.sur5r.net Git - minitube/commitdiff
HiDPI support
authorFlavio Tordini <flavio.tordini@gmail.com>
Fri, 11 Sep 2015 12:40:44 +0000 (14:40 +0200)
committerFlavio Tordini <flavio.tordini@gmail.com>
Fri, 11 Sep 2015 12:40:44 +0000 (14:40 +0200)
40 files changed:
images/app@2x.png [new file with mode: 0644]
images/badge3@2x.png [new file with mode: 0644]
images/badge4@2x.png [new file with mode: 0644]
images/badge@2x.png [new file with mode: 0644]
images/channels@2x.png [new file with mode: 0644]
images/mark-watched@2x.png [new file with mode: 0644]
images/refine-search.png
images/refine-search@2x.png [new file with mode: 0644]
images/search-duration@2x.png [new file with mode: 0644]
images/search-quality@2x.png [new file with mode: 0644]
images/search-sortBy@2x.png [new file with mode: 0644]
images/search-time@2x.png [new file with mode: 0644]
images/show-updated.png
images/show-updated@2x.png [new file with mode: 0644]
images/sort@2x.png [new file with mode: 0644]
images/unwatched@2x.png [new file with mode: 0644]
images/worldwide@2x.png [new file with mode: 0644]
resources.qrc
src/aboutview.cpp
src/channelitemdelegate.cpp
src/downloadmanager.cpp
src/iconutils.cpp
src/iconutils.h
src/main.cpp
src/mainwindow.cpp
src/mediaview.cpp
src/painterutils.cpp
src/playlistitemdelegate.cpp
src/qtsingleapplication/qtsingleapplication.pri
src/refinesearchbutton.cpp
src/refinesearchwidget.cpp
src/searchview.cpp
src/segmentedcontrol.cpp
src/segmentedcontrol.h
src/video.cpp
src/video.h
src/videosourcewidget.cpp
src/videosourcewidget.h
src/yt3listparser.cpp
src/ytchannel.cpp

diff --git a/images/app@2x.png b/images/app@2x.png
new file mode 100644 (file)
index 0000000..38c2c30
Binary files /dev/null and b/images/app@2x.png differ
diff --git a/images/badge3@2x.png b/images/badge3@2x.png
new file mode 100644 (file)
index 0000000..f516a47
Binary files /dev/null and b/images/badge3@2x.png differ
diff --git a/images/badge4@2x.png b/images/badge4@2x.png
new file mode 100644 (file)
index 0000000..4511b45
Binary files /dev/null and b/images/badge4@2x.png differ
diff --git a/images/badge@2x.png b/images/badge@2x.png
new file mode 100644 (file)
index 0000000..2ae172e
Binary files /dev/null and b/images/badge@2x.png differ
diff --git a/images/channels@2x.png b/images/channels@2x.png
new file mode 100644 (file)
index 0000000..abba86b
Binary files /dev/null and b/images/channels@2x.png differ
diff --git a/images/mark-watched@2x.png b/images/mark-watched@2x.png
new file mode 100644 (file)
index 0000000..73f8fb4
Binary files /dev/null and b/images/mark-watched@2x.png differ
index ea2cd3eca065b49ed4a16a7046e9874302f2123b..dd977aa7a6507e3389b1a40e8af0fda6114f547b 100644 (file)
Binary files a/images/refine-search.png and b/images/refine-search.png differ
diff --git a/images/refine-search@2x.png b/images/refine-search@2x.png
new file mode 100644 (file)
index 0000000..37340a5
Binary files /dev/null and b/images/refine-search@2x.png differ
diff --git a/images/search-duration@2x.png b/images/search-duration@2x.png
new file mode 100644 (file)
index 0000000..daef48d
Binary files /dev/null and b/images/search-duration@2x.png differ
diff --git a/images/search-quality@2x.png b/images/search-quality@2x.png
new file mode 100644 (file)
index 0000000..3035153
Binary files /dev/null and b/images/search-quality@2x.png differ
diff --git a/images/search-sortBy@2x.png b/images/search-sortBy@2x.png
new file mode 100644 (file)
index 0000000..235200c
Binary files /dev/null and b/images/search-sortBy@2x.png differ
diff --git a/images/search-time@2x.png b/images/search-time@2x.png
new file mode 100644 (file)
index 0000000..aeaaa21
Binary files /dev/null and b/images/search-time@2x.png differ
index 732c556f34d6f8d2440ce7b9831ac0de47c789aa..9af84f2609fa2bc50c04971acdf01bd3f6458121 100644 (file)
Binary files a/images/show-updated.png and b/images/show-updated.png differ
diff --git a/images/show-updated@2x.png b/images/show-updated@2x.png
new file mode 100644 (file)
index 0000000..7f0b807
Binary files /dev/null and b/images/show-updated@2x.png differ
diff --git a/images/sort@2x.png b/images/sort@2x.png
new file mode 100644 (file)
index 0000000..7475325
Binary files /dev/null and b/images/sort@2x.png differ
diff --git a/images/unwatched@2x.png b/images/unwatched@2x.png
new file mode 100644 (file)
index 0000000..573c25e
Binary files /dev/null and b/images/unwatched@2x.png differ
diff --git a/images/worldwide@2x.png b/images/worldwide@2x.png
new file mode 100644 (file)
index 0000000..2393b38
Binary files /dev/null and b/images/worldwide@2x.png differ
index 6353887b16854cab2d5a15809de786b08c23670f..d41ca8a47765aceb7f1f0764f7152eb7dd16cc50 100644 (file)
         <file>images/badge3.png</file>
         <file>images/badge4.png</file>
         <file>sounds/snapshot.wav</file>
+        <file>images/app@2x.png</file>
+        <file>images/sort@2x.png</file>
+        <file>images/unwatched@2x.png</file>
+        <file>images/badge@2x.png</file>
+        <file>images/badge3@2x.png</file>
+        <file>images/channels@2x.png</file>
+        <file>images/mark-watched@2x.png</file>
+        <file>images/show-updated@2x.png</file>
+        <file>images/worldwide@2x.png</file>
+        <file>images/badge4@2x.png</file>
+        <file>images/refine-search@2x.png</file>
+        <file>images/search-duration@2x.png</file>
+        <file>images/search-quality@2x.png</file>
+        <file>images/search-time@2x.png</file>
+        <file>images/search-sortBy@2x.png</file>
     </qresource>
 </RCC>
index 8548e86b968efd053c58b63f023e65238233c5fc..19c5ee547ea88b41d94464e35dfc269c79931563 100644 (file)
@@ -31,6 +31,7 @@ $END_LICENSE */
 #include "mac_startup.h"
 #endif
 #include "fontutils.h"
+#include "iconutils.h"
 
 AboutView::AboutView(QWidget *parent) : View(parent) {
 
@@ -40,7 +41,7 @@ AboutView::AboutView(QWidget *parent) : View(parent) {
     hLayout->setSpacing(30);
 
     QLabel *logo = new QLabel(this);
-    logo->setPixmap(QPixmap(":/images/app.png"));
+    logo->setPixmap(IconUtils::pixmap(":/images/app.png"));
     hLayout->addWidget(logo, 0, Qt::AlignTop);
 
     QBoxLayout *layout = new QVBoxLayout();
index 4c13dfe7446bb618c756a05debc03fd236cb4c4f..16f3a5357546f5812f920e7f65b1c4e2374ced7a 100644 (file)
@@ -24,6 +24,7 @@ $END_LICENSE */
 #include "fontutils.h"
 #include "channelaggregator.h"
 #include "painterutils.h"
+#include "iconutils.h"
 
 static const int ITEM_WIDTH = 128;
 static const int ITEM_HEIGHT = 128;
@@ -62,7 +63,7 @@ void ChannelItemDelegate::paintAggregate(QPainter* painter,
     painter->translate(option.rect.topLeft());
     const QRect line(0, 0, option.rect.width(), option.rect.height());
 
-    static const QPixmap thumbnail = QPixmap(":/images/channels.png");
+    static const QPixmap thumbnail = IconUtils::pixmap(":/images/channels.png");
 
     QString name = tr("All Videos");
 
@@ -80,7 +81,7 @@ void ChannelItemDelegate::paintUnwatched(QPainter* painter,
     painter->translate(option.rect.topLeft());
     const QRect line(0, 0, option.rect.width(), option.rect.height());
 
-    static const QPixmap thumbnail = QPixmap(":/images/unwatched.png");
+    static const QPixmap thumbnail = IconUtils::pixmap(":/images/unwatched.png");
 
     QString name = tr("Unwatched Videos");
 
index 2a7ac2e87620c8cdc0b67e3a3bf7462ce2763b54..9375bb082f6a4164b6ad6ccf87a6e9e0c95a2580 100644 (file)
@@ -32,6 +32,7 @@ $END_LICENSE */
 #endif
 #include "datautils.h"
 #include "compatibility/pathsservice.h"
+#include "iconutils.h"
 
 static DownloadManager *downloadManagerInstance = 0;
 
@@ -73,7 +74,7 @@ void DownloadManager::addItem(Video *video) {
     if (!Activation::instance().isActivated()) {
         if (video->duration() >= 60*4) {
             QMessageBox msgBox(MainWindow::instance());
-            msgBox.setIconPixmap(QPixmap(":/images/app.png").scaled(64, 64, Qt::KeepAspectRatio, Qt::SmoothTransformation));
+            msgBox.setIconPixmap(IconUtils::pixmap(":/images/app.png").scaled(64, 64, Qt::KeepAspectRatio, Qt::SmoothTransformation));
             msgBox.setText(tr("This is just the demo version of %1.").arg(Constants::NAME));
             msgBox.setInformativeText(
                         tr("It can only download videos shorter than %1 minutes so you can test the download functionality.")
index 6b0f61ed2ead07235e85f2f22bee8ff3020dd01b..b975411159ff0ef638b3d557c6086363e969c778 100644 (file)
@@ -33,9 +33,9 @@ QIcon IconUtils::fromTheme(const QString &name) {
 QIcon IconUtils::fromResources(const QString &name) {
     QIcon icon = QIcon(QString(":/images/%1.png").arg(name));
     if (!icon.isNull()) {
-        icon.addPixmap(QString(":/images/%1_active.png").arg(name), QIcon::Active);
-        icon.addPixmap(QString(":/images/%1_selected.png").arg(name), QIcon::Selected);
-        icon.addPixmap(QString(":/images/%1_disabled.png").arg(name), QIcon::Disabled);
+        icon.addPixmap(IconUtils::pixmap(QString(":/images/%1_active.png").arg(name)), QIcon::Active);
+        icon.addPixmap(IconUtils::pixmap(QString(":/images/%1_selected.png").arg(name)), QIcon::Selected);
+        icon.addPixmap(IconUtils::pixmap(QString(":/images/%1_disabled.png").arg(name)), QIcon::Disabled);
     }
     return icon;
 }
@@ -110,3 +110,19 @@ void IconUtils::setupAction(QAction *action) {
                              action->shortcut().toString(QKeySequence::NativeText) +
                              ")");
 }
+
+QPixmap IconUtils::pixmap(const QString &name) {
+    // Check if a "@2x" file exists
+    QString fileName = name;
+    if (qApp->devicePixelRatio() > 1.0) {
+        int dotIndex = fileName.lastIndexOf(QLatin1Char('.'));
+        if (dotIndex != -1) {
+            QString at2xfileName = fileName;
+            at2xfileName.insert(dotIndex, QStringLiteral("@2x"));
+            if (QFile::exists(at2xfileName))
+                fileName = at2xfileName;
+        }
+    }
+
+    return QPixmap(fileName);
+}
index 398fc4ca923ae61119204765b9561a6f65b9c509..851841268c65a413fc4cd0c822d8b2f495a325c6 100644 (file)
@@ -35,6 +35,10 @@ public:
     static QIcon tintedIcon(const QString &name, const QColor &color, const QSize &size);
     static void setupAction(QAction *action);
 
+    // HiDPI stuff
+    static QPixmap pixmap(const QString &name);
+    static qreal maxSupportedPixelRatio() { return 2.0; }
+
 private:
     IconUtils() { }
     static QImage grayscaled(const QImage &image);
index 651506775cdda169d94e2aaa79dea71f7f87b741..ea695ece96b6476c10ca2645c468b12d9dbf3212 100644 (file)
@@ -64,7 +64,7 @@ int main(int argc, char **argv) {
 
 #ifdef Q_OS_MAC
     mac::MacMain();
-    QFont::insertSubstitution(".Helvetica Neue DeskInterface", "Helvetica Neue");
+    // QFont::insertSubstitution(".Helvetica Neue DeskInterface", "Helvetica Neue");
 #endif
 
     QtSingleApplication app(argc, argv);
@@ -81,9 +81,8 @@ int main(int argc, char **argv) {
     app.setOrganizationDomain(Constants::ORG_DOMAIN);
     app.setApplicationVersion(Constants::VERSION);
     app.setAttribute(Qt::AA_DontShowIconsInMenus);
-#ifndef APP_WIN
     app.setWheelScrollLines(1);
-#endif
+    app.setAttribute(Qt::AA_UseHighDpiPixmaps);
 
 #ifdef APP_EXTRA
     Extra::appSetup(&app);
index 5a50548663e3b10650315c084878b570f3b608f8..aba8d47fdfc327b0d014aab696935de9ba67e51b 100644 (file)
@@ -992,6 +992,8 @@ void MainWindow::showWidget(QWidget* widget, bool transition) {
         else title += QLatin1String(" - ") + Constants::NAME;
         setWindowTitle(title);
 
+        statusToolBar->setUpdatesEnabled(false);
+
         // dynamic view actions
         foreach (QAction* action, viewActions)
             showActionInStatusBar(action, false);
@@ -1004,6 +1006,8 @@ void MainWindow::showWidget(QWidget* widget, bool transition) {
         adjustStatusBarVisibility();
         messageLabel->hide();
 
+        statusToolBar->setUpdatesEnabled(true);
+
         /*
         QString desc = metadata.value("description").toString();
         if (!desc.isEmpty()) showMessage(desc);
@@ -1081,7 +1085,7 @@ void MainWindow::showEvent(QShowEvent *e) {
 bool MainWindow::confirmQuit() {
     if (DownloadManager::instance()->activeItems() > 0) {
         QMessageBox msgBox(this);
-        msgBox.setIconPixmap(QPixmap(":/images/app.png").scaled(64, 64, Qt::KeepAspectRatio, Qt::SmoothTransformation));
+        msgBox.setIconPixmap(IconUtils::pixmap(":/images/app.png").scaled(64, 64, Qt::KeepAspectRatio, Qt::SmoothTransformation));
         msgBox.setText(tr("Do you want to exit %1 with a download in progress?").arg(Constants::NAME));
         msgBox.setInformativeText(tr("If you close %1 now, this download will be cancelled.").arg(Constants::NAME));
         msgBox.setModal(true);
@@ -1187,7 +1191,6 @@ void MainWindow::resizeEvent(QResizeEvent *e) {
 #ifdef APP_MAC
     if (initialized && mac::CanGoFullScreen(winId())) {
         bool isFullscreen = mac::IsFullScreen(winId());
-        qDebug() << __PRETTY_FUNCTION__ << isFullscreen << fullscreenFlag;
         if (isFullscreen != fullscreenFlag) {
             if (compactViewAct->isChecked()) {
                 compactViewAct->setChecked(false);
@@ -1725,7 +1728,7 @@ void MainWindow::gotNewVersion(const QString &version) {
 void MainWindow::simpleUpdateDialog(const QString &version) {
     QMessageBox msgBox(this);
     msgBox.setIconPixmap(
-                QPixmap(":/images/app.png")
+                IconUtils::pixmap(":/images/app.png")
                 .scaled(64, 64, Qt::KeepAspectRatio, Qt::SmoothTransformation));
     msgBox.setText(tr("%1 version %2 is now available.").arg(Constants::NAME, version));
     msgBox.setModal(true);
index 7100009b106e957c4f508d61fbb3dd81efa73cce..07443212f01c028a45827dba2589684e8248c72b 100644 (file)
@@ -400,6 +400,8 @@ void MediaView::stop() {
     QSlider *slider = MainWindow::instance()->getSlider();
     slider->setEnabled(false);
     slider->setValue(0);
+#else
+    Phonon::SeekSlider *slider = MainWindow::instance()->getSeekSlider();
 #endif
 
     if (snapshotSettings) {
@@ -796,7 +798,7 @@ void MediaView::demoMessage() {
 #endif
 
     QMessageBox msgBox(this);
-    msgBox.setIconPixmap(QPixmap(":/images/app.png").scaled(64, 64, Qt::KeepAspectRatio, Qt::SmoothTransformation));
+    msgBox.setIconPixmap(IconUtils::pixmap(":/images/app.png").scaled(64, 64, Qt::KeepAspectRatio, Qt::SmoothTransformation));
     msgBox.setText(tr("This is just the demo version of %1.").arg(Constants::NAME));
     msgBox.setInformativeText(tr("It allows you to test the application and see if it works for you."));
     msgBox.setModal(true);
index 7e3be425684fd9c6c3a0173ff600c996cdc03a23..9281b0d62ab5003eea0e2418c9557bf8b01d6ac1 100644 (file)
@@ -20,6 +20,7 @@ $END_LICENSE */
 
 #include "painterutils.h"
 #include "fontutils.h"
+#include "iconutils.h"
 
 PainterUtils::PainterUtils() { }
 
@@ -63,10 +64,9 @@ void PainterUtils::topShadow(QWidget *widget) {
 }
 
 void PainterUtils::paintBadge(QPainter *painter, const QString &text, bool center) {
-    static const QPixmap badge1 = QPixmap(":/images/badge.png");
-    static const QPixmap badge3 = QPixmap(":/images/badge3.png");
-    static const QPixmap badge4 = QPixmap(":/images/badge4.png");
-    static const int size = badge1.height();
+    const QPixmap badge1 = IconUtils::pixmap(":/images/badge.png");
+    const QPixmap badge3 = IconUtils::pixmap(":/images/badge3.png");
+    const QPixmap badge4 = IconUtils::pixmap(":/images/badge4.png");
 
     const int textSize = text.size();
 
@@ -75,10 +75,13 @@ void PainterUtils::paintBadge(QPainter *painter, const QString &text, bool cente
     else if (textSize == 3) badge = badge3;
     else badge = badge4;
 
+    const int w = badge.width() / badge.devicePixelRatio();
+    const int h = badge.height() / badge.devicePixelRatio();
+
     int x = 0;
-    if (center) x -= badge.width() / 2;
+    if (center) x -= w / 2;
 
-    QRect rect(x, 0, badge.width(), size);
+    QRect rect(x, 0, w, h);
     painter->drawPixmap(rect, badge);
 
     QFont f = painter->font();
index 7639a509167d40610285c7b95d11f20661a9cb87..e3383f6c47e4d9c1ad7bfddb9c29e2ac5e525ae2 100644 (file)
@@ -55,10 +55,13 @@ PlaylistItemDelegate::~PlaylistItemDelegate() {
 }
 
 void PlaylistItemDelegate::createPlayIcon() {
-    playIcon = QPixmap(THUMB_WIDTH, THUMB_HEIGHT);
+    qreal maxRatio = IconUtils::maxSupportedPixelRatio();
+    playIcon = QPixmap(THUMB_WIDTH * maxRatio, THUMB_HEIGHT * maxRatio);
+    playIcon.setDevicePixelRatio(maxRatio);
     playIcon.fill(Qt::transparent);
 
-    QPixmap tempPixmap(THUMB_WIDTH, THUMB_HEIGHT);
+    QPixmap tempPixmap(THUMB_WIDTH * maxRatio, THUMB_HEIGHT * maxRatio);
+    tempPixmap.setDevicePixelRatio(maxRatio);
     tempPixmap.fill(Qt::transparent);
     QPainter painter(&tempPixmap);
     painter.setRenderHints(QPainter::Antialiasing, true);
@@ -135,7 +138,7 @@ void PlaylistItemDelegate::paintBody( QPainter* painter,
 
     // play icon overlayed on the thumb
     if (isActive)
-        painter->drawPixmap(playIcon.rect(), playIcon);
+        painter->drawPixmap(0, 0, playIcon);
 
     // time
     if (video->duration() > 0)
index 6f2bced94dc6d3f7d115a739e7fdf235fbd8221c..1d852858a03c1d79abff3c9aebc79f7b4ca900d8 100755 (executable)
@@ -1,4 +1,3 @@
-include(../common.pri)
 INCLUDEPATH += $$PWD
 DEPENDPATH += $$PWD
 QT *= network
index eeb4fe18f2e3413c7ef3b6d4586723a68a188a44..361fe3a930c8be1fb680e3aacfdd04e2d351a79b 100644 (file)
@@ -19,21 +19,17 @@ along with Minitube.  If not, see <http://www.gnu.org/licenses/>.
 $END_LICENSE */
 
 #include "refinesearchbutton.h"
-
-static const int refineButtonSize = 48;
+#include "iconutils.h"
 
 RefineSearchButton::RefineSearchButton(QWidget *parent) :
     QPushButton(parent) {
 
     hovered = false;
 
+    const int refineButtonSize = 48;
     setMinimumSize(refineButtonSize, refineButtonSize);
     setMaximumSize(refineButtonSize, refineButtonSize);
     setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed);
-    setStyleSheet(
-                "background: red url(:/images/refine-search.png) no-repeat center;"
-                "border: 0;"
-                );
 }
 
 void RefineSearchButton::paintBackground() const {
@@ -41,19 +37,18 @@ void RefineSearchButton::paintBackground() const {
 }
 
 void RefineSearchButton::paintEvent(QPaintEvent *) {
-    // QPushButton::paintEvent(event);
     QPainter painter(this);
     painter.setRenderHints(QPainter::Antialiasing, true);
+    painter.setPen(Qt::NoPen);
     painter.setBrush(QColor(0,0,0, hovered ? 192 : 170));
-    QPen pen(Qt::white);
-    pen.setWidth(2);
-    painter.setPen(pen);
     painter.drawEllipse(QPoint(width(), height()), width()-2, height()-2);
 
-    QPixmap icon = QPixmap(":/images/refine-search.png");
-    painter.drawPixmap(width() - icon.width() - 6, height() - icon.height() - 6,
-                       icon.width(), icon.height(),
-                       icon);
+    QPixmap pixmap = IconUtils::pixmap(":/images/refine-search.png");
+    int pw = pixmap.width() / pixmap.devicePixelRatio();
+    int ph = pixmap.height() / pixmap.devicePixelRatio();
+    painter.drawPixmap(width() - pw - 6, height() - ph - 6,
+                       pw, ph,
+                       pixmap);
 }
 
 void RefineSearchButton::enterEvent(QEvent *) {
index ddd0999f97046230d21ed7ed7cbd3d4bb53f432f..5948f2da63c519749d79939511f22444fcedf6e0 100644 (file)
@@ -23,6 +23,7 @@ $END_LICENSE */
 #ifdef APP_EXTRA
 #include "extra.h"
 #endif
+#include "iconutils.h"
 
 namespace The {
 QHash<QString, QAction*>* globalActions();
@@ -155,7 +156,8 @@ void RefineSearchWidget::setupLabel(const QString &text, QBoxLayout *layout, con
     QLabel *icon = new QLabel(this);
     icon->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed);
     QString resource = paramName;
-    QPixmap pixmap = QPixmap(":/images/search-" + resource + ".png");
+    QPixmap pixmap = IconUtils::pixmap(":/images/search-" + resource + ".png");
+    /*
     QPixmap translucentPixmap(pixmap.size());
     translucentPixmap.fill(Qt::transparent);
     QPainter painter;
@@ -163,11 +165,11 @@ void RefineSearchWidget::setupLabel(const QString &text, QBoxLayout *layout, con
     painter.setOpacity(0.5);
     painter.drawPixmap(0, 0, pixmap);
     painter.end();
-    icon->setPixmap(translucentPixmap);
+    */
+    icon->setPixmap(pixmap);
     hLayout->addWidget(icon);
 
     QLabel *label = new QLabel(text, this);
-    label->setStyleSheet("color: rgba(0, 0, 0, 128);");
     hLayout->addWidget(label);
 
     icon->setMaximumHeight(label->height());
index aa0038a86f603ddeb1da82cb8d764a72e4c89a63..6f3280e7e515b98e578e212f4a4e54181b8214a2 100644 (file)
@@ -37,6 +37,7 @@ $END_LICENSE */
 #endif
 #include "mainwindow.h"
 #include "painterutils.h"
+#include "iconutils.h"
 
 namespace The {
 QHash<QString, QAction*>* globalActions();
@@ -70,7 +71,7 @@ SearchView::SearchView(QWidget *parent) : View(parent) {
     mainLayout->addLayout(hLayout);
 
     QLabel *logo = new QLabel(this);
-    logo->setPixmap(QPixmap(":/images/app.png"));
+    logo->setPixmap(IconUtils::pixmap(":/images/app.png"));
     hLayout->addWidget(logo, 0, Qt::AlignTop);
     hLayout->addSpacing(PADDING);
 
@@ -257,7 +258,7 @@ void SearchView::updateRecentKeywords() {
         itemLabel->setAttribute(Qt::WA_DeleteOnClose);
         itemLabel->setProperty("recentItem", true);
         itemLabel->setMaximumWidth(queryEdit->toWidget()->width() + watchButton->width());
-        // itemLabel->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed);
+        itemLabel->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed);
         // Make links navigable with the keyboard too
         itemLabel->setTextInteractionFlags(Qt::LinksAccessibleByKeyboard | Qt::LinksAccessibleByMouse);
         if (needStatusTip)
index e27ff64079b9f1d0222974833f3b3c07d178b68a..88172ab990d0bbe479eadcf9dc830602a6157ac0 100644 (file)
@@ -173,7 +173,7 @@ QAction *SegmentedControl::hoveredAction(const QPoint& pos) const {
     return(d->actionList[buttonIndex]);
 }
 
-int SegmentedControl::calculateButtonWidth (void) const {
+int SegmentedControl::calculateButtonWidth() const {
     QFontMetrics fontMetrics(font());
     int tmpItemWidth, itemWidth = 0;
     foreach (QAction *action, d->actionList) {
@@ -195,7 +195,6 @@ void SegmentedControl::drawButton (QPainter *painter,
 void SegmentedControl::drawUnselectedButton (QPainter *painter,
                                         const QRect& rect,
                                         const QAction *action) {
-    painter->setPen(QPen(QColor(0, 0, 0, 128), 1));
     paintButton(painter, rect, action);
 }
 
@@ -216,7 +215,6 @@ void SegmentedControl::drawSelectedButton (QPainter *painter,
     painter->fillRect(0, 0, width, height, QBrush(gradient));
 
     painter->restore();
-    painter->setPen(QPen(QColor(0, 0, 0, 232), 1));
     paintButton(painter, rect, action);
 }
 
@@ -228,7 +226,7 @@ void SegmentedControl::paintButton(QPainter *painter, const QRect& rect, const Q
     const int width = rect.width();
 
     painter->save();
-    painter->setPen(borderColor);
+    painter->setPen(QPen(borderColor, 1.0 / qApp->devicePixelRatio()));
 #if defined(APP_MAC) | defined(APP_WIN)
     painter->drawRect(-1, -1, width, height);
 #else
index bab83b1aaafcdbc5abcd059773cd9770a742ac56..4f3ec85899c4f118185b31b60d99d2082ee19301 100644 (file)
@@ -62,7 +62,7 @@ private:
                     const QRect& rect,
                     const QAction *action);
     QAction *hoveredAction(const QPoint& pos) const;
-    int calculateButtonWidth(void) const;
+    int calculateButtonWidth() const;
 
     class Private;
     Private *d;
index 03edbdad3240b89f882038100c3ec0b3ee232b7c..2a05f07692e3fad88399275b7899a81514be1932 100644 (file)
@@ -94,21 +94,19 @@ void Video::loadThumbnail() {
     connect(reply, SIGNAL(data(QByteArray)), SLOT(setThumbnail(QByteArray)));
 }
 
-void Video::setThumbnail(QByteArray bytes) {
+void Video::setThumbnail(const QByteArray &bytes) {
     loadingThumbnail = false;
+    qreal ratio = qApp->devicePixelRatio();
     m_thumbnail = QPixmap();
     m_thumbnail.loadFromData(bytes);
-    if (m_thumbnail.width() > 160)
-        m_thumbnail = m_thumbnail.scaledToWidth(160, Qt::SmoothTransformation);
+    m_thumbnail.setDevicePixelRatio(ratio);
+    const int thumbWidth = 160 * ratio;
+    if (m_thumbnail.width() > thumbWidth)
+        m_thumbnail = m_thumbnail.scaledToWidth(thumbWidth, Qt::SmoothTransformation);
+    qDebug() << __PRETTY_FUNCTION__ << m_thumbnail.size();
     emit gotThumbnail();
 }
 
-void Video::loadMediumThumbnail() {
-    if (m_mediumThumbnailUrl.isEmpty()) return;
-    QObject *reply = The::http()->get(m_mediumThumbnailUrl);
-    connect(reply, SIGNAL(data(QByteArray)), SIGNAL(gotMediumThumbnail(QByteArray)));
-}
-
 void Video::loadStreamUrl() {
     if (loadingStreamUrl) {
         qDebug() << "Already loading stream URL for" << this->title();
@@ -156,8 +154,8 @@ void  Video::getVideoInfo() {
     // see you in gotVideoInfo...
 }
 
-void  Video::gotVideoInfo(QByteArray data) {
-    QString videoInfo = QString::fromUtf8(data);
+void  Video::gotVideoInfo(const QByteArray &bytes) {
+    QString videoInfo = QString::fromUtf8(bytes);
     // qDebug() << "videoInfo" << videoInfo;
 
     // get video token
@@ -292,8 +290,8 @@ void Video::errorVideoInfo(QNetworkReply *reply) {
     emit errorStreamUrl(tr("Network error: %1 for %2").arg(reply->errorString(), reply->url().toString()));
 }
 
-void Video::scrapeWebPage(QByteArray data) {
-    QString html = QString::fromUtf8(data);
+void Video::scrapeWebPage(const QByteArray &bytes) {
+    QString html = QString::fromUtf8(bytes);
 
     QRegExp ageGateRE(JsFunctions::instance()->ageGateRE());
     if (ageGateRE.indexIn(html) != -1) {
@@ -347,7 +345,7 @@ void Video::scrapeWebPage(QByteArray data) {
     }
 }
 
-void Video::parseJsPlayer(QByteArray bytes) {
+void Video::parseJsPlayer(const QByteArray &bytes) {
     QString js = QString::fromUtf8(bytes);
     // qWarning() << "jsPlayer" << js;
 
@@ -393,7 +391,7 @@ void Video::parseJsPlayer(QByteArray bytes) {
     parseFmtUrlMap(fmtUrlMap, true);
 }
 
-void Video::parseDashManifest(QByteArray bytes) {
+void Video::parseDashManifest(const QByteArray &bytes) {
     QFile file(Temporary::filename() + ".mpd");
     if (!file.open(QIODevice::WriteOnly))
         qWarning() << file.errorString() << file.fileName();
index d502cb24d6dee94f1fa5287ccc5c09a60a257299..f612d90879bd93f6b2c9cf4fce107d9a8e880c97 100644 (file)
@@ -42,65 +42,68 @@ public:
         LicenseCC
     };
 
-    const QString & title() const { return m_title; }
-    void setTitle(const QString &title) { m_title = title; }
+    const QString &title() const { return m_title; }
+    void setTitle(const QString &value) { m_title = value; }
 
-    const QString & description() const { return m_description; }
-    void setDescription(const QString &description) { m_description = description; }
+    const QString &description() const { return m_description; }
+    void setDescription(const QString &value) { m_description = value; }
 
-    const QString & channelTitle() const { return m_channelTitle; }
+    const QString &channelTitle() const { return m_channelTitle; }
     void setChannelTitle(const QString &value) { m_channelTitle = value; }
 
-    const QString & channelId() const { return m_channelId; }
+    const QString &channelId() const { return m_channelId; }
     void setChannelId(const QString &value ) { m_channelId = value; }
 
-    const QString & webpage();
+    const QString &webpage();
     void setWebpage(const QString &value);
 
     void loadThumbnail();
-    const QPixmap & thumbnail() const { return m_thumbnail; }
+    const QPixmap &thumbnail() const { return m_thumbnail; }
 
-    const QString & thumbnailUrl() { return m_thumbnailUrl; }
-    void setThumbnailUrl(const QString &url) { m_thumbnailUrl = url; }
+    const QString &thumbnailUrl() { return m_thumbnailUrl; }
+    void setThumbnailUrl(const QString &value) { m_thumbnailUrl = value; }
 
-    void loadMediumThumbnail();
-    const QString & mediumThumbnailUrl() { return m_mediumThumbnailUrl; }
-    void setMediumThumbnailUrl(const QString &url) { m_mediumThumbnailUrl = url; }
+    const QString &mediumThumbnailUrl() { return m_mediumThumbnailUrl; }
+    void setMediumThumbnailUrl(const QString &value) { m_mediumThumbnailUrl = value; }
+
+    const QString &largeThumbnailUrl() { return m_largeThumbnailUrl; }
+    void setLargeThumbnailUrl(const QString &value) { m_largeThumbnailUrl = value; }
 
     int duration() const { return m_duration; }
-    void setDuration( int duration ) { m_duration = duration; }
+    void setDuration(int value) { m_duration = value; }
     QString formattedDuration() const;
 
     int viewCount() const { return m_viewCount; }
-    void setViewCount( int viewCount ) { m_viewCount = viewCount; }
+    void setViewCount(int viewCount) { m_viewCount = viewCount; }
 
-    const QDateTime & published() const { return m_published; }
-    void setPublished(const QDateTime &published ) { m_published = published; }
+    const QDateTime &published() const { return m_published; }
+    void setPublished(const QDateTime &value) { m_published = value; }
 
     int getDefinitionCode() const { return definitionCode; }
 
     void loadStreamUrl();
-    const QUrl & getStreamUrl() { return m_streamUrl; }
+    const QUrl &getStreamUrl() { return m_streamUrl; }
 
     void setId(const QString &value) { videoId = value; }
-    const QString & id() const { return videoId; }
+    const QString &id() const { return videoId; }
 
-    void setLicense(License license) { m_license = license; }
+    void setLicense(License value) { m_license = value; }
     License license() const { return m_license; }
 
 signals:
     void gotThumbnail();
-    void gotMediumThumbnail(QByteArray bytes);
-    void gotStreamUrl(QUrl streamUrl);
-    void errorStreamUrl(QString message);
+    void gotMediumThumbnail(const QByteArray &bytes);
+    void gotLargeThumbnail(const QByteArray &bytes);
+    void gotStreamUrl(const QUrl &streamUrl);
+    void errorStreamUrl(const QString &message);
 
 private slots:
-    void setThumbnail(QByteArray bytes);
-    void gotVideoInfo(QByteArray);
-    void errorVideoInfo(QNetworkReply*);
-    void scrapeWebPage(QByteArray);
-    void parseJsPlayer(QByteArray bytes);
-    void parseDashManifest(QByteArray bytes);
+    void setThumbnail(const QByteArray &bytes);
+    void gotVideoInfo(const QByteArray &bytes);
+    void errorVideoInfo(QNetworkReply *reply);
+    void scrapeWebPage(const QByteArray &bytes);
+    void parseJsPlayer(const QByteArray &bytes);
+    void parseDashManifest(const QByteArray &bytes);
 
 private:
     void getVideoInfo();
@@ -108,7 +111,7 @@ private:
     void captureFunction(const QString &name, const QString &js);
     void captureObject(const QString &name, const QString &js);
     QString decryptSignature(const QString &s);
-    void saveDefinitionForUrl(const QString& url, const VideoDefinition& definition);
+    void saveDefinitionForUrl(const QString &url, const VideoDefinition &definition);
 
     QString m_title;
     QString m_description;
@@ -119,6 +122,7 @@ private:
     QPixmap m_thumbnail;
     QString m_thumbnailUrl;
     QString m_mediumThumbnailUrl;
+    QString m_largeThumbnailUrl;
     int m_duration;
     QDateTime m_published;
     int m_viewCount;
index ccd2a0f87448fb07223643f0df36d3724e20236a..ce1a92fc498b143b56a1de64638bfc74df9c1e26 100644 (file)
@@ -22,16 +22,21 @@ $END_LICENSE */
 #include "videosource.h"
 #include "video.h"
 #include "fontutils.h"
+#include "iconutils.h"
+#include "networkaccess.h"
+
+namespace The {
+NetworkAccess* http();
+}
 
 VideoSourceWidget::VideoSourceWidget(VideoSource *videoSource, QWidget *parent)
     : GridWidget(parent),
-      videoSource(videoSource) {
+      videoSource(videoSource),
+      lastPixelRatio(0) {
 
     setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
 
-    connect(videoSource, SIGNAL(gotVideos(QList<Video*>)),
-            SLOT(previewVideo(QList<Video*>)), Qt::UniqueConnection);
-    videoSource->loadVideos(1, 1);
+    loadPreview();
 
     connect(this, SIGNAL(activated()), SLOT(activate()));
 }
@@ -40,26 +45,38 @@ void VideoSourceWidget::activate() {
     emit activated(videoSource);
 }
 
-void VideoSourceWidget::previewVideo(QList<Video*> videos) {
+void VideoSourceWidget::previewVideo(const QList<Video *> &videos) {
     videoSource->disconnect();
     if (videos.isEmpty()) return;
-    video = videos.first();
-    connect(video, SIGNAL(gotMediumThumbnail(QByteArray)),
-            SLOT(setPixmapData(QByteArray)), Qt::UniqueConnection);
-    video->loadMediumThumbnail();
+    Video *video = videos.first();
+    lastPixelRatio = window()->devicePixelRatio();
+    bool needLargeThumb = lastPixelRatio > 1.0 || window()->width() > 2000;
+    QString url =  needLargeThumb ? video->largeThumbnailUrl() : video->mediumThumbnailUrl();
+    if (url.isEmpty()) url = video->mediumThumbnailUrl();
+    video->deleteLater();
+    QObject *reply = The::http()->get(url);
+    connect(reply, SIGNAL(data(QByteArray)), SLOT(setPixmapData(QByteArray)));
 }
 
-void VideoSourceWidget::setPixmapData(QByteArray bytes) {
-    video->deleteLater();
-    video = 0;
+void VideoSourceWidget::setPixmapData(const QByteArray &bytes) {
     pixmap.loadFromData(bytes);
+    pixmap.setDevicePixelRatio(lastPixelRatio);
     update();
 }
 
+void VideoSourceWidget::loadPreview() {
+    connect(videoSource, SIGNAL(gotVideos(QList<Video*>)),
+            SLOT(previewVideo(QList<Video*>)), Qt::UniqueConnection);
+    videoSource->loadVideos(1, 1);
+}
+
 QPixmap VideoSourceWidget::playPixmap() {
     const int s = height() / 2;
     const int padding = s / 8;
-    QPixmap playIcon = QPixmap(s, s);
+
+    qreal ratio = window()->devicePixelRatio();
+    QPixmap playIcon = QPixmap(s * ratio, s * ratio);
+    playIcon.setDevicePixelRatio(ratio);
     playIcon.fill(Qt::transparent);
     QPainter painter(&playIcon);
     QPolygon polygon;
@@ -84,11 +101,13 @@ QPixmap VideoSourceWidget::playPixmap() {
 void VideoSourceWidget::paintEvent(QPaintEvent *event) {
     GridWidget::paintEvent(event);
     if (pixmap.isNull()) return;
+    if (window()->devicePixelRatio() != lastPixelRatio) loadPreview();
 
     QPainter p(this);
 
-    const int w = width();
-    const int h = height();
+    qreal ratio = lastPixelRatio;
+    int w = width() * ratio;
+    int h = height() * ratio;
 
     int xOffset = 0;
     int xOrigin = 0;
@@ -102,13 +121,16 @@ void VideoSourceWidget::paintEvent(QPaintEvent *event) {
     else yOrigin = -hDiff / 2;
     p.drawPixmap(xOrigin, yOrigin, pixmap, xOffset, yOffset, w, h);
 
+    w = width();
+    h = height();
+
     if (hovered) {
         QPixmap play = playPixmap();
         p.save();
         p.setOpacity(.5);
         p.drawPixmap(
-                    (w - play.width()) / 2,
-                    (h * 2/3 - play.height()) / 2,
+                    (w - play.width() * ratio) / 2,
+                    (h * 2/3 - play.height() * ratio) / 2,
                     play
                     );
         p.restore();
index 1aab7c432d292b73c464ccb42bc02e4207781924..185e615ba156930b949d42340d8d4c52f5ade304 100644 (file)
@@ -45,14 +45,16 @@ protected:
 
 private slots:
     void activate();
-    void previewVideo(QList<Video*> videos);
-    void setPixmapData(QByteArray bytes);
+    void previewVideo(const QList<Video*> &videos);
+    void setPixmapData(const QByteArray &bytes);
 
 private:
+    void loadPreview();
+
     QPixmap playPixmap();
     VideoSource *videoSource;
     QPixmap pixmap;
-    Video *video;
+    qreal lastPixelRatio;
 
 };
 
index ed65c7232176c90d0b68f64b2d714ad338a6347e..45aa536e91454a34de83129c867a1eb6040ee14c 100644 (file)
@@ -3,7 +3,6 @@
 #include "datautils.h"
 
 YT3ListParser::YT3ListParser(const QByteArray &bytes) {
-
     QScriptEngine engine;
     QScriptValue json = engine.evaluate("(" + QString::fromUtf8(bytes) + ")");
 
@@ -54,6 +53,7 @@ void YT3ListParser::parseItem(const QScriptValue &item) {
     QScriptValue thumbnails = snippet.property("thumbnails");
     video->setThumbnailUrl(thumbnails.property("medium").property("url").toString());
     video->setMediumThumbnailUrl(thumbnails.property("high").property("url").toString());
+    video->setLargeThumbnailUrl(thumbnails.property("standard").property("url").toString());
 
     video->setChannelTitle(snippet.property("channelTitle").toString());
 
index bcebcfed0ed4e1ada2677d4ba1491e593a5cbd81..a80879af1736c586325db3bbf898cd6542aefafe 100644 (file)
@@ -29,6 +29,7 @@ $END_LICENSE */
 #endif
 #include "compatibility/qurlqueryhelper.h"
 #include "compatibility/pathsservice.h"
+#include "iconutils.h"
 
 namespace The {
 NetworkAccess* http();
@@ -74,6 +75,7 @@ YTChannel* YTChannel::forId(const QString &channelId) {
         channel->checked = query.value(6).toUInt();
         channel->loaded = query.value(7).toUInt();
         channel->thumbnail = QPixmap(channel->getThumbnailLocation());
+        channel->thumbnail.setDevicePixelRatio(IconUtils::maxSupportedPixelRatio());
         channel->maybeLoadfromAPI();
         cache.insert(channelId, channel);
     }
@@ -132,7 +134,7 @@ void YTChannel::parseResponse(const QByteArray &bytes) {
                 displayName = snippet.property("title").toString();
                 description = snippet.property("description").toString();
                 QScriptValue thumbnails = snippet.property("thumbnails");
-                thumbnailUrl = thumbnails.property("default").property("url").toString();
+                thumbnailUrl = thumbnails.property("medium").property("url").toString();
                 qDebug() << displayName << description << thumbnailUrl;
             }
         }
@@ -180,10 +182,6 @@ void YTChannel::loadThumbnail() {
     if (thumbnailUrl.isEmpty()) return;
     loadingThumbnail = true;
 
-#ifdef Q_OS_WIN
-    thumbnailUrl.replace(QLatin1String("https://"), QLatin1String("http://"));
-#endif
-
     QUrl url(thumbnailUrl);
     QObject *reply = The::http()->get(url);
     connect(reply, SIGNAL(data(QByteArray)), SLOT(storeThumbnail(QByteArray)));
@@ -216,13 +214,16 @@ void YTChannel::unsubscribe() {
 
 void YTChannel::storeThumbnail(const QByteArray &bytes) {
     thumbnail.loadFromData(bytes);
-    static const int maxWidth = 88;
+    qreal maxRatio = IconUtils::maxSupportedPixelRatio();
+    thumbnail.setDevicePixelRatio(maxRatio);
+    const int maxWidth = 88 * maxRatio;
 
     QDir dir;
     dir.mkpath(getThumbnailDir());
 
     if (thumbnail.width() > maxWidth) {
         thumbnail = thumbnail.scaledToWidth(maxWidth, Qt::SmoothTransformation);
+        thumbnail.setDevicePixelRatio(maxRatio);
         thumbnail.save(getThumbnailLocation(), "JPG");
     } else {
         QFile file(getThumbnailLocation());