Commit 736ef044 authored by Marco Martin's avatar Marco Martin
Browse files

Wrap around during navigation with arrow keys

This resurrects https://phabricator.kde.org/D9039 originally by Nate Grahm. By default when on last image pressing the right arrow will wrap to the first image, and left arrow on first image will wrap to the last. to determine the proper next and last images, it skips things that are not images
parent ac47787f
......@@ -53,6 +53,12 @@ ConfigDialog::ConfigDialog(QWidget* parent)
// General
widget = setupPage(mGeneralConfigPage);
mWrapNavigationBehaviorGroup = new InvisibleButtonGroup(widget);
mWrapNavigationBehaviorGroup->setObjectName(QStringLiteral("kcfg_NavigationEndNotification"));
mWrapNavigationBehaviorGroup->addButton(mGeneralConfigPage.neverShowWrapNoticeRadioButton, int(SlideShow::NavigationEndNotification::NeverWarn));
mWrapNavigationBehaviorGroup->addButton(mGeneralConfigPage.wrapNoticeOnSlideshowRadioButton, int(SlideShow::NavigationEndNotification::WarnOnSlideshow));
mWrapNavigationBehaviorGroup->addButton(mGeneralConfigPage.alwaysShowWrapNoticeRadioButton, int(SlideShow::NavigationEndNotification::AlwaysWarn));
mFullScreenBackgroundGroup = new InvisibleButtonGroup(widget);
mFullScreenBackgroundGroup->setObjectName(QStringLiteral("kcfg_FullScreenBackground"));
mFullScreenBackgroundGroup->addButton(mGeneralConfigPage.fullscreenBackgroundBlackRadioButton, int(FullScreenBackground::Black));
......
......@@ -45,6 +45,7 @@ private Q_SLOTS:
void updateViewBackgroundFrame();
private:
InvisibleButtonGroup* mWrapNavigationBehaviorGroup = nullptr;
InvisibleButtonGroup* mAlphaBackgroundModeGroup = nullptr;
InvisibleButtonGroup* mWheelBehaviorGroup = nullptr;
InvisibleButtonGroup* mAnimationMethodGroup = nullptr;
......
......@@ -6,8 +6,8 @@
<rect>
<x>0</x>
<y>0</y>
<width>474</width>
<height>338</height>
<width>515</width>
<height>493</height>
</rect>
</property>
<layout class="QFormLayout" name="formLayout">
......@@ -16,6 +16,9 @@
<property name="text">
<string>Videos:</string>
</property>
<property name="buddy">
<cstring>kcfg_ListVideos</cstring>
</property>
</widget>
</item>
<item row="0" column="1">
......@@ -32,7 +35,38 @@
</property>
</widget>
</item>
<item row="2" column="0">
<widget class="QLabel" name="label_7">
<property name="text">
<string>Notify after reaching the last image:</string>
</property>
<property name="buddy">
<cstring>neverShowWrapNoticeRadioButton</cstring>
</property>
</widget>
</item>
<item row="2" column="1">
<widget class="QRadioButton" name="neverShowWrapNoticeRadioButton">
<property name="text">
<string>Never</string>
</property>
</widget>
</item>
<item row="3" column="1">
<widget class="QRadioButton" name="wrapNoticeOnSlideshowRadioButton">
<property name="text">
<string>Only during slideshows</string>
</property>
</widget>
</item>
<item row="4" column="1">
<widget class="QRadioButton" name="alwaysShowWrapNoticeRadioButton">
<property name="text">
<string>Always</string>
</property>
</widget>
</item>
<item row="5" column="1">
<spacer name="verticalSpacer_1">
<property name="orientation">
<enum>Qt::Vertical</enum>
......@@ -48,14 +82,17 @@
</property>
</spacer>
</item>
<item row="3" column="0">
<item row="6" column="0">
<widget class="QLabel" name="label_2">
<property name="text">
<string>Background color:</string>
</property>
<property name="buddy">
<cstring>kcfg_ViewBackgroundValue</cstring>
</property>
</widget>
</item>
<item row="3" column="1">
<item row="6" column="1">
<layout class="QHBoxLayout">
<item>
<widget class="QSlider" name="kcfg_ViewBackgroundValue">
......@@ -113,7 +150,7 @@
</item>
</layout>
</item>
<item row="4" column="1">
<item row="7" column="1">
<spacer name="verticalSpacer_2">
<property name="orientation">
<enum>Qt::Vertical</enum>
......@@ -129,28 +166,31 @@
</property>
</spacer>
</item>
<item row="5" column="0">
<item row="8" column="0">
<widget class="QLabel" name="label_3">
<property name="text">
<string>Fullscreen background:</string>
</property>
<property name="buddy">
<cstring>fullscreenBackgroundImageRadioButton</cstring>
</property>
</widget>
</item>
<item row="5" column="1">
<item row="8" column="1">
<widget class="QRadioButton" name="fullscreenBackgroundImageRadioButton">
<property name="text">
<string>Dark gray texture</string>
</property>
</widget>
</item>
<item row="6" column="1">
<item row="9" column="1">
<widget class="QRadioButton" name="fullscreenBackgroundBlackRadioButton">
<property name="text">
<string>Black</string>
</property>
</widget>
</item>
<item row="7" column="1">
<item row="10" column="1">
<spacer name="verticalSpacer_3">
<property name="orientation">
<enum>Qt::Vertical</enum>
......@@ -166,14 +206,17 @@
</property>
</spacer>
</item>
<item row="8" column="0">
<item row="11" column="0">
<widget class="QLabel" name="label_4">
<property name="text">
<string>Lossy image save quality:</string>
</property>
<property name="buddy">
<cstring>kcfg_JPEGQuality</cstring>
</property>
</widget>
</item>
<item row="8" column="1">
<item row="11" column="1">
<layout class="QHBoxLayout" name="horizontalLayout">
<item>
<widget class="QSlider" name="kcfg_JPEGQuality">
......@@ -231,7 +274,7 @@
</item>
</layout>
</item>
<item row="9" column="1">
<item row="12" column="1">
<widget class="QLabel" name="lossyImageFormatHelpLabel">
<property name="text">
<string>The quality level when saving images using lossy image formats such as JPEG, WEBP, AVIF, HEIF, and HEIC. Higher quality increases the file size.</string>
......@@ -241,7 +284,7 @@
</property>
</widget>
</item>
<item row="10" column="1">
<item row="13" column="1">
<spacer name="verticalSpacer_3">
<property name="orientation">
<enum>Qt::Vertical</enum>
......@@ -257,28 +300,28 @@
</property>
</spacer>
</item>
<item row="11" column="0">
<item row="14" column="0">
<widget class="QLabel" name="label_5">
<property name="text">
<string>Thumbnail actions:</string>
</property>
</widget>
</item>
<item row="12" column="1">
<item row="15" column="1">
<widget class="QRadioButton" name="allButtonsThumbnailActionsRadioButton">
<property name="text">
<string>All buttons</string>
</property>
</widget>
</item>
<item row="13" column="1">
<item row="16" column="1">
<widget class="QRadioButton" name="selectionOnlyThumbnailActionsRadioButton">
<property name="text">
<string>Show selection button only</string>
</property>
</widget>
</item>
<item row="14" column="1">
<item row="17" column="1">
<widget class="QRadioButton" name="noneThumbnailActionsRadioButton">
<property name="text">
<string>None</string>
......@@ -287,6 +330,21 @@
</item>
</layout>
</widget>
<tabstops>
<tabstop>kcfg_ListVideos</tabstop>
<tabstop>kcfg_AutoplayVideos</tabstop>
<tabstop>neverShowWrapNoticeRadioButton</tabstop>
<tabstop>wrapNoticeOnSlideshowRadioButton</tabstop>
<tabstop>alwaysShowWrapNoticeRadioButton</tabstop>
<tabstop>kcfg_ViewBackgroundValue</tabstop>
<tabstop>fullscreenBackgroundImageRadioButton</tabstop>
<tabstop>fullscreenBackgroundBlackRadioButton</tabstop>
<tabstop>kcfg_JPEGQuality</tabstop>
<tabstop>jpegQualitySpinner</tabstop>
<tabstop>allButtonsThumbnailActionsRadioButton</tabstop>
<tabstop>selectionOnlyThumbnailActionsRadioButton</tabstop>
<tabstop>noneThumbnailActionsRadioButton</tabstop>
</tabstops>
<resources/>
<connections/>
</ui>
......@@ -45,6 +45,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
// KF
#include <KActionCategory>
#include <KActionCollection>
#include <KDirModel>
#include <KFileItem>
#include <KHamburgerMenu>
#include <KLocalizedString>
......@@ -209,6 +210,7 @@ struct MainWindow::Private
QAction * mToggleSlideShowAction;
KToggleAction* mShowMenuBarAction;
KToggleAction* mShowStatusBarAction;
QPointer<HudButtonBox> hudButtonBox;
#ifdef KF5Purpose_FOUND
Purpose::Menu* mShareMenu;
KToolBarPopupAction* mShareAction;
......@@ -1414,12 +1416,58 @@ void MainWindow::slotDirListerCompleted()
void MainWindow::goToPrevious()
{
d->goTo(-1);
const QModelIndex currentIndex = d->mContextManager->selectionModel()->currentIndex();
QModelIndex previousIndex = d->mDirModel->index(currentIndex.row(), 0);
KFileItem fileItem;
// Besides images also folders and archives are listed as well,
// we need to skip them in the slideshow
do {
previousIndex = d->mDirModel->index(previousIndex.row() - 1, 0);
fileItem = previousIndex.data(KDirModel::FileItemRole).value<KFileItem>();
} while (previousIndex.isValid()
&& !MimeTypeUtils::imageMimeTypes().contains(fileItem.currentMimeType().name()));
if (!previousIndex.isValid()
&& (GwenviewConfig::navigationEndNotification() == SlideShow::NeverWarn
|| (GwenviewConfig::navigationEndNotification() == SlideShow::WarnOnSlideshow
&& !d->mSlideShow->isRunning() && !d->mFullScreenAction->isChecked())
|| d->hudButtonBox)) {
d->goToLastDocument();
} else if (!previousIndex.isValid()) {
showFirstDocumentReached();
} else {
d->goTo(-1);
}
}
void MainWindow::goToNext()
{
d->goTo(1);
const QModelIndex currentIndex = d->mContextManager->selectionModel()->currentIndex();
QModelIndex nextIndex = d->mDirModel->index(currentIndex.row(), 0);
KFileItem fileItem;
// Besides images also folders and archives are listed as well,
// we need to skip them in the slideshow
do {
nextIndex = d->mDirModel->index(nextIndex.row() + 1, 0);
fileItem = nextIndex.data(KDirModel::FileItemRole).value<KFileItem>();
} while (nextIndex.isValid()
&& !MimeTypeUtils::imageMimeTypes().contains(fileItem.currentMimeType().name()));
if (!nextIndex.isValid()
&& (GwenviewConfig::navigationEndNotification() == SlideShow::NeverWarn
|| (GwenviewConfig::navigationEndNotification() == SlideShow::WarnOnSlideshow
&& !d->mSlideShow->isRunning() && !d->mFullScreenAction->isChecked())
|| d->hudButtonBox)) {
d->goToFirstDocument();
} else if (!nextIndex.isValid()) {
showLastDocumentReached();
} else {
d->goTo(1);
}
}
void MainWindow::goToFirst()
......@@ -1455,11 +1503,11 @@ void MainWindow::updatePreviousNextActions()
int row = currentIndex.row();
QModelIndex prevIndex = d->mDirModel->index(row - 1, 0);
QModelIndex nextIndex = d->mDirModel->index(row + 1, 0);
hasPrevious = prevIndex.isValid() && !d->indexIsDirOrArchive(prevIndex);
hasNext = nextIndex.isValid() && !d->indexIsDirOrArchive(nextIndex);
hasPrevious = GwenviewConfig::navigationEndNotification() != SlideShow::AlwaysWarn || (prevIndex.isValid() && !d->indexIsDirOrArchive(prevIndex));
hasNext = GwenviewConfig::navigationEndNotification() != SlideShow::AlwaysWarn || (nextIndex.isValid() && !d->indexIsDirOrArchive(nextIndex));
} else {
hasPrevious = false;
hasNext = false;
hasNext = false;
}
d->mGoToPreviousAction->setEnabled(hasPrevious);
......@@ -1891,30 +1939,30 @@ void MainWindow::readProperties(const KConfigGroup& group)
void MainWindow::showFirstDocumentReached()
{
if (d->mCurrentMainPageId != ViewMainPageId) {
if (d->hudButtonBox || d->mCurrentMainPageId != ViewMainPageId) {
return;
}
HudButtonBox* dlg = new HudButtonBox;
dlg->setText(i18n("You reached the first document, what do you want to do?"));
dlg->addButton(i18n("Stay There"));
dlg->addAction(d->mGoToLastAction, i18n("Go to the Last Document"));
dlg->addAction(d->mBrowseAction, i18n("Go Back to the Document List"));
dlg->addCountDown(15000);
d->mViewMainPage->showMessageWidget(dlg, Qt::AlignCenter);
d->hudButtonBox = new HudButtonBox;
d->hudButtonBox->setText(i18n("You reached the first document, what do you want to do?"));
d->hudButtonBox->addButton(i18n("Stay There"));
d->hudButtonBox->addAction(d->mGoToLastAction, i18n("Go to the Last Document"));
d->hudButtonBox->addAction(d->mBrowseAction, i18n("Go Back to the Document List"));
d->hudButtonBox->addCountDown(15000);
d->mViewMainPage->showMessageWidget(d->hudButtonBox, Qt::AlignCenter);
}
void MainWindow::showLastDocumentReached()
{
if (d->mCurrentMainPageId != ViewMainPageId) {
if (d->hudButtonBox || d->mCurrentMainPageId != ViewMainPageId) {
return;
}
HudButtonBox* dlg = new HudButtonBox;
dlg->setText(i18n("You reached the last document, what do you want to do?"));
dlg->addButton(i18n("Stay There"));
dlg->addAction(d->mGoToFirstAction, i18n("Go to the First Document"));
dlg->addAction(d->mBrowseAction, i18n("Go Back to the Document List"));
dlg->addCountDown(15000);
d->mViewMainPage->showMessageWidget(dlg, Qt::AlignCenter);
d->hudButtonBox = new HudButtonBox;
d->hudButtonBox->setText(i18n("You reached the last document, what do you want to do?"));
d->hudButtonBox->addButton(i18n("Stay There"));
d->hudButtonBox->addAction(d->mGoToFirstAction, i18n("Go to the First Document"));
d->hudButtonBox->addAction(d->mBrowseAction, i18n("Go Back to the Document List"));
d->hudButtonBox->addCountDown(15000);
d->mViewMainPage->showMessageWidget(d->hudButtonBox, Qt::AlignCenter);
}
void MainWindow::replaceLocation()
......
......@@ -21,6 +21,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
#include "config-gwenview.h"
// Qt
#include <QApplication>
#include <QCheckBox>
#include <QItemSelectionModel>
#include <QShortcut>
......@@ -204,6 +205,7 @@ struct ViewMainPagePrivate
// Show the thumbnail bar after setting the parent to avoid recreating
// the native window and to avoid QTBUG-87345.
mThumbnailBar->setVisible(GwenviewConfig::thumbnailBarIsVisible());
mThumbnailBar->installEventFilter(q);
QVBoxLayout* viewMainPageLayout = new QVBoxLayout(q);
viewMainPageLayout->setContentsMargins(0, 0, 0, 0);
......@@ -788,7 +790,33 @@ void ViewMainPage::slotEnterPressed()
bool ViewMainPage::eventFilter(QObject* watched, QEvent* event)
{
if (event->type() == QEvent::ShortcutOverride) {
if (watched == d->mThumbnailBar && event->type() == QEvent::KeyPress) {
QKeyEvent *ke = static_cast<QKeyEvent*>(event);
switch (ke->key()) {
case Qt::Key_Left:
if (QApplication::isRightToLeft()) {
emit nextImageRequested();
} else {
emit previousImageRequested();
}
return true;
case Qt::Key_Up:
emit previousImageRequested();
return true;
case Qt::Key_Right:
if (QApplication::isRightToLeft()) {
emit previousImageRequested();
} else {
emit nextImageRequested();
}
return true;
case Qt::Key_Down:
emit nextImageRequested();
return true;
default:
break;
}
} else if (event->type() == QEvent::ShortcutOverride) {
const int key = static_cast<QKeyEvent*>(event)->key();
if (key == Qt::Key_Space || key == Qt::Key_Escape) {
const DocumentView* view = d->currentView();
......
......@@ -444,10 +444,22 @@ void AbstractImageView::keyPressEvent(QKeyEvent* event)
switch (event->key()) {
case Qt::Key_Left:
if (QApplication::isRightToLeft()) {
emit nextImageRequested();
} else {
emit previousImageRequested();
}
break;
case Qt::Key_Up:
emit previousImageRequested();
break;
case Qt::Key_Right:
if (QApplication::isRightToLeft()) {
emit previousImageRequested();
} else {
emit nextImageRequested();
}
break;
case Qt::Key_Down:
emit nextImageRequested();
break;
......
......@@ -6,6 +6,7 @@
http://www.kde.org/standards/kcfg/1.0/kcfg.xsd">
<include>lib/sorting.h</include>
<include>lib/zoommode.h</include>
<include>lib/slideshow.h</include>
<include>lib/thumbnailactions.h</include>
<include>lib/mousewheelbehavior.h</include>
<include>lib/fullscreenbackground.h</include>
......@@ -214,6 +215,15 @@
<entry name="NoMonitorICC" type="Bool">
<default>true</default>
</entry>
<entry name="NavigationEndNotification" type="Enum">
<choices name="Gwenview::SlideShow::NavigationEndNotification">
<choice name="NavigationEndNotification::NeverWarn"/>
<choice name="NavigationEndNotification::WarnOnSlideshow"/>
<choice name="NavigationEndNotification::AlwaysWarn"/>
</choices>
<default>Gwenview::SlideShow::NavigationEndNotification::WarnOnSlideshow</default>
</entry>
</group>
<group name="ThumbnailView">
......
......@@ -39,6 +39,13 @@ class GWENVIEWLIB_EXPORT SlideShow : public QObject
{
Q_OBJECT
public:
enum NavigationEndNotification {
NeverWarn,
WarnOnSlideshow,
AlwaysWarn
};
Q_ENUM(NavigationEndNotification)
explicit SlideShow(QObject* parent);
~SlideShow() override;
......
......@@ -807,13 +807,28 @@ void ThumbnailView::dropEvent(QDropEvent* event)
void ThumbnailView::keyPressEvent(QKeyEvent* event)
{
QListView::keyPressEvent(event);
if (event->key() == Qt::Key_Return) {
const QModelIndex index = selectionModel()->currentIndex();
if (index.isValid() && selectionModel()->selectedIndexes().count() == 1) {
emit indexActivated(index);
}
} else if (event->key() == Qt::Key_Left && event->modifiers() == Qt::NoModifier) {
if (flow() == LeftToRight && QApplication::isRightToLeft()) {
setCurrentIndex(moveCursor(QAbstractItemView::MoveRight, Qt::NoModifier));
} else {
setCurrentIndex(moveCursor(QAbstractItemView::MoveLeft, Qt::NoModifier));
}
return;
} else if (event->key() == Qt::Key_Right && event->modifiers() == Qt::NoModifier) {
if (flow() == LeftToRight && QApplication::isRightToLeft()) {
setCurrentIndex(moveCursor(QAbstractItemView::MoveLeft, Qt::NoModifier));
} else {
setCurrentIndex(moveCursor(QAbstractItemView::MoveRight, Qt::NoModifier));
}
return;
}
QListView::keyPressEvent(event);
}
void ThumbnailView::resizeEvent(QResizeEvent* event)
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment