From e5ce2f5e3de0d40ab90e0bf6d8eb5aa308077c4d Mon Sep 17 00:00:00 2001 From: nowrep Date: Sun, 8 Apr 2012 21:45:40 +0200 Subject: [PATCH] Added animated tab previews (by Alexander Samilovskih) - thanks a lot for his work! - option to disable animations in preferences -> tabs --- src/lib/bookmarks/bookmarksmodel.cpp | 2 +- src/lib/lib.pro | 2 + src/lib/plugins/plugins.cpp | 2 +- src/lib/plugins/speeddial.cpp | 2 +- src/lib/preferences/preferences.cpp | 2 + src/lib/preferences/preferences.ui | 31 ++++-- src/lib/webview/tabbar.cpp | 46 ++++++++ src/lib/webview/tabbar.h | 7 ++ src/lib/webview/tabbedwebview.cpp | 1 - src/lib/webview/tabpreview.cpp | 161 +++++++++++++++++++++++++++ src/lib/webview/tabpreview.h | 57 ++++++++++ src/lib/webview/webtab.cpp | 25 ++++- src/lib/webview/webtab.h | 2 + 13 files changed, 323 insertions(+), 17 deletions(-) create mode 100644 src/lib/webview/tabpreview.cpp create mode 100644 src/lib/webview/tabpreview.h diff --git a/src/lib/bookmarks/bookmarksmodel.cpp b/src/lib/bookmarks/bookmarksmodel.cpp index 23f0db44b..b30339653 100644 --- a/src/lib/bookmarks/bookmarksmodel.cpp +++ b/src/lib/bookmarks/bookmarksmodel.cpp @@ -217,7 +217,7 @@ void BookmarksModel::removeBookmark(const QList list) QSqlDatabase db = QSqlDatabase::database(); db.transaction(); - foreach (int id, list) { + foreach(int id, list) { QSqlQuery query; query.prepare("SELECT url, title, folder FROM bookmarks WHERE id = ?"); query.bindValue(0, id); diff --git a/src/lib/lib.pro b/src/lib/lib.pro index 545e90206..9ae30faa1 100644 --- a/src/lib/lib.pro +++ b/src/lib/lib.pro @@ -34,6 +34,7 @@ INCLUDEPATH += 3rdparty\ popupwindow\ SOURCES += \ + webview/tabpreview.cpp \ 3rdparty/qtwin.cpp \ 3rdparty/lineedit.cpp \ app/qupzilla.cpp \ @@ -171,6 +172,7 @@ SOURCES += \ tools/plaineditwithlines.cpp HEADERS += \ + webview/tabpreview.h \ 3rdparty/qtwin.h \ 3rdparty/lineedit.h \ app/qupzilla.h \ diff --git a/src/lib/plugins/plugins.cpp b/src/lib/plugins/plugins.cpp index 6401191c2..6f9354065 100644 --- a/src/lib/plugins/plugins.cpp +++ b/src/lib/plugins/plugins.cpp @@ -226,7 +226,7 @@ void Plugins::refreshLoadedPlugins() bool Plugins::alreadySpecInAvailable(const PluginSpec &spec) { - foreach (const Plugin & plugin, m_availablePlugins) { + foreach(const Plugin & plugin, m_availablePlugins) { if (plugin.pluginSpec == spec) { return true; } diff --git a/src/lib/plugins/speeddial.cpp b/src/lib/plugins/speeddial.cpp index 77cc8bce2..338b1eb72 100644 --- a/src/lib/plugins/speeddial.cpp +++ b/src/lib/plugins/speeddial.cpp @@ -279,7 +279,7 @@ QString SpeedDial::getOpenFileName() const QString &image = QFileDialog::getOpenFileName(0, tr("Select image..."), QDir::homePath(), fileTypes); if (image.isEmpty()) { - return image; + return image; } return QUrl::fromLocalFile(image).toString(); diff --git a/src/lib/preferences/preferences.cpp b/src/lib/preferences/preferences.cpp index 0263ddac7..9c537109c 100644 --- a/src/lib/preferences/preferences.cpp +++ b/src/lib/preferences/preferences.cpp @@ -168,6 +168,7 @@ Preferences::Preferences(QupZilla* mainClass, QWidget* parent) ui->dontQuitOnTab->setChecked(settings.value("dontQuitWithOneTab", false).toBool()); ui->askWhenClosingMultipleTabs->setChecked(settings.value("AskOnClosing", false).toBool()); ui->closedInsteadOpened->setChecked(settings.value("closedInsteadOpenedTabs", false).toBool()); + ui->animatedTabPreviews->setChecked(settings.value("previewAnimationsEnabled", true).toBool()); settings.endGroup(); //AddressBar settings.beginGroup("AddressBar"); @@ -759,6 +760,7 @@ void Preferences::saveSettings() settings.setValue("dontQuitWithOneTab", ui->dontQuitOnTab->isChecked()); settings.setValue("AskOnClosing", ui->askWhenClosingMultipleTabs->isChecked()); settings.setValue("closedInsteadOpenedTabs", ui->closedInsteadOpened->isChecked()); + settings.setValue("previewAnimationsEnabled", ui->animatedTabPreviews->isChecked()); settings.endGroup(); //DOWNLOADS diff --git a/src/lib/preferences/preferences.ui b/src/lib/preferences/preferences.ui index aaa5021ad..01c16cdbb 100644 --- a/src/lib/preferences/preferences.ui +++ b/src/lib/preferences/preferences.ui @@ -626,21 +626,21 @@ - + Hide tabs when there is only one tab - + <b>Address Bar behaviour</b> - + Qt::Vertical @@ -653,7 +653,7 @@ - + Qt::Vertical @@ -666,28 +666,28 @@ - + Select all text by double clicking in address bar - + Add .co.uk domain by pressing ALT key - + Ask when closing multiple tabs - + Select all text by clicking in address bar @@ -707,34 +707,41 @@ - + Activate last tab when closing active tab - + Don't quit upon closing last tab - + Closed tabs list instead of opened in tab bar - + Open new tabs after active tab + + + + Make tab previews animated + + + diff --git a/src/lib/webview/tabbar.cpp b/src/lib/webview/tabbar.cpp index 24f734058..6925149be 100644 --- a/src/lib/webview/tabbar.cpp +++ b/src/lib/webview/tabbar.cpp @@ -17,6 +17,7 @@ * ============================================================ */ #include "tabbar.h" #include "tabwidget.h" +#include "tabpreview.h" #include "qupzilla.h" #include "webtab.h" #include "iconprovider.h" @@ -29,6 +30,7 @@ #include #include #include +#include #define MAXIMUM_TAB_WIDTH 250 #define MINIMUM_TAB_WIDTH 50 @@ -45,8 +47,10 @@ TabBar::TabBar(QupZilla* mainClass, TabWidget* tabWidget) : QTabBar() , p_QupZilla(mainClass) , m_tabWidget(tabWidget) + , m_tabPreview(new TabPreview(mainClass, tabWidget)) , m_clickedTab(0) , m_pinnedTabsCount(0) + , m_currentTabPreview(-1) , m_normalTabWidth(0) , m_lastTabWidth(0) , m_adjustingLastTab(false) @@ -57,6 +61,7 @@ TabBar::TabBar(QupZilla* mainClass, TabWidget* tabWidget) setTabsClosable(true); setDocumentMode(true); setFocusPolicy(Qt::NoFocus); + setMouseTracking(true); setAcceptDrops(true); @@ -71,6 +76,7 @@ void TabBar::loadSettings() settings.beginGroup("Browser-Tabs-Settings"); setMovable(settings.value("makeTabsMovable", true).toBool()); + m_tabPreview->setAnimationsEnabled(settings.value("previewAnimationsEnabled", true).toBool()); if (settings.value("ActivateLastTabWhenClosingActual", false).toBool()) { setSelectionBehaviorOnRemove(QTabBar::SelectPreviousTab); @@ -107,6 +113,8 @@ void TabBar::setVisible(bool visible) emit hideButtons(); } + m_tabPreview->setVisible(false); + QTabBar::setVisible(visible); } @@ -337,6 +345,22 @@ int TabBar::normalTabsCount() return count() - m_pinnedTabsCount; } +void TabBar::showTabPreview() +{ + WebTab* webTab = qobject_cast(m_tabWidget->widget(m_currentTabPreview)); + if (!webTab) { + return; + } + + m_tabPreview->setWebTab(webTab, m_currentTabPreview == currentIndex()); + m_tabPreview->showOnRect(tabRect(m_currentTabPreview)); +} + +void TabBar::hideTabPreview() +{ + m_tabPreview->hide(); +} + void TabBar::mouseDoubleClickEvent(QMouseEvent* event) { if (mApp->plugins()->processMouseDoubleClick(Qz::ON_TabBar, this, event)) { @@ -380,6 +404,20 @@ void TabBar::mouseMoveEvent(QMouseEvent* event) } } + //Tab Preview + + const int tab = tabAt(event->pos()); + + if (tab != -1 && tab != m_currentTabPreview && event->buttons() == Qt::NoButton) { + m_currentTabPreview = tab; + if (m_tabPreview->isVisible()) { + showTabPreview(); + } + else { + QTimer::singleShot(200, this, SLOT(showTabPreview())); + } + } + QTabBar::mouseMoveEvent(event); } @@ -411,6 +449,14 @@ void TabBar::mouseReleaseEvent(QMouseEvent* event) QTabBar::mouseReleaseEvent(event); } +void TabBar::leaveEvent(QEvent* event) +{ + hideTabPreview(); + m_currentTabPreview = -1; + + QTabBar::leaveEvent(event); +} + void TabBar::wheelEvent(QWheelEvent* event) { if (mApp->plugins()->processWheelEvent(Qz::ON_TabBar, this, event)) { diff --git a/src/lib/webview/tabbar.h b/src/lib/webview/tabbar.h index cc121c68f..1a9ed4c85 100644 --- a/src/lib/webview/tabbar.h +++ b/src/lib/webview/tabbar.h @@ -24,6 +24,7 @@ class QupZilla; class TabWidget; +class TabPreview; class QT_QUPZILLA_EXPORT TabBar : public QTabBar { @@ -74,11 +75,15 @@ private slots: void pinTab(); void closeCurrentTab(); + void showTabPreview(); + void hideTabPreview(); + private: void mouseDoubleClickEvent(QMouseEvent* event); void mousePressEvent(QMouseEvent* event); void mouseMoveEvent(QMouseEvent* event); void mouseReleaseEvent(QMouseEvent* event); + void leaveEvent(QEvent* event); void wheelEvent(QWheelEvent* event); void dragEnterEvent(QDragEnterEvent* event); @@ -91,12 +96,14 @@ private: QupZilla* p_QupZilla; TabWidget* m_tabWidget; + TabPreview* m_tabPreview; bool m_showCloseButtonWithOneTab; bool m_showTabBarWithOneTab; int m_clickedTab; int m_pinnedTabsCount; + int m_currentTabPreview; int m_normalTabWidth; int m_lastTabWidth; diff --git a/src/lib/webview/tabbedwebview.cpp b/src/lib/webview/tabbedwebview.cpp index e74a15de5..aaf73d4d0 100644 --- a/src/lib/webview/tabbedwebview.cpp +++ b/src/lib/webview/tabbedwebview.cpp @@ -180,7 +180,6 @@ void TabbedWebView::setIp(const QHostInfo &info) void TabbedWebView::titleChanged() { const QString &t = title(); - m_tabWidget->setTabToolTip(tabIndex(), t); if (isCurrent()) { p_QupZilla->setWindowTitle(tr("%1 - QupZilla").arg(t)); diff --git a/src/lib/webview/tabpreview.cpp b/src/lib/webview/tabpreview.cpp new file mode 100644 index 000000000..70d8764b6 --- /dev/null +++ b/src/lib/webview/tabpreview.cpp @@ -0,0 +1,161 @@ +/* ============================================================ +* QupZilla - WebKit based browser +* Copyright (C) 2010-2012 Alexander Samilovskih +* David Rosca +* +* This program is free software: you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation, either version 3 of the License, or +* (at your option) any later version. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program. If not, see . +* ============================================================ */ +#include "qupzilla.h" +#include "tabpreview.h" +#include "webtab.h" +#include "tabbedwebview.h" + +#include +#include +#include +#include +#include +#include +#include + +TabPreview::TabPreview(QupZilla* mainClass, QWidget* parent) + : QFrame(parent) + , p_QupZilla(mainClass) + , m_pixmap(new QLabel) + , m_title(new QLabel) + , m_animationsEnabled(true) +{ + m_pixmap->setAlignment(Qt::AlignHCenter); + m_title->setAlignment(Qt::AlignHCenter); + m_title->setWordWrap(true); + + QVBoxLayout* layout = new QVBoxLayout(this); + layout->addWidget(m_pixmap); + layout->addWidget(m_title); + layout->setMargin(0); + layout->setAlignment(Qt::AlignCenter); + setLayout(layout); + + setBackgroundRole(QPalette::ToolTipBase); + setForegroundRole(QPalette::ToolTipText); + + setContentsMargins(5, 5, 5, 5); + setMaximumWidth(250); + setMaximumHeight(170); + + m_animation = new QPropertyAnimation(this, "geometry", this); +} + +void TabPreview::setWebTab(WebTab* webTab, bool noPixmap) +{ + if (webTab->isRestored() && !webTab->isLoading() && !noPixmap) { + m_title->setText(webTab->title()); + m_pixmap->setPixmap(webTab->renderTabPreview()); + m_pixmap->show(); + } + else { + m_title->setText(webTab->title()); + m_pixmap->hide(); + } +} + +void TabPreview::setAnimationsEnabled(bool enabled) +{ + m_animationsEnabled = enabled; +} + +void TabPreview::paintEvent(QPaintEvent* pe) +{ + QStyleOptionFrame opt; + opt.init(this); + + QStylePainter painter(this); + painter.setClipRegion(pe->region()); + painter.drawPrimitive(QStyle::PE_PanelTipLabel, opt); +} + +void TabPreview::setFinishingGeometry(const QRect &oldGeometry, const QRect &newGeometry) +{ + m_animation->setDuration(400); + m_animation->setStartValue(oldGeometry); + m_animation->setEndValue(newGeometry); +} + +QPoint TabPreview::calculatePosition(const QRect &tabRect, const QSize &previewSize) +{ + QPoint p; + p.setY(tabRect.y() + tabRect.height() + 2); + + // Map to center of tab + if (tabRect.width() > previewSize.width()) { + int extraWidth = tabRect.width() - previewSize.width(); + p.setX(tabRect.x() + extraWidth / 2); + } + else { + int extraWidth = previewSize.width() - tabRect.width(); + p.setX(tabRect.x() - extraWidth / 2); + } + + // Ensure the whole preview is always shown + if (p.x() < 0) { + p.setX(0); + } + if (p.x() + previewSize.width() > p_QupZilla->width()) { + int extraWidth = p.x() + previewSize.width() - p_QupZilla->width(); + p.setX(p.x() - extraWidth); + } + + return p; +} + +void TabPreview::showOnRect(const QRect &r) +{ + if (m_animation->state() == QPropertyAnimation::Running) { + m_animation->stop(); + } + + QRect oldGeometry = geometry(); + bool wasVisible = isVisible(); + + resize(QSize(250, 170)); + QFrame::show(); + + QRect finishingGeometry; + + if (m_pixmap->isVisible()) { + m_title->setWordWrap(false); + m_title->setText(m_title->fontMetrics().elidedText(m_title->text(), Qt::ElideRight, 240)); + + QSize previewSize(250, 170); + finishingGeometry = QRect(calculatePosition(r, previewSize), previewSize); + } + else { + m_title->setWordWrap(true); + + QSize previewSize = sizeHint(); + previewSize.setWidth(qMin(previewSize.width() + 2 * 5, 240)); + previewSize.setHeight(qMin(previewSize.height() + 2 * 5, 130)); + + finishingGeometry = QRect(calculatePosition(r, previewSize), previewSize); + } + + if (!m_animationsEnabled || !wasVisible) { + QFrame::setGeometry(finishingGeometry); + QFrame::show(); + } + else { + setFinishingGeometry(oldGeometry, finishingGeometry); + m_animation->start(); + } +} diff --git a/src/lib/webview/tabpreview.h b/src/lib/webview/tabpreview.h new file mode 100644 index 000000000..e77ce157a --- /dev/null +++ b/src/lib/webview/tabpreview.h @@ -0,0 +1,57 @@ +/* ============================================================ +* QupZilla - WebKit based browser +* Copyright (C) 2010-2012 Alexander Samilovskih +* David Rosca +* +* This program is free software: you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation, either version 3 of the License, or +* (at your option) any later version. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program. If not, see . +* ============================================================ */ +#ifndef TABPREVIEW_H +#define TABPREVIEW_H + +#include + +class QupZilla; +class WebTab; +class QLabel; +class QPropertyAnimation; +class QParallelAnimationGroup; + + +class TabPreview : public QFrame +{ + Q_OBJECT +public: + explicit TabPreview(QupZilla* mainClass, QWidget* parent); + + void setWebTab(WebTab* webTab, bool noPixmap); + void showOnRect(const QRect &rect); + + void setAnimationsEnabled(bool enabled); + +protected: + void paintEvent(QPaintEvent* pe); + +private: + void setFinishingGeometry(const QRect &oldGeometry, const QRect &newGeometry); + QPoint calculatePosition(const QRect &tabRect, const QSize &previewSize); + + QupZilla* p_QupZilla; + QLabel* m_pixmap; + QLabel* m_title; + + bool m_animationsEnabled; + QPropertyAnimation* m_animation; +}; + +#endif // TABPREVIEW_H diff --git a/src/lib/webview/webtab.cpp b/src/lib/webview/webtab.cpp index 51f2f8658..8a9ae1967 100644 --- a/src/lib/webview/webtab.cpp +++ b/src/lib/webview/webtab.cpp @@ -27,6 +27,7 @@ #include #include +#include #include WebTab::SavedTab::SavedTab(WebTab* webTab) @@ -226,7 +227,6 @@ void WebTab::restoreTab(const WebTab::SavedTab &tab) m_view->tabWidget()->setTabIcon(index, tab.icon); m_view->tabWidget()->setTabText(index, tab.title); - m_view->tabWidget()->setTabToolTip(index, tab.title); m_locationBar.data()->showUrl(tab.url); } else { @@ -247,6 +247,29 @@ void WebTab::p_restoreTab(const WebTab::SavedTab &tab) p_restoreTab(tab.url, tab.history); } +QPixmap WebTab::renderTabPreview() +{ + WebPage* page = m_view->page(); + const QSize &contentsSize = page->mainFrame()->contentsSize(); + QSize oldSize = page->viewportSize(); + + int renderWidth = qMin(contentsSize.width(), 2000); + int renderHeight = qMin(contentsSize.height(), 1500); + + page->setViewportSize(QSize(renderWidth, renderHeight)); + + QPixmap pageImage(renderWidth, renderHeight); + pageImage.fill(Qt::transparent); + + QPainter p(&pageImage); + m_view->page()->mainFrame()->render(&p, QWebFrame::ContentsLayer, m_view->visibleRegion()); + p.end(); + + page->setViewportSize(oldSize); + + pageImage = pageImage.scaled(230, 200, Qt::KeepAspectRatioByExpanding, Qt::SmoothTransformation); + return pageImage.copy(0, 0, 230, 150); +} void WebTab::showNotification(QWidget* notif) { diff --git a/src/lib/webview/webtab.h b/src/lib/webview/webtab.h index c00f15578..036beca2f 100644 --- a/src/lib/webview/webtab.h +++ b/src/lib/webview/webtab.h @@ -91,6 +91,8 @@ public: void p_restoreTab(const SavedTab &tab); void p_restoreTab(const QUrl &url, const QByteArray &history); + QPixmap renderTabPreview(); + void disconnectObjects(); private slots: