1
0

feat: update action manager

- add and delete some actions in action manager.
- rename "fit to view" to "fit to screen".
- update main window right click menu and toolbar.
- use special state update slot in action manager instead of function located in main window.
This commit is contained in:
2026-07-12 21:00:11 +08:00
parent 369a17ed7d
commit dbf8c09368
8 changed files with 388 additions and 324 deletions

View File

@@ -4,7 +4,11 @@
#include "actionmanager.h"
#include "settings.h"
#include "mainwindow.h"
#include "playlistmanager.h"
#include "graphicsview.h"
#include "graphicsscene.h"
#include <QGuiApplication>
#include <QSvgRenderer>
@@ -25,6 +29,8 @@ void ActionManager::setupAction(MainWindow *mainWindow)
{
// region: Action and Its Icon Creation
// Declare some convenient macros and lambdas.
#define ICON_NAME(name)\
QStringLiteral(":/icons/" #name ".svg")
@@ -39,40 +45,51 @@ void ActionManager::setupAction(MainWindow *mainWindow)
w->addAction(*a);
};
#define CREATE_NEW_ICON_ACTION(w, a, i) create_action(w, &a, ICON_NAME(i), ACTION_NAME(a))
CREATE_NEW_ICON_ACTION(mainWindow, actionActualSize, zoom-original);
CREATE_NEW_ICON_ACTION(mainWindow, actionToggleMaximize, view-fullscreen);
CREATE_NEW_ICON_ACTION(mainWindow, actionZoomIn, zoom-in);
CREATE_NEW_ICON_ACTION(mainWindow, actionZoomOut, zoom-out);
CREATE_NEW_ICON_ACTION(mainWindow, actionToggleCheckerboard, view-background-checkerboard);
CREATE_NEW_ICON_ACTION(mainWindow, actionRotateClockwise, object-rotate-right);
/// This macro for register normal action.
#define CREATE_NEW_ACTION(w, a) create_action(w, &a, QString(), ACTION_NAME(a))
/// This macro for register Qt theme action.
#define CREATE_NEW_THEMEICON_ACTION(w, a, i) create_action(w, &a, QLatin1String(STRIFY(i)), ACTION_NAME(a), true)
/// This macro for register action with our custom icon.
#define CREATE_NEW_ICON_ACTION(w, a, i) create_action(w, &a, ICON_NAME(i), ACTION_NAME(a), false)
// TODO: We may replace all Qt theme icons to our custom icon for visual consistency.
// TODO: Some icons are invalid.
CREATE_NEW_THEMEICON_ACTION(mainWindow, actionCopyPixmap, edit-copy);
CREATE_NEW_ACTION(mainWindow, actionCopyFilePath);
CREATE_NEW_ICON_ACTION(mainWindow, actionPrevPicture, go-previous);
CREATE_NEW_ICON_ACTION(mainWindow, actionNextPicture, go-next);
#undef CREATE_NEW_ICON_ACTION
#define CREATE_NEW_ACTION(w, a) create_action(w, &a, QString(), ACTION_NAME(a))
#define CREATE_NEW_THEMEICON_ACTION(w, a, i) create_action(w, &a, QLatin1String(STRIFY(i)), ACTION_NAME(a), true)
CREATE_NEW_ACTION(mainWindow, actionRotateCounterClockwise);
CREATE_NEW_ICON_ACTION(mainWindow, actionActualSize, zoom-original);
CREATE_NEW_ICON_ACTION(mainWindow, actionFitToScreen, app-icon);
CREATE_NEW_ICON_ACTION(mainWindow, actionFitByWidth, app-icon);
CREATE_NEW_ICON_ACTION(mainWindow, actionFitByHeight, app-icon);
CREATE_NEW_ICON_ACTION(mainWindow, actionZoomIn, zoom-in);
CREATE_NEW_ICON_ACTION(mainWindow, actionZoomOut, zoom-out);
CREATE_NEW_ICON_ACTION(mainWindow, actionFlipHorizontal, app-icon);
CREATE_NEW_ICON_ACTION(mainWindow, actionFlipVertical, app-icon);
CREATE_NEW_ICON_ACTION(mainWindow, actionRotateClockwise, object-rotate-right);
CREATE_NEW_ICON_ACTION(mainWindow, actionRotateCounterClockwise, app-icon);
CREATE_NEW_ACTION(mainWindow, actionToggleAvoidResetTransform);
CREATE_NEW_ICON_ACTION(mainWindow, actionToggleCheckerboard, view-background-checkerboard);
CREATE_NEW_ACTION(mainWindow, actionTogglePauseAnimation);
CREATE_NEW_ACTION(mainWindow, actionAnimationNextFrame);
CREATE_NEW_THEMEICON_ACTION(mainWindow, actionOpen, document-open);
CREATE_NEW_ACTION(mainWindow, actionHorizontalFlip);
CREATE_NEW_ACTION(mainWindow, actionFitInView);
CREATE_NEW_ACTION(mainWindow, actionFitByWidth);
CREATE_NEW_THEMEICON_ACTION(mainWindow, actionCopyPixmap, edit-copy);
CREATE_NEW_ACTION(mainWindow, actionCopyFilePath);
CREATE_NEW_THEMEICON_ACTION(mainWindow, actionPaste, edit-paste);
CREATE_NEW_THEMEICON_ACTION(mainWindow, actionTrash, edit-delete);
CREATE_NEW_ACTION(mainWindow, actionToggleAvoidResetTransform);
CREATE_NEW_ACTION(mainWindow, actionSettings);
CREATE_NEW_THEMEICON_ACTION(mainWindow, actionHelp, system-help);
CREATE_NEW_THEMEICON_ACTION(mainWindow, actionLocateInFileManager, system-file-manager);
CREATE_NEW_THEMEICON_ACTION(mainWindow, actionProperties, document-properties);
CREATE_NEW_ACTION(mainWindow, actionQuitApp);
#undef CREATE_NEW_ACTION
CREATE_NEW_ACTION(mainWindow, actionSettings);
CREATE_NEW_THEMEICON_ACTION(mainWindow, actionHelp, system-help);
// Remove convenient macros
#undef CREATE_NEW_ICON_ACTION
#undef CREATE_NEW_THEMEICON_ACTION
#undef CREATE_NEW_ACTION
#undef STRIFY
#undef ACTION_NAME
@@ -80,34 +97,40 @@ void ActionManager::setupAction(MainWindow *mainWindow)
// endregion
// region: Setup Checkable Action
actionToggleAvoidResetTransform->setCheckable(true);
actionToggleCheckerboard->setCheckable(true);
actionTogglePauseAnimation->setCheckable(true);
// endregion
// region: Action Translatable Text Setup
actionOpen->setText(QCoreApplication::translate("MainWindow", "&Open...", nullptr));
actionActualSize->setText(QCoreApplication::translate("MainWindow", "Actual size", nullptr));
actionToggleMaximize->setText(QCoreApplication::translate("MainWindow", "Toggle maximize", nullptr));
actionZoomIn->setText(QCoreApplication::translate("MainWindow", "Zoom in", nullptr));
actionZoomOut->setText(QCoreApplication::translate("MainWindow", "Zoom out", nullptr));
actionToggleCheckerboard->setText(QCoreApplication::translate("MainWindow", "Toggle Checkerboard", nullptr));
actionRotateClockwise->setText(QCoreApplication::translate("MainWindow", "Rotate right", nullptr));
actionRotateCounterClockwise->setText(QCoreApplication::translate("MainWindow", "Rotate left", nullptr));
actionCopyPixmap->setText(QCoreApplication::translate("MainWindow", "Copy P&ixmap", nullptr));
actionCopyFilePath->setText(QCoreApplication::translate("MainWindow", "Copy &File Path", nullptr));
actionPrevPicture->setText(QCoreApplication::translate("MainWindow", "Previous image", nullptr));
actionNextPicture->setText(QCoreApplication::translate("MainWindow", "Next image", nullptr));
actionActualSize->setText(QCoreApplication::translate("MainWindow", "Actual size", nullptr));
actionFitToScreen->setText(QCoreApplication::translate("MainWindow", "Fit to screen", nullptr));
actionFitByWidth->setText(QCoreApplication::translate("MainWindow", "Fit by width", nullptr));
actionFitByHeight->setText(QCoreApplication::translate("MainWindow", "Fit by height", nullptr));
actionZoomIn->setText(QCoreApplication::translate("MainWindow", "Zoom in", nullptr));
actionZoomOut->setText(QCoreApplication::translate("MainWindow", "Zoom out", nullptr));
actionFlipHorizontal->setText(QCoreApplication::translate("MainWindow", "Flip &Horizontally", nullptr));
actionFlipVertical->setText(QCoreApplication::translate("MainWindow", "Flip &Vertically", nullptr));
actionRotateClockwise->setText(QCoreApplication::translate("MainWindow", "Rotate right", nullptr));
actionRotateCounterClockwise->setText(QCoreApplication::translate("MainWindow", "Rotate left", nullptr));
actionToggleAvoidResetTransform->setText(QCoreApplication::translate("MainWindow", "Keep transformation", "The 'transformation' means the flip/rotation status that currently applied to the image view"));
actionToggleCheckerboard->setText(QCoreApplication::translate("MainWindow", "Toggle Checkerboard", nullptr));
actionTogglePauseAnimation->setText(QCoreApplication::translate("MainWindow", "Pause/Resume Animation", nullptr));
actionAnimationNextFrame->setText(QCoreApplication::translate("MainWindow", "Animation Go to Next Frame", nullptr));
actionHorizontalFlip->setText(QCoreApplication::translate("MainWindow", "Flip &Horizontally", nullptr));
actionFitInView->setText(QCoreApplication::translate("MainWindow", "Fit to view", nullptr));
actionFitByWidth->setText(QCoreApplication::translate("MainWindow", "Fit to width", nullptr));
actionCopyPixmap->setText(QCoreApplication::translate("MainWindow", "Copy P&ixmap", nullptr));
actionCopyFilePath->setText(QCoreApplication::translate("MainWindow", "Copy &File Path", nullptr));
actionPaste->setText(QCoreApplication::translate("MainWindow", "&Paste", nullptr));
actionTrash->setText(QCoreApplication::translate("MainWindow", "Move to Trash", nullptr));
actionToggleAvoidResetTransform->setText(QCoreApplication::translate("MainWindow", "Keep transformation", "The 'transformation' means the flip/rotation status that currently applied to the image view"));
actionSettings->setText(QCoreApplication::translate("MainWindow", "Configure...", nullptr));
actionHelp->setText(QCoreApplication::translate("MainWindow", "Help", nullptr));
#ifdef Q_OS_WIN
actionLocateInFileManager->setText(
QCoreApplication::translate(
@@ -119,8 +142,9 @@ void ActionManager::setupAction(MainWindow *mainWindow)
actionLocateInFileManager->setText(QCoreApplication::translate("MainWindow", "Show in directory", nullptr));
#endif // Q_OS_WIN
actionProperties->setText(QCoreApplication::translate("MainWindow", "Properties", nullptr));
actionQuitApp->setText(QCoreApplication::translate("MainWindow", "Quit", nullptr));
actionSettings->setText(QCoreApplication::translate("MainWindow", "Configure...", nullptr));
actionHelp->setText(QCoreApplication::translate("MainWindow", "Help", nullptr));
// endregion
QMetaObject::connectSlotsByName(mainWindow);
@@ -128,34 +152,57 @@ void ActionManager::setupAction(MainWindow *mainWindow)
void ActionManager::setupShortcuts()
{
actionOpen->setShortcut(QKeySequence::Open);
actionCopyPixmap->setShortcut(QKeySequence::Copy);
actionPrevPicture->setShortcuts({
QKeySequence(Qt::Key_Left),
QKeySequence(Qt::Key_PageUp),
});
actionNextPicture->setShortcuts({
QKeySequence(Qt::Key_Right),
QKeySequence(Qt::Key_PageDown),
});
actionActualSize->setShortcut(QKeySequence(Qt::CTRL | Qt::Key_0));
actionZoomIn->setShortcut(QKeySequence::ZoomIn);
actionZoomOut->setShortcut(QKeySequence::ZoomOut);
actionPrevPicture->setShortcuts({
QKeySequence(Qt::Key_PageUp),
QKeySequence(Qt::Key_Left),
});
actionNextPicture->setShortcuts({
QKeySequence(Qt::Key_PageDown),
QKeySequence(Qt::Key_Right),
});
actionHorizontalFlip->setShortcut(QKeySequence(Qt::CTRL | Qt::Key_R));
actionCopyPixmap->setShortcut(QKeySequence::Copy);
actionPaste->setShortcut(QKeySequence::Paste);
actionTrash->setShortcut(QKeySequence::Delete);
actionHelp->setShortcut(QKeySequence::HelpContents);
actionSettings->setShortcut(QKeySequence::Preferences);
actionProperties->setShortcut(QKeySequence(Qt::CTRL | Qt::Key_I));
actionQuitApp->setShortcuts({
QKeySequence(Qt::Key_Space),
QKeySequence(Qt::Key_Escape)
});
actionSettings->setShortcut(QKeySequence::Preferences);
actionHelp->setShortcut(QKeySequence::HelpContents);
}
void ActionManager::enablePrevNextPictureAction(bool enablePrevPictureAction, bool enableNextPictureAction)
void ActionManager::updateActionState(PlaylistManager* pm, GraphicsView* gv)
{
actionPrevPicture->setEnabled(enablePrevPictureAction);
actionNextPicture->setEnabled(enableNextPictureAction);
const auto* gs = gv->scene();
const auto* settings = Settings::instance();
// Update Prev/Next Picture State
const int galleryFileCount = pm->totalCount();
const bool loopGallery = settings->loopGallery();
actionPrevPicture->setEnabled(galleryFileCount > 1 && (loopGallery || !pm->isFirstIndex()));
actionNextPicture->setEnabled(galleryFileCount > 1 && (loopGallery || !pm->isLastIndex()));
// Update Avoid Reset Transform
actionToggleAvoidResetTransform->setCheckable(gv->avoidResetTransform());
// Update Checkerboard
actionToggleCheckerboard->setChecked(gv->checkerboard());
// Update Animation Graphics Action
bool canPauseAnimation = gs->canPauseAnimation();
actionTogglePauseAnimation->setEnabled(canPauseAnimation);
if (canPauseAnimation) {
actionTogglePauseAnimation->setChecked(gs->isPauseAnimation());
} else {
actionTogglePauseAnimation->setChecked(false);
}
bool canSkipAnimation = gs->canSkipAnimationFrame();
actionAnimationNextFrame->setEnabled(canSkipAnimation);
// TODO: Add more...
}