From 195bbe3636155613555c27f4e67d21aa1461a5b6 Mon Sep 17 00:00:00 2001 From: David Hurka Date: Sat, 29 May 2021 23:08:56 +0000 Subject: [PATCH] Create color mode menu. Implemented using a ColorModeMenu class, derived from ToggleActionMenu (derived from KActionMenu), as a child object of PageView. * KToggleAction for every color mode, allows to set shortcuts for every mode. Color mode actions have icons. * KToggleAction for normal colors mode. * ToggleActionMenu containing all color mode actions. If triggered, toggles color mode between normal colors and last change colors mode. "Toggle Change Colors" is replaced by "Change Colors", which is actually a toggle action. BUG: 407217 BUG: 437755 --- CMakeLists.txt | 3 +- conf/okular.kcfg | 7 ++ conf/okular_core.kcfg | 4 + part/colormodemenu.cpp | 145 +++++++++++++++++++++++++++++++++++++ part/colormodemenu.h | 74 +++++++++++++++++++ part/pageview.cpp | 22 ++---- part/pageview.h | 3 - part/part.cpp | 21 +++++- part/part.h | 1 + part/preferencesdialog.cpp | 9 ++- part/preferencesdialog.h | 2 + 11 files changed, 269 insertions(+), 22 deletions(-) create mode 100644 part/colormodemenu.cpp create mode 100644 part/colormodemenu.h diff --git a/CMakeLists.txt b/CMakeLists.txt index 98031b3db..d05a74f80 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -275,7 +275,7 @@ ki18n_wrap_ui(okularcore_SRCS core/chooseenginewidget.ui ) -kconfig_add_kcfg_files(okularcore_SRCS conf/settings_core.kcfgc) +kconfig_add_kcfg_files(okularcore_SRCS GENERATE_MOC conf/settings_core.kcfgc) add_library(okularcore SHARED ${okularcore_SRCS}) generate_export_header(okularcore BASE_NAME okularcore EXPORT_FILE_NAME "${CMAKE_CURRENT_BINARY_DIR}/core/okularcore_export.h") @@ -381,6 +381,7 @@ if(BUILD_DESKTOP) part/annotationwidgets.cpp part/bookmarklist.cpp part/certificateviewer.cpp + part/colormodemenu.cpp part/cursorwraphelper.cpp part/debug_ui.cpp part/drawingtoolactions.cpp diff --git a/conf/okular.kcfg b/conf/okular.kcfg index f5d37333f..f10bf178e 100644 --- a/conf/okular.kcfg +++ b/conf/okular.kcfg @@ -8,6 +8,9 @@ + + + true @@ -376,19 +379,23 @@ 0x600000 + 0xF0F0F0 + 127 2 253 + 2 2 6 + diff --git a/conf/okular_core.kcfg b/conf/okular_core.kcfg index 41b03bd0e..ad886b13f 100644 --- a/conf/okular_core.kcfg +++ b/conf/okular_core.kcfg @@ -5,6 +5,7 @@ http://www.kde.org/standards/kcfg/1.0/kcfg.xsd" > kuser.h + Normal @@ -43,9 +44,11 @@ Qt::white + false + Inverted @@ -60,6 +63,7 @@ + diff --git a/part/colormodemenu.cpp b/part/colormodemenu.cpp new file mode 100644 index 000000000..7d8e28282 --- /dev/null +++ b/part/colormodemenu.cpp @@ -0,0 +1,145 @@ +/*************************************************************************** + * Copyright (C) 2019-2021 by David Hurka * + * * + * 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 2 of the License, or * + * (at your option) any later version. * + ***************************************************************************/ + +#include "colormodemenu.h" + +#include +#include +#include // TODO KF6: Remove, this was needed for KActionMenu::setPopupMode(). + +#include "guiutils.h" +#include "settings.h" + +ColorModeMenu::ColorModeMenu(KActionCollection *ac, QObject *parent) + : ToggleActionMenu(QIcon::fromTheme(QStringLiteral("color-management")), i18nc("@title:menu", "&Color Mode"), parent) + , m_colorModeActionGroup(new QActionGroup(this)) + , m_aChangeColors(new KToggleAction(QIcon::fromTheme(QStringLiteral("color-management")), i18nc("@action Change Colors feature toggle action", "Change Colors"), this)) +{ +#if KWIDGETSADDONS_VERSION < QT_VERSION_CHECK(5, 77, 0) + setDelayed(false); + setStickyMenu(true); +#else + setPopupMode(QToolButton::MenuButtonPopup); +#endif + + Q_ASSERT_X(ac->action(QStringLiteral("color_mode_menu")) == nullptr, "ColorModeMenu", "ColorModeMenu constructed twice; color_mode_menu already in action collection."); + ac->addAction(QStringLiteral("color_mode_menu"), this); + + // Normal Colors action. + m_aNormal = new KToggleAction(i18nc("@item:inmenu color mode", "&Normal Colors"), this); + ac->addAction(QStringLiteral("color_mode_normal"), m_aNormal); + addAction(m_aNormal); + m_colorModeActionGroup->addAction(m_aNormal); + + // Other color mode actions. + auto addColorMode = [=](KToggleAction *a, const QString &name, Okular::SettingsCore::EnumRenderMode::type id) { + a->setData(int(id)); + addAction(a); + ac->addAction(name, a); + m_colorModeActionGroup->addAction(a); + }; + addColorMode(new KToggleAction(QIcon::fromTheme(QStringLiteral("invertimage")), i18nc("@item:inmenu color mode", "&Invert Colors"), this), QStringLiteral("color_mode_inverted"), Okular::SettingsCore::EnumRenderMode::Inverted); + m_aPaperColor = new KToggleAction(i18nc("@item:inmenu color mode", "Change &Paper Color"), this); + addColorMode(m_aPaperColor, QStringLiteral("color_mode_paper"), Okular::SettingsCore::EnumRenderMode::Paper); + m_aDarkLight = new KToggleAction(i18nc("@item:inmenu color mode", "Change &Dark && Light Colors"), this); + addColorMode(m_aDarkLight, QStringLiteral("color_mode_recolor"), Okular::SettingsCore::EnumRenderMode::Recolor); + addColorMode(new KToggleAction(QIcon::fromTheme(QStringLiteral("color-mode-black-white")), i18nc("@item:inmenu color mode", "Convert to &Black && White"), this), + QStringLiteral("color_mode_black_white"), + Okular::SettingsCore::EnumRenderMode::BlackWhite); + addColorMode(new KToggleAction(QIcon::fromTheme(QStringLiteral("color-mode-invert-text")), i18nc("@item:inmenu color mode", "Invert &Lightness"), this), + QStringLiteral("color_mode_invert_lightness"), + Okular::SettingsCore::EnumRenderMode::InvertLightness); + addColorMode(new KToggleAction(QIcon::fromTheme(QStringLiteral("color-mode-invert-image")), i18nc("@item:inmenu color mode", "Invert L&uma (sRGB Linear)"), this), + QStringLiteral("color_mode_invert_luma_srgb"), + Okular::SettingsCore::EnumRenderMode::InvertLuma); + addColorMode(new KToggleAction(QIcon::fromTheme(QStringLiteral("color-mode-invert-image")), i18nc("@item:inmenu color mode", "Invert Luma (&Symmetric)"), this), + QStringLiteral("color_mode_invert_luma_symmetric"), + Okular::SettingsCore::EnumRenderMode::InvertLumaSymmetric); + addColorMode(new KToggleAction(QIcon::fromTheme(QStringLiteral("color-mode-hue-shift-positive")), i18nc("@item:inmenu color mode", "Shift Hue P&ositive"), this), + QStringLiteral("color_mode_hue_shift_positive"), + Okular::SettingsCore::EnumRenderMode::HueShiftPositive); + addColorMode(new KToggleAction(QIcon::fromTheme(QStringLiteral("color-mode-hue-shift-negative")), i18nc("@item:inmenu color mode", "Shift Hue N&egative"), this), + QStringLiteral("color_mode_hue_shift_negative"), + Okular::SettingsCore::EnumRenderMode::HueShiftNegative); + + // Add Configure Color Modes action. + addSeparator(); + QAction *aConfigure = ac->action(QStringLiteral("options_configure_color_modes")); + Q_ASSERT_X(aConfigure, "ColorModeMenu", "ColorModeMenu constructed before Okular::Part?!? options_configure_color_modes not in action collection."); + addAction(aConfigure); + + connect(m_colorModeActionGroup, &QActionGroup::triggered, this, &ColorModeMenu::slotColorModeActionTriggered); + connect(Okular::SettingsCore::self(), &Okular::SettingsCore::colorModesChanged, this, &ColorModeMenu::slotConfigChanged); + connect(Okular::Settings::self(), &Okular::Settings::colorModesChanged2, this, &ColorModeMenu::slotConfigChanged); + connect(this, &QAction::changed, this, &ColorModeMenu::slotChanged); + + // Allow to configure a toggle shortcut. + connect(m_aChangeColors, &QAction::toggled, this, &ColorModeMenu::slotSetChangeColors); + ac->addAction(QStringLiteral("color_mode_change_colors"), m_aChangeColors); + + slotConfigChanged(); +} + +void ColorModeMenu::slotColorModeActionTriggered(QAction *action) +{ + const int newRenderMode = action->data().toInt(); + // Color mode toggles to normal when the currently checked mode is triggered. + // Normal mode is special, triggering it always enables normal mode. + // Otherwise, the triggered color mode is activated. + if (action == m_aNormal) { + Okular::SettingsCore::setChangeColors(false); + } else if (Okular::SettingsCore::renderMode() == newRenderMode) { + Okular::SettingsCore::setChangeColors(!Okular::SettingsCore::changeColors()); + } else { + Okular::SettingsCore::setRenderMode(newRenderMode); + Okular::SettingsCore::setChangeColors(true); + } + Okular::SettingsCore::self()->save(); +} + +void ColorModeMenu::slotSetChangeColors(bool on) +{ + Okular::SettingsCore::setChangeColors(on); + Okular::SettingsCore::self()->save(); +} + +void ColorModeMenu::slotConfigChanged() +{ + // Check the current color mode action, and update the toolbar button default action + const int rm = Okular::SettingsCore::renderMode(); + const QList colorModeActions = m_colorModeActionGroup->actions(); + for (QAction *a : colorModeActions) { + if (a != m_aNormal && a->data().toInt() == rm) { + a->setChecked(true); + setDefaultAction(a); + break; + } + } + + // If Change Colors is disabled, check Normal Colors instead + if (!Okular::SettingsCore::changeColors()) { + m_aNormal->setChecked(true); + } + + // Update color icons + m_aPaperColor->setIcon(GuiUtils::createColorIcon(QList() << Okular::Settings::paperColor(), QIcon::fromTheme(QStringLiteral("paper-color")))); + m_aDarkLight->setIcon(GuiUtils::createColorIcon(QList() << Okular::Settings::recolorForeground() << Okular::Settings::recolorBackground(), QIcon::fromTheme(QStringLiteral("color-mode-black-white")))); + + // Update toggle action + m_aChangeColors->setChecked(Okular::SettingsCore::changeColors()); +} + +void ColorModeMenu::slotChanged() +{ + const bool enabled = isEnabled(); + const QList colorModeActions = m_colorModeActionGroup->actions(); + for (QAction *a : colorModeActions) { + a->setEnabled(enabled); + } +} diff --git a/part/colormodemenu.h b/part/colormodemenu.h new file mode 100644 index 000000000..aeaac0be0 --- /dev/null +++ b/part/colormodemenu.h @@ -0,0 +1,74 @@ +/*************************************************************************** + * Copyright (C) 2019-2021 by David Hurka * + * * + * 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 2 of the License, or * + * (at your option) any later version. * + ***************************************************************************/ + +#ifndef COLORMODEMENU_H +#define COLORMODEMENU_H + +#include "toggleactionmenu.h" + +class KActionCollection; +class KToggleAction; + +/** + * Color Mode menu. Allows to change Okular::Settings::RenderMode from the toolbar. + * + * The toolbar button will always show the last selected color mode (except normal mode), + * so it can be quickly enabled and disabled by just clicking the button. + * Clicking on the menu arrow opens a menu with all color modes (including normal mode), + * and an action to configure the color modes. + * + * Every color mode actions is available in the action collection, in addition to this menu itself. + * + * Color mode actions are enabled/disabled automatically when this menu is enabled/disabled. + */ +class ColorModeMenu : public ToggleActionMenu +{ + Q_OBJECT + +public: + explicit ColorModeMenu(KActionCollection *ac, QObject *parent); + +protected: + /** Makes color mode actions exclusive */ + QActionGroup *m_colorModeActionGroup; + + KToggleAction *m_aNormal; + KToggleAction *m_aPaperColor; + KToggleAction *m_aDarkLight; + + /** Allows to set a shortcut to toggle the Change Colors feature. */ + KToggleAction *m_aChangeColors; + +protected Q_SLOTS: + /** + * Sets the color mode (render mode) to the one represented by @p action. + * + * If @p action represents the current mode, toggles the Change Colors feature. + */ + void slotColorModeActionTriggered(QAction *action); + + /** + * Sets the change colors feature on or off. + */ + void slotSetChangeColors(bool on); + + /** + * Updates the default action and the checked states of the color mode menu. + * + * Call this when the color mode was changed or Change Colors was toggled. + */ + void slotConfigChanged(); + + /** + * Updates child actions as necessary + */ + void slotChanged(); +}; + +#endif // COLORMODEMENU_H diff --git a/part/pageview.cpp b/part/pageview.cpp index af61752ae..97333b9a1 100644 --- a/part/pageview.cpp +++ b/part/pageview.cpp @@ -72,6 +72,7 @@ // local includes #include "annotationpopup.h" #include "annotwindow.h" +#include "colormodemenu.h" #include "core/annotations.h" #include "cursorwraphelper.h" #include "debug_ui.h" @@ -246,6 +247,7 @@ public: KToggleAction *aZoomAutoFit; KActionMenu *aViewModeMenu; QActionGroup *viewModeActionGroup; + ColorModeMenu *aColorModeMenu; KToggleAction *aViewContinuous; QAction *aPrevAction; KToggleAction *aToggleForms; @@ -375,6 +377,7 @@ PageView::PageView(QWidget *parent, Okular::Document *document) d->aViewModeMenu = nullptr; d->aViewContinuous = nullptr; d->viewModeActionGroup = nullptr; + d->aColorModeMenu = nullptr; d->aPrevAction = nullptr; d->aToggleForms = nullptr; d->aSpeakDoc = nullptr; @@ -670,9 +673,7 @@ void PageView::setupViewerActions(KActionCollection *ac) mz->setActionGroup(d->mouseModeActionGroup); mz->setChecked(Okular::Settings::mouseMode() == Okular::Settings::EnumMouseMode::Zoom); - QAction *aToggleChangeColors = new QAction(i18n("&Toggle Change Colors"), this); - ac->addAction(QStringLiteral("toggle_change_colors"), aToggleChangeColors); - connect(aToggleChangeColors, &QAction::triggered, this, &PageView::slotToggleChangeColors); + d->aColorModeMenu = new ColorModeMenu(ac, this); } // WARNING: 'setupViewerActions' must have been called before this method @@ -1300,6 +1301,9 @@ void PageView::updateActionState(bool haspages, bool hasformwidgets) if (d->aZoomActual) d->aZoomActual->setEnabled(haspages && d->zoomFactor != 1.0); + if (d->aColorModeMenu) + d->aColorModeMenu->setEnabled(haspages); + if (d->aReadingDirection) { d->aReadingDirection->setEnabled(haspages); } @@ -5162,18 +5166,6 @@ void PageView::slotProcessRenditionAction(const Okular::RenditionAction *action) }; } -void PageView::slotSetChangeColors(bool active) -{ - Okular::SettingsCore::setChangeColors(active); - Okular::Settings::self()->save(); - viewport()->update(); -} - -void PageView::slotToggleChangeColors() -{ - slotSetChangeColors(!Okular::SettingsCore::changeColors()); -} - void PageView::slotFitWindowToPage() { const PageViewItem *currentPageItem = nullptr; diff --git a/part/pageview.h b/part/pageview.h index 0872fbd8f..44dad6d52 100644 --- a/part/pageview.h +++ b/part/pageview.h @@ -126,9 +126,6 @@ public Q_SLOTS: void openAnnotationWindow(Okular::Annotation *annotation, int pageNumber); void reloadForms(); - void slotToggleChangeColors(); - void slotSetChangeColors(bool active); - void slotSelectPage(); void slotAction(Okular::Action *action); diff --git a/part/part.cpp b/part/part.cpp index 0dfd2ca74..0ac2a7f5e 100644 --- a/part/part.cpp +++ b/part/part.cpp @@ -945,6 +945,11 @@ void Part::setupActions() eraseDrawingAction->setIcon(QIcon::fromTheme(QStringLiteral("draw-eraser-delete-objects"))); eraseDrawingAction->setEnabled(false); + QAction *configureColorModes = new QAction(i18nc("@action", "Configure Color Modes..."), ac); + ac->addAction(QStringLiteral("options_configure_color_modes"), configureColorModes); + configureColorModes->setIcon(QIcon::fromTheme(QStringLiteral("configure"))); + connect(configureColorModes, &QAction::triggered, this, &Part::slotAccessibilityPreferences); + QAction *configureAnnotations = new QAction(i18n("Configure Annotations..."), ac); ac->addAction(QStringLiteral("options_configure_annotations"), configureAnnotations); configureAnnotations->setIcon(QIcon::fromTheme(QStringLiteral("configure"))); @@ -2809,12 +2814,24 @@ void Part::slotPreferences() void Part::slotToggleChangeColors() { - m_pageView->slotToggleChangeColors(); + slotSetChangeColors(!Okular::SettingsCore::changeColors()); } void Part::slotSetChangeColors(bool active) { - m_pageView->slotSetChangeColors(active); + Okular::SettingsCore::setChangeColors(active); + Okular::Settings::self()->save(); +} + +void Part::slotAccessibilityPreferences() +{ + // Create dialog + PreferencesDialog *dialog = new PreferencesDialog(m_pageView, Okular::Settings::self(), m_embedMode); + dialog->setAttribute(Qt::WA_DeleteOnClose); + + // Show it + dialog->switchToAccessibilityPage(); + dialog->show(); } void Part::slotAnnotationPreferences() diff --git a/part/part.h b/part/part.h index 743d04402..9adbf1eb6 100644 --- a/part/part.h +++ b/part/part.h @@ -436,6 +436,7 @@ private: QUrl m_urlWithFragment; private Q_SLOTS: + void slotAccessibilityPreferences(); void slotAnnotationPreferences(); void slotHandleActivatedSourceReference(const QString &absFileName, int line, int col, bool *handled); }; diff --git a/part/preferencesdialog.cpp b/part/preferencesdialog.cpp index a34ece3de..6e3d7279d 100644 --- a/part/preferencesdialog.cpp +++ b/part/preferencesdialog.cpp @@ -29,6 +29,7 @@ PreferencesDialog::PreferencesDialog(QWidget *parent, KConfigSkeleton *skeleton, m_general = new DlgGeneral(this, embedMode); m_performance = new DlgPerformance(this); m_accessibility = new DlgAccessibility(this); + m_accessibilityPage = nullptr; m_presentation = nullptr; m_annotations = nullptr; m_annotationsPage = nullptr; @@ -39,7 +40,7 @@ PreferencesDialog::PreferencesDialog(QWidget *parent, KConfigSkeleton *skeleton, #endif addPage(m_general, i18n("General"), QStringLiteral("okular"), i18n("General Options")); - addPage(m_accessibility, i18n("Accessibility"), QStringLiteral("preferences-desktop-accessibility"), i18n("Accessibility Reading Aids")); + m_accessibilityPage = addPage(m_accessibility, i18n("Accessibility"), QStringLiteral("preferences-desktop-accessibility"), i18n("Accessibility Reading Aids")); addPage(m_performance, i18n("Performance"), QStringLiteral("preferences-system-performance"), i18n("Performance Tuning")); if (embedMode == Okular::ViewerWidgetMode) { setWindowTitle(i18n("Configure Viewer")); @@ -57,6 +58,12 @@ PreferencesDialog::PreferencesDialog(QWidget *parent, KConfigSkeleton *skeleton, setHelp(QStringLiteral("configure"), QStringLiteral("okular")); } +void PreferencesDialog::switchToAccessibilityPage() +{ + if (m_accessibilityPage) + setCurrentPage(m_accessibilityPage); +} + void PreferencesDialog::switchToAnnotationsPage() { if (m_annotationsPage) diff --git a/part/preferencesdialog.h b/part/preferencesdialog.h index d43b073a4..79a768716 100644 --- a/part/preferencesdialog.h +++ b/part/preferencesdialog.h @@ -33,6 +33,7 @@ class PreferencesDialog : public KConfigDialog public: PreferencesDialog(QWidget *parent, KConfigSkeleton *skeleton, Okular::EmbedMode embedMode); + void switchToAccessibilityPage(); void switchToAnnotationsPage(); protected: @@ -54,6 +55,7 @@ private: DlgDebug *m_debug; #endif + KPageWidgetItem *m_accessibilityPage; KPageWidgetItem *m_annotationsPage; };