┌   ┐
54
└   ┘

summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/dolphinmainwindow.cpp8
-rw-r--r--src/dolphintabpage.cpp144
-rw-r--r--src/dolphintabpage.h41
-rw-r--r--src/global.cpp27
-rw-r--r--src/global.h23
5 files changed, 230 insertions, 13 deletions
diff --git a/src/dolphinmainwindow.cpp b/src/dolphinmainwindow.cpp
index 321670b58..3377918ce 100644
--- a/src/dolphinmainwindow.cpp
+++ b/src/dolphinmainwindow.cpp
@@ -807,7 +807,7 @@ void DolphinMainWindow::invertSelection()
void DolphinMainWindow::toggleSplitView()
{
DolphinTabPage* tabPage = m_tabWidget->currentTabPage();
- tabPage->setSplitViewEnabled(!tabPage->splitViewEnabled());
+ tabPage->setSplitViewEnabled(!tabPage->splitViewEnabled(), WithAnimation);
updateViewActions();
}
@@ -815,8 +815,8 @@ void DolphinMainWindow::toggleSplitView()
void DolphinMainWindow::toggleSplitStash()
{
DolphinTabPage* tabPage = m_tabWidget->currentTabPage();
- tabPage->setSplitViewEnabled(false);
- tabPage->setSplitViewEnabled(true, QUrl("stash:/"));
+ tabPage->setSplitViewEnabled(false, WithAnimation);
+ tabPage->setSplitViewEnabled(true, WithAnimation, QUrl("stash:/"));
}
void DolphinMainWindow::reloadView()
@@ -2143,7 +2143,7 @@ void DolphinMainWindow::refreshViews()
// The startup settings have been changed by the user (see bug #254947).
// Synchronize the split-view setting with the active view:
const bool splitView = GeneralSettings::splitView();
- m_tabWidget->currentTabPage()->setSplitViewEnabled(splitView);
+ m_tabWidget->currentTabPage()->setSplitViewEnabled(splitView, WithAnimation);
updateSplitAction();
updateWindowTitle();
}
diff --git a/src/dolphintabpage.cpp b/src/dolphintabpage.cpp
index 138822cfd..a90e8e7f0 100644
--- a/src/dolphintabpage.cpp
+++ b/src/dolphintabpage.cpp
@@ -1,5 +1,6 @@
/*
* SPDX-FileCopyrightText: 2014 Emmanuel Pescosta <[email protected]>
+ * SPDX-FileCopyrightText: 2020 Felix Ernst <[email protected]>
*
* SPDX-License-Identifier: GPL-2.0-or-later
*/
@@ -8,13 +9,17 @@
#include "dolphin_generalsettings.h"
#include "dolphinviewcontainer.h"
+#include "global.h"
+#include <QVariantAnimation>
#include <QSplitter>
#include <QGridLayout>
#include <QWidgetAction>
+#include <QStyle>
DolphinTabPage::DolphinTabPage(const QUrl &primaryUrl, const QUrl &secondaryUrl, QWidget* parent) :
QWidget(parent),
+ m_expandingContainer{nullptr},
m_primaryViewActive(true),
m_splitViewEnabled(false),
m_active(true)
@@ -65,12 +70,24 @@ bool DolphinTabPage::splitViewEnabled() const
return m_splitViewEnabled;
}
-void DolphinTabPage::setSplitViewEnabled(bool enabled, const QUrl &secondaryUrl)
+void DolphinTabPage::setSplitViewEnabled(bool enabled, Animated animated, const QUrl &secondaryUrl)
{
if (m_splitViewEnabled != enabled) {
m_splitViewEnabled = enabled;
+ if (animated == WithAnimation && (
+ style()->styleHint(QStyle::SH_Widget_Animation_Duration, nullptr, this) < 1 ||
+ GlobalConfig::animationDurationFactor() <= 0.0)) {
+ animated = WithoutAnimation;
+ }
+ if (m_expandViewAnimation) {
+ m_expandViewAnimation->stop(); // deletes because of QAbstractAnimation::DeleteWhenStopped.
+ if (animated == WithoutAnimation) {
+ slotAnimationFinished();
+ }
+ }
if (enabled) {
+ QList<int> splitterSizes = m_splitter->sizes();
const QUrl& url = (secondaryUrl.isEmpty()) ? m_primaryViewContainer->url() : secondaryUrl;
m_secondaryViewContainer = createViewContainer(url);
@@ -84,8 +101,15 @@ void DolphinTabPage::setSplitViewEnabled(bool enabled, const QUrl &secondaryUrl)
m_splitter->addWidget(m_secondaryViewContainer);
m_secondaryViewContainer->installEventFilter(this);
- m_secondaryViewContainer->show();
m_secondaryViewContainer->setActive(true);
+
+ if (animated == WithAnimation) {
+ m_secondaryViewContainer->setMinimumWidth(1);
+ splitterSizes.append(1);
+ m_splitter->setSizes(splitterSizes);
+ startExpandViewAnimation(m_secondaryViewContainer);
+ }
+ m_secondaryViewContainer->show();
} else {
m_navigatorsWidget->setSecondaryNavigatorVisible(false);
m_secondaryViewContainer->disconnectUrlNavigator();
@@ -117,8 +141,18 @@ void DolphinTabPage::setSplitViewEnabled(bool enabled, const QUrl &secondaryUrl)
}
}
m_primaryViewContainer->setActive(true);
- view->close();
- view->deleteLater();
+
+ if (animated == WithoutAnimation) {
+ view->close();
+ view->deleteLater();
+ } else {
+ // Kill it but keep it as a zombie for the closing animation.
+ m_secondaryViewContainer = nullptr;
+ view->blockSignals(true);
+ view->view()->blockSignals(true);
+ view->setDisabled(true);
+ startExpandViewAnimation(m_primaryViewContainer);
+ }
}
}
}
@@ -204,7 +238,7 @@ void DolphinTabPage::insertNavigatorsWidget(DolphinNavigatorsWidgetAction* navig
void DolphinTabPage::resizeNavigators() const
{
- if (!m_splitViewEnabled) {
+ if (!m_secondaryViewContainer) {
m_navigatorsWidget->followViewContainerGeometry(
m_primaryViewContainer->mapToGlobal(QPoint(0,0)).x(),
m_primaryViewContainer->width());
@@ -285,7 +319,7 @@ void DolphinTabPage::restoreState(const QByteArray& state)
bool isSplitViewEnabled = false;
stream >> isSplitViewEnabled;
- setSplitViewEnabled(isSplitViewEnabled);
+ setSplitViewEnabled(isSplitViewEnabled, WithoutAnimation);
QUrl primaryUrl;
stream >> primaryUrl;
@@ -329,7 +363,7 @@ void DolphinTabPage::restoreStateV1(const QByteArray& state)
bool isSplitViewEnabled = false;
stream >> isSplitViewEnabled;
- setSplitViewEnabled(isSplitViewEnabled);
+ setSplitViewEnabled(isSplitViewEnabled, WithoutAnimation);
QUrl primaryUrl;
stream >> primaryUrl;
@@ -372,6 +406,72 @@ void DolphinTabPage::setActive(bool active)
activeViewContainer()->setActive(active);
}
+void DolphinTabPage::slotAnimationFinished()
+{
+ for (int i = 0; i < m_splitter->count(); ++i) {
+ QWidget *viewContainer = m_splitter->widget(i);
+ if (viewContainer != m_primaryViewContainer &&
+ viewContainer != m_secondaryViewContainer) {
+ viewContainer->close();
+ viewContainer->deleteLater();
+ }
+ }
+ for (int i = 0; i < m_splitter->count(); ++i) {
+ QWidget *viewContainer = m_splitter->widget(i);
+ viewContainer->setMinimumWidth(viewContainer->minimumSizeHint().width());
+ }
+ m_expandingContainer = nullptr;
+}
+
+void DolphinTabPage::slotAnimationValueChanged(const QVariant& value)
+{
+ Q_CHECK_PTR(m_expandingContainer);
+ const int indexOfExpandingContainer = m_splitter->indexOf(m_expandingContainer);
+ int indexOfNonExpandingContainer = -1;
+ if (m_expandingContainer == m_primaryViewContainer) {
+ indexOfNonExpandingContainer = m_splitter->indexOf(m_secondaryViewContainer);
+ } else {
+ indexOfNonExpandingContainer = m_splitter->indexOf(m_primaryViewContainer);
+ }
+ std::vector<QWidget *> widgetsToRemove;
+ const QList<int> oldSplitterSizes = m_splitter->sizes();
+ QList<int> newSplitterSizes{oldSplitterSizes};
+ int expansionWidthNeeded = value.toInt() - oldSplitterSizes.at(indexOfExpandingContainer);
+
+ // Reduce the size of the other widgets to make space for the expandingContainer.
+ for (int i = m_splitter->count() - 1; i >= 0; --i) {
+ if (m_splitter->widget(i) == m_primaryViewContainer ||
+ m_splitter->widget(i) == m_secondaryViewContainer) {
+ continue;
+ }
+ newSplitterSizes[i] = oldSplitterSizes.at(i) - expansionWidthNeeded;
+ expansionWidthNeeded = 0;
+ if (indexOfNonExpandingContainer != -1) {
+ // Make sure every zombie container is at least slightly reduced in size
+ // so it doesn't seem like they are here to stay.
+ newSplitterSizes[i]--;
+ newSplitterSizes[indexOfNonExpandingContainer]++;
+ }
+ if (newSplitterSizes.at(i) <= 0) {
+ expansionWidthNeeded -= newSplitterSizes.at(i);
+ newSplitterSizes[i] = 0;
+ widgetsToRemove.emplace_back(m_splitter->widget(i));
+ }
+ }
+ if (expansionWidthNeeded > 1 && indexOfNonExpandingContainer != -1) {
+ Q_ASSERT(m_splitViewEnabled);
+ newSplitterSizes[indexOfNonExpandingContainer] -= expansionWidthNeeded;
+ }
+ newSplitterSizes[indexOfExpandingContainer] = value.toInt();
+ m_splitter->setSizes(newSplitterSizes);
+ while (!widgetsToRemove.empty()) {
+ widgetsToRemove.back()->close();
+ widgetsToRemove.back()->deleteLater();
+ widgetsToRemove.pop_back();
+ }
+}
+
+
void DolphinTabPage::slotViewActivated()
{
const DolphinView* oldActiveView = activeViewContainer()->view();
@@ -441,3 +541,33 @@ DolphinViewContainer* DolphinTabPage::createViewContainer(const QUrl& url) const
return container;
}
+
+void DolphinTabPage::startExpandViewAnimation(DolphinViewContainer *expandingContainer)
+{
+ Q_CHECK_PTR(expandingContainer);
+ Q_ASSERT(expandingContainer == m_primaryViewContainer ||
+ expandingContainer == m_secondaryViewContainer);
+ m_expandingContainer = expandingContainer;
+
+ m_expandViewAnimation = new QVariantAnimation(m_splitter);
+ m_expandViewAnimation->setDuration(2 *
+ style()->styleHint(QStyle::SH_Widget_Animation_Duration, nullptr, this) *
+ GlobalConfig::animationDurationFactor());
+ for (int i = 0; i < m_splitter->count(); ++i) {
+ m_splitter->widget(i)->setMinimumWidth(1);
+ }
+ connect(m_expandViewAnimation, &QAbstractAnimation::finished,
+ this, &DolphinTabPage::slotAnimationFinished);
+ connect(m_expandViewAnimation, &QVariantAnimation::valueChanged,
+ this, &DolphinTabPage::slotAnimationValueChanged);
+
+ m_expandViewAnimation->setStartValue(expandingContainer->width());
+ if (m_splitViewEnabled) { // A new viewContainer is being opened.
+ m_expandViewAnimation->setEndValue(m_splitter->width() / 2);
+ m_expandViewAnimation->setEasingCurve(QEasingCurve::OutCubic);
+ } else { // A viewContainer is being closed.
+ m_expandViewAnimation->setEndValue(m_splitter->width());
+ m_expandViewAnimation->setEasingCurve(QEasingCurve::InCubic);
+ }
+ m_expandViewAnimation->start(QAbstractAnimation::DeleteWhenStopped);
+}
diff --git a/src/dolphintabpage.h b/src/dolphintabpage.h
index 63a246328..e90bf99bf 100644
--- a/src/dolphintabpage.h
+++ b/src/dolphintabpage.h
@@ -1,5 +1,6 @@
/*
* SPDX-FileCopyrightText: 2014 Emmanuel Pescosta <[email protected]>
+ * SPDX-FileCopyrightText: 2020 Felix Ernst <[email protected]>
*
* SPDX-License-Identifier: GPL-2.0-or-later
*/
@@ -14,8 +15,14 @@
class DolphinNavigatorsWidgetAction;
class DolphinViewContainer;
class QSplitter;
+class QVariantAnimation;
class KFileItemList;
+enum Animated {
+ WithAnimation,
+ WithoutAnimation
+};
+
class DolphinTabPage : public QWidget
{
Q_OBJECT
@@ -36,9 +43,15 @@ public:
/**
* Enables or disables the split view mode.
*
- * If \a enabled is true, it creates a secondary view with the url of the primary view.
+ * @param enabled If true, creates a secondary viewContainer in this tab.
+ * Otherwise deletes it.
+ * @param animated Decides wether the effects of this method call should
+ * happen instantly or be transitioned to smoothly.
+ * @param secondaryUrl If \p enabled is true, the new viewContainer will be opened at this
+ * parameter. The default value will set the Url of the new viewContainer
+ * to be the same as the existing one.
*/
- void setSplitViewEnabled(bool enabled, const QUrl &secondaryUrl = QUrl());
+ void setSplitViewEnabled(bool enabled, Animated animated, const QUrl &secondaryUrl = QUrl());
/**
* @return The primary view container.
@@ -148,6 +161,17 @@ signals:
private slots:
/**
+ * Deletes all zombie viewContainers that were used for the animation
+ * and resets the minimum size of the others to a sane value.
+ */
+ void slotAnimationFinished();
+
+ /**
+ * This method is called for every frame of the m_expandViewAnimation.
+ */
+ void slotAnimationValueChanged(const QVariant &value);
+
+ /**
* Handles the view activated event.
*
* It sets the previous active view to inactive, updates the current
@@ -170,6 +194,16 @@ private:
*/
DolphinViewContainer* createViewContainer(const QUrl& url) const;
+ /**
+ * Starts an animation that transitions between split view mode states.
+ *
+ * One of the viewContainers is always being expanded when toggling so
+ * this method can animate both opening and closing of viewContainers.
+ * @param expandingContainer The container that will increase in size
+ * over the course of the animation.
+ */
+ void startExpandViewAnimation(DolphinViewContainer *expandingContainer);
+
private:
QSplitter* m_splitter;
@@ -177,6 +211,9 @@ private:
QPointer<DolphinViewContainer> m_primaryViewContainer;
QPointer<DolphinViewContainer> m_secondaryViewContainer;
+ DolphinViewContainer *m_expandingContainer;
+ QPointer<QVariantAnimation> m_expandViewAnimation;
+
bool m_primaryViewActive;
bool m_splitViewEnabled;
bool m_active;
diff --git a/src/global.cpp b/src/global.cpp
index 1018c7d4c..3d17a733b 100644
--- a/src/global.cpp
+++ b/src/global.cpp
@@ -10,6 +10,7 @@
#include "dolphindebug.h"
#include "dolphinmainwindowinterface.h"
+#include <KConfigWatcher>
#include <KDialogJobUiDelegate>
#include <KIO/ApplicationLauncherJob>
#include <KService>
@@ -138,3 +139,29 @@ QVector<QPair<QSharedPointer<OrgKdeDolphinMainWindowInterface>, QStringList>> Do
return dolphinInterfaces;
}
+
+double GlobalConfig::animationDurationFactor()
+{
+ if (s_animationDurationFactor >= 0.0) {
+ return s_animationDurationFactor;
+ }
+ // This is the first time this method is called.
+ auto kdeGlobalsConfig = KConfigGroup(KSharedConfig::openConfig(), QStringLiteral("KDE"));
+ updateAnimationDurationFactor(kdeGlobalsConfig, {"AnimationDurationFactor"});
+
+ KConfigWatcher::Ptr configWatcher = KConfigWatcher::create(KSharedConfig::openConfig());
+ connect(configWatcher.data(), &KConfigWatcher::configChanged,
+ &GlobalConfig::updateAnimationDurationFactor);
+ return s_animationDurationFactor;
+}
+
+void GlobalConfig::updateAnimationDurationFactor(const KConfigGroup &group, const QByteArrayList &names)
+{
+ if (group.name() == QLatin1String("KDE") &&
+ names.contains(QByteArrayLiteral("AnimationDurationFactor"))) {
+ s_animationDurationFactor = std::max(0.0,
+ group.readEntry("AnimationDurationFactor", 1.0));
+ }
+}
+
+double GlobalConfig::s_animationDurationFactor = -1.0;
diff --git a/src/global.h b/src/global.h
index 65247351a..088e9c5b6 100644
--- a/src/global.h
+++ b/src/global.h
@@ -11,6 +11,7 @@
#include <QUrl>
#include <QWidget>
+class KConfigGroup;
class OrgKdeDolphinMainWindowInterface;
namespace Dolphin {
@@ -52,4 +53,26 @@ namespace Dolphin {
const int LAYOUT_SPACING_SMALL = 2;
}
+class GlobalConfig : public QObject
+{
+ Q_OBJECT
+
+public:
+ GlobalConfig() = delete;
+
+ /**
+ * @return a value from the global KDE config that should be
+ * multiplied with every animation duration once.
+ * 0.0 is returned if animations are globally turned off.
+ * 1.0 is the default value.
+ */
+ static double animationDurationFactor();
+
+private:
+ static void updateAnimationDurationFactor(const KConfigGroup &group, const QByteArrayList &names);
+
+private:
+ static double s_animationDurationFactor;
+};
+
#endif //GLOBAL_H