diff options
-rw-r--r-- | src/config.cpp | 140 | ||||
-rw-r--r-- | src/config.hpp | 30 | ||||
-rw-r--r-- | src/main_window.cpp | 93 | ||||
-rw-r--r-- | src/main_window.hpp | 1 |
4 files changed, 197 insertions, 67 deletions
diff --git a/src/config.cpp b/src/config.cpp index 1ab2b93..5ffb76e 100644 --- a/src/config.cpp +++ b/src/config.cpp @@ -33,13 +33,10 @@ Shortcuts::Shortcuts(ShortcutMap&& shortcutMap) : { for (const auto& [action, shortcuts] : m_actionToShortcuts) { for (const auto& shortcut : shortcuts) { - qDebug("Working on action %s", actionTypeToString(action)); auto bindResult = bind(action, shortcut); if (bindResult != FudStatus::Success) { qWarning("Error: %s", FudStatusToString(bindResult)); return; - } else { - qDebug("Bound %s to %s", qPrintable(shortcut.toString()), actionTypeToString(action)); } } } @@ -231,7 +228,7 @@ ShortcutMap Shortcuts::fromUserConfig(const std::filesystem::path& configFileNam auto binder = [&](ActionType action, QKeySequence keySeq) { auto bindDefaultStatus = shortcuts.bind(action, keySeq); if (bindDefaultStatus != FudStatus::Success) { - qDebug("%s already bound", actionTypeToString(action)); + qWarning("%s already bound", actionTypeToString(action)); } }; binder(ActionType::OpenFile, QKeySequence(QKeySequence::Open)); @@ -277,30 +274,45 @@ ShortcutMap GetsuyomiConfig::shortcuts() const return shortcuts; } +ShortcutDisplay::ShortcutDisplay(QWidget* parent, QKeySequence shortcut) : QWidget{parent}, m_binding{shortcut} +{ + auto layout = new QHBoxLayout(); + layout->addWidget(new QLabel(shortcut.toString())); + auto* deleteButton = new QPushButton("Delete", this); + connect(deleteButton, &QPushButton::clicked, this, &ShortcutDisplay::removeOnClicked); + layout->addWidget(deleteButton); + setLayout(layout); +} + +void ShortcutDisplay::removeOnClicked() +{ + emit removeClicked(m_binding); +} + ShortcutCollector::ShortcutCollector(QWidget* parent, ActionType action, Shortcuts& shortcuts) : - QWidget(parent), m_action{action}, m_shortcuts{shortcuts} + QWidget(parent), m_action{action}, m_shortcuts{shortcuts}, m_bindings{} { - m_layout = new QGridLayout(); + m_layout = new QVBoxLayout(); + auto headerLayout = new QHBoxLayout(); auto* name = new QLabel(actionTypeToString(m_action)); - m_layout->addWidget(name, 0, 0); + headerLayout->addWidget(name); m_shortcutEditor = new QKeySequenceEdit(this); - m_layout->addWidget(m_shortcutEditor, 0, 1); - m_shortcutTable = new QTableWidget(this); - m_layout->addWidget(m_shortcutTable); + m_shortcutEditor->setMaximumSequenceLength(1); + connect(m_shortcutEditor, &QKeySequenceEdit::editingFinished, this, &ShortcutCollector::checkBinding); + headerLayout->addWidget(m_shortcutEditor); - auto shortcutOptions = m_shortcuts.shortcuts(m_action); - if (shortcutOptions != std::nullopt) { - m_shortcutTable->setColumnCount(2); - m_actionList = *shortcutOptions; + m_acceptButton = new QPushButton("Accept", this); + m_acceptButton->setEnabled(false); + connect(m_acceptButton, &QPushButton::clicked, this, &ShortcutCollector::addBinding); + headerLayout->addWidget(m_acceptButton); + headerLayout->addStretch(); - m_shortcutTable->setRowCount(static_cast<int>(m_actionList.size())); + m_layout->addLayout(headerLayout); - for (auto index = 0; index < m_actionList.size(); ++index) { - const auto& shortcut = m_actionList[index]; - m_shortcutTable->setCellWidget(index, 0, new QLabel(shortcut.toString())); - auto* deleteButton = new QPushButton("Delete", this); - m_shortcutTable->setCellWidget(index, 1, deleteButton); - connect(m_shortcutTable, &QTableWidget::cellClicked, this, &ShortcutCollector::removeShortcut); + auto shortcutOptions = m_shortcuts.shortcuts(m_action); + if (shortcutOptions != std::nullopt) { + for (const auto& binding : *shortcutOptions) { + createBinding(binding); } } else { qWarning("No shortcuts found for %s", actionTypeToString(action)); @@ -309,15 +321,66 @@ ShortcutCollector::ShortcutCollector(QWidget* parent, ActionType action, Shortcu setLayout(m_layout); } -void ShortcutCollector::removeShortcut(int row, int) +void ShortcutCollector::createBinding(QKeySequence binding) { - auto keySequence = m_actionList[row]; - auto result = m_shortcuts.remove(keySequence); - if (result == FudStatus::Success) { - m_actionList.removeAt(row); + auto displayItem = new ShortcutDisplay(this, binding); + m_bindings[binding] = displayItem; + m_layout->addWidget(displayItem); + connect(displayItem, &ShortcutDisplay::removeClicked, this, &ShortcutCollector::removeBinding); +} + +void ShortcutCollector::checkBinding() +{ + auto keySequence = m_shortcutEditor->keySequence(); + if (keySequence == QKeySequence::UnknownKey) { + m_acceptButton->setEnabled(false); + return; + } + + m_acceptButton->setEnabled(not m_shortcuts.contains(keySequence)); +} + +void ShortcutCollector::addBinding() +{ + auto keySequence = m_shortcutEditor->keySequence(); + if (keySequence == QKeySequence::UnknownKey) { + qWarning("Invalid state - can't accept unknown key"); + return; + } else if (m_shortcuts.contains(keySequence)) { + qWarning("Shortcut %s already bound", qPrintable(keySequence.toString())); + return; + } + auto result = m_shortcuts.bind(m_action, keySequence); + if (result != FudStatus::Success) { + qCritical("Error binding %s to action %s", qPrintable(keySequence.toString()), actionTypeToString(m_action)); + return; + } + if (m_bindings.contains(keySequence)) { + qWarning("binding %s to action %s already exists", qPrintable(keySequence.toString()), actionTypeToString(m_action)); + m_layout->removeWidget(m_bindings[keySequence]); + delete m_bindings[keySequence]; + } + + createBinding(keySequence); + m_shortcutEditor->clear(); +} + +void ShortcutCollector::removeBinding(QKeySequence binding) +{ + auto result = m_shortcuts.remove(binding); + if (result == FudStatus::NotFound) { + qWarning("binding %s not found", qPrintable(binding.toString())); + } else if (result != FudStatus::Success) { + qWarning("error removing binding %s: %s", qPrintable(binding.toString()), FudStatusToString(result)); + } + auto bindingHandle = m_bindings.extract(binding); + if (bindingHandle) { + m_layout->removeWidget(bindingHandle.mapped()); + delete bindingHandle.mapped(); } else { - qCritical("What"); + qWarning("Could not remove widget!"); } + checkBinding(); } Settings::Settings(QWidget* parent, Shortcuts&& shortcuts) : QDialog{parent}, m_shortcuts{std::move(shortcuts)} @@ -329,11 +392,32 @@ Settings::Settings(QWidget* parent, Shortcuts&& shortcuts) : QDialog{parent}, m_ return; } + auto containerLayout = new QHBoxLayout(); + auto* columnLayout = new QVBoxLayout(); + size_t counter{0}; + constexpr size_t maxEntriesPerColumn{4}; + for (const auto& action : m_shortcuts.actions()) { auto* collector = new ShortcutCollector(this, action, m_shortcuts); - layout->addWidget(collector); + columnLayout->addWidget(collector); + counter++; + if (counter % (maxEntriesPerColumn + 1) == 0) { + containerLayout->addLayout(columnLayout); + columnLayout = new QVBoxLayout(); + } } + if (columnLayout->count() > 0) { + containerLayout->addLayout(columnLayout); + } + + layout->addLayout(containerLayout); + + auto* dialogButtonBox = new QDialogButtonBox(QDialogButtonBox::Ok | QDialogButtonBox::Cancel); + connect(dialogButtonBox, &QDialogButtonBox::accepted, this, &QDialog::accept); + connect(dialogButtonBox, &QDialogButtonBox::rejected, this, &QDialog::reject); + layout->addWidget(dialogButtonBox); + setLayout(layout); } diff --git a/src/config.hpp b/src/config.hpp index 95df6b6..5937a9b 100644 --- a/src/config.hpp +++ b/src/config.hpp @@ -129,7 +129,23 @@ struct GetsuyomiConfig { ShortcutMap shortcuts() const; }; +class ShortcutDisplay : public QWidget { + Q_OBJECT +public: + ShortcutDisplay(QWidget* parent, QKeySequence shortcut); + +signals: + void removeClicked(QKeySequence shortcut); +private: + QKeySequence m_binding; +private slots: + void removeOnClicked(); +}; + +constexpr auto foo = sizeof(QKeySequence); + class ShortcutCollector : public QWidget { + Q_OBJECT public: ShortcutCollector(QWidget* parent, ActionType action, Shortcuts& shortcuts); ~ShortcutCollector() = default; @@ -138,19 +154,25 @@ class ShortcutCollector : public QWidget { ShortcutCollector& operator=(const ShortcutCollector&) = delete; ShortcutCollector& operator=(ShortcutCollector&&) = delete; +private: + void createBinding(QKeySequence binding); + private slots: - void removeShortcut(int row, int); + void checkBinding(); + void addBinding(); + void removeBinding(QKeySequence shortcut); private: ActionType m_action; Shortcuts& m_shortcuts; + std::map<QKeySequence, ShortcutDisplay*> m_bindings; QKeySequenceEdit* m_shortcutEditor{nullptr}; - QGridLayout* m_layout{nullptr}; - ShortcutList m_actionList{}; - QTableWidget* m_shortcutTable{nullptr}; + QPushButton* m_acceptButton{nullptr}; + QVBoxLayout* m_layout{nullptr}; }; class Settings : public QDialog { + Q_OBJECT public: Settings(QWidget* parent, Shortcuts&& shortcuts); Settings(const Settings&) = delete; diff --git a/src/main_window.cpp b/src/main_window.cpp index dea951c..82e6ef2 100644 --- a/src/main_window.cpp +++ b/src/main_window.cpp @@ -50,6 +50,26 @@ FudStatus createXdgDirectory(const std::string& directoryName) return FudStatus::Success; } +void setUserConfig(GetsuyomiConfig& config, const ShortcutMap& shortcutMap) +{ + auto binder = [&](ShortcutList& shortcuts, ActionType action) { + shortcuts = shortcutListFromSet(shortcutMap.at(action)); + }; + + binder(config.openFileShortcuts, ActionType::OpenFile); + binder(config.openDirectoryShortcuts, ActionType::OpenDirectory); + binder(config.quitShortcuts, ActionType::Quit); + + binder(config.settingsShortcuts, ActionType::Configure); + + binder(config.nextShortcuts, ActionType::Next); + binder(config.backShortcuts, ActionType::Back); + + binder(config.singlePageShortcuts, ActionType::SinglePage); + binder(config.dualPageShortcuts, ActionType::DualPage); + binder(config.mangaPageShortcuts, ActionType::MangaPage); +} + GetConfigResult getUserConfig() { auto configResult = getEnvironment(); @@ -74,22 +94,7 @@ GetConfigResult getUserConfig() auto configFileName = std::filesystem::path(config.configHome).append("config.lua"); auto shortcutMap = Shortcuts::fromUserConfig(configFileName); - auto binder = [&](ShortcutList& shortcuts, ActionType action) { - shortcuts = shortcutListFromSet(shortcutMap.at(action)); - }; - - binder(config.openFileShortcuts, ActionType::OpenFile); - binder(config.openDirectoryShortcuts, ActionType::OpenDirectory); - binder(config.quitShortcuts, ActionType::Quit); - - binder(config.settingsShortcuts, ActionType::Configure); - - binder(config.nextShortcuts, ActionType::Next); - binder(config.backShortcuts, ActionType::Back); - - binder(config.singlePageShortcuts, ActionType::SinglePage); - binder(config.dualPageShortcuts, ActionType::DualPage); - binder(config.mangaPageShortcuts, ActionType::MangaPage); + setUserConfig(config, shortcutMap); return GetConfigResult::okay(config); } @@ -130,48 +135,30 @@ FudStatus GetsuyomiApp::setup() void GetsuyomiApp::createActions() { m_openFile = new QAction(QIcon::fromTheme(QIcon::ThemeIcon::DocumentOpen), tr("&Open File"), this); - m_openFile->setShortcuts(m_config.openFileShortcuts); - m_openFile->setStatusTip(tr("Open a file")); connect(m_openFile, &QAction::triggered, this, &GetsuyomiApp::openFile); m_openDirectory = new QAction(QIcon::fromTheme(QIcon::ThemeIcon::FolderOpen), tr("Open &Directory"), this); - m_openDirectory->setShortcuts(m_config.openDirectoryShortcuts); - m_openDirectory->setStatusTip(tr("Open a directory")); connect(m_openDirectory, &QAction::triggered, this, &GetsuyomiApp::openDirectory); m_quitAction = new QAction(QIcon::fromTheme(QIcon::ThemeIcon::ApplicationExit), tr("&Quit"), this); - m_quitAction->setShortcuts(m_config.quitShortcuts); - m_quitAction->setStatusTip(tr("Quit")); connect(m_quitAction, &QAction::triggered, this, &GetsuyomiApp::quit); m_settingsAction = new QAction(QIcon("resources/gear.svg"), tr("&Settings"), this); - m_settingsAction->setShortcuts(m_config.settingsShortcuts); - m_settingsAction->setStatusTip(tr("Configure getsuyomi")); connect(m_settingsAction, &QAction::triggered, this, &GetsuyomiApp::configure); m_nextAction = new QAction(QIcon::fromTheme(QIcon::ThemeIcon::GoNext), tr("Next"), this); - m_nextAction->setShortcuts(m_config.nextShortcuts); - m_nextAction->setStatusTip(tr("Next")); connect(m_nextAction, &QAction::triggered, this, &GetsuyomiApp::next); m_backAction = new QAction(QIcon::fromTheme(QIcon::ThemeIcon::GoPrevious), tr("Back"), this); - m_backAction->setShortcuts(m_config.backShortcuts); - m_backAction->setStatusTip(tr("Back")); connect(m_backAction, &QAction::triggered, this, &GetsuyomiApp::back); m_setSinglePageLayout = new QAction(QIcon("../resources/pageSingle.png"), tr("Single Page Layout"), this); - m_setSinglePageLayout->setShortcuts(m_config.singlePageShortcuts); - m_setSinglePageLayout->setStatusTip(tr("Set Single Page Layout")); connect(m_setSinglePageLayout, &QAction::triggered, this, &GetsuyomiApp::setSinglePageLayout); m_setDualPageLayout = new QAction(QIcon("../resources/pageDual.png"), tr("Dual Page Layout"), this); - m_setDualPageLayout->setShortcuts(m_config.dualPageShortcuts); - m_setDualPageLayout->setStatusTip(tr("Set Dual Page Layout")); connect(m_setDualPageLayout, &QAction::triggered, this, &GetsuyomiApp::setDualPageLayout); m_setMangaLayout = new QAction(QIcon("../resources/pageManga.png"), tr("Manga Page Layout"), this); - m_setMangaLayout->setShortcuts(m_config.mangaPageShortcuts); - m_setMangaLayout->setStatusTip(tr("Set Manga Page Layout")); connect(m_setMangaLayout, &QAction::triggered, this, &GetsuyomiApp::setMangaLayout); m_setPageLayoutGroup = new QActionGroup(this); @@ -179,6 +166,38 @@ void GetsuyomiApp::createActions() m_setPageLayoutGroup->addAction(m_setDualPageLayout); m_setPageLayoutGroup->addAction(m_setMangaLayout); m_setPageLayoutGroup->setExclusionPolicy(QActionGroup::ExclusionPolicy::Exclusive); + + bindShortcuts(); +} + +void GetsuyomiApp::bindShortcuts() +{ + m_openFile->setShortcuts(m_config.openFileShortcuts); + m_openFile->setStatusTip(tr("Open a file")); + + m_openDirectory->setShortcuts(m_config.openDirectoryShortcuts); + m_openDirectory->setStatusTip(tr("Open a directory")); + + m_quitAction->setShortcuts(m_config.quitShortcuts); + m_quitAction->setStatusTip(tr("Quit")); + + m_settingsAction->setShortcuts(m_config.settingsShortcuts); + m_settingsAction->setStatusTip(tr("Configure getsuyomi")); + + m_nextAction->setShortcuts(m_config.nextShortcuts); + m_nextAction->setStatusTip(tr("Next")); + + m_backAction->setShortcuts(m_config.backShortcuts); + m_backAction->setStatusTip(tr("Back")); + + m_setSinglePageLayout->setShortcuts(m_config.singlePageShortcuts); + m_setSinglePageLayout->setStatusTip(tr("Set Single Page Layout")); + + m_setDualPageLayout->setShortcuts(m_config.dualPageShortcuts); + m_setDualPageLayout->setStatusTip(tr("Set Dual Page Layout")); + + m_setMangaLayout->setShortcuts(m_config.mangaPageShortcuts); + m_setMangaLayout->setStatusTip(tr("Set Manga Page Layout")); } void GetsuyomiApp::createMenus() @@ -282,7 +301,11 @@ void GetsuyomiApp::configure() qCritical("Invalid settings"); return; } - settings.exec(); + if (settings.exec()) { + const auto& shortcuts = settings.shortcuts(); + setUserConfig(m_config, shortcuts.shortcutMap()); + bindShortcuts(); + } } void GetsuyomiApp::next() diff --git a/src/main_window.hpp b/src/main_window.hpp index 2dabf77..e5363a2 100644 --- a/src/main_window.hpp +++ b/src/main_window.hpp @@ -32,6 +32,7 @@ class GetsuyomiApp : public QMainWindow { private: /* Private methods */ void createActions(); + void bindShortcuts(); void createMenus(); void createToolBar(); |