diff --git a/atools.pro b/atools.pro index ef83fbdf..b23893e6 100644 --- a/atools.pro +++ b/atools.pro @@ -210,6 +210,7 @@ HEADERS += \ src/geo/rect.h \ src/geo/spatialindex.h \ src/grib/windquery.h \ + src/gui/actionbuttonhandler.h \ src/gui/actionstatesaver.h \ src/gui/actiontextsaver.h \ src/gui/actiontool.h \ @@ -350,6 +351,7 @@ SOURCES += \ src/geo/rect.cpp \ src/geo/spatialindex.cpp \ src/grib/windquery.cpp \ + src/gui/actionbuttonhandler.cpp \ src/gui/actionstatesaver.cpp \ src/gui/actiontextsaver.cpp \ src/gui/actiontool.cpp \ diff --git a/src/gui/actionbuttonhandler.cpp b/src/gui/actionbuttonhandler.cpp new file mode 100644 index 00000000..38dc0c3f --- /dev/null +++ b/src/gui/actionbuttonhandler.cpp @@ -0,0 +1,149 @@ +/***************************************************************************** +* Copyright 2015-2022 Alexander Barthel alex@littlenavmap.org +* +* 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 3 of the License, or +* (at your option) any later version. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program. If not, see . +*****************************************************************************/ + +#include "gui/actionbuttonhandler.h" + +#include +#include + +namespace atools { +namespace gui { + +ActionButtonHandler::ActionButtonHandler(QObject *parent) + : QObject{parent} +{ + +} + +ActionButtonHandler::~ActionButtonHandler() +{ + +} + +void ActionButtonHandler::setNoneAction(QAction *action) +{ + actionNone = action; + connect(actionNone, &QAction::triggered, this, &ActionButtonHandler::noneTriggered); +} + +void ActionButtonHandler::setAllAction(QAction *action) +{ + actionAll = action; + connect(actionAll, &QAction::triggered, this, &ActionButtonHandler::allTriggered); +} + +void ActionButtonHandler::addOtherAction(QAction *action) +{ + actionsOther.insert(action, action->isChecked()); + connect(action, &QAction::triggered, this, &ActionButtonHandler::otherTriggered); +} + +void ActionButtonHandler::noneTriggered() +{ +#ifdef DEBUG_INFORMATION + qDebug() << Q_FUNC_INFO << "lastTriggered" << lastTriggered; +#endif + + if(lastTriggered == NONE) + // Repeated press - restore state + toggleSavedStateWithActions(); + else + // Save state and uncheck all + saveAndSetActionState(false); + + lastTriggered = NONE; + + emit actionNoneTriggered(actionNone); +} + +void ActionButtonHandler::allTriggered() +{ +#ifdef DEBUG_INFORMATION + qDebug() << Q_FUNC_INFO << "lastTriggered" << lastTriggered; +#endif + + if(lastTriggered == ALL) + // Repeated press - restore state + toggleSavedStateWithActions(); + else + // Save state and check all + saveAndSetActionState(true); + + lastTriggered = ALL; + + emit actionAllTriggered(actionAll); +} + +void ActionButtonHandler::otherTriggered() +{ +#ifdef DEBUG_INFORMATION + qDebug() << Q_FUNC_INFO << "lastTriggered" << lastTriggered; +#endif + + QAction *action = dynamic_cast(sender()); + if(action != nullptr) + // Save state for restore + actionsOther[action] = action->isChecked(); + + lastTriggered = ACTION; + + emit actionOtherTriggered(action); +} + +void ActionButtonHandler::toggleSavedStateWithActions() +{ +#ifdef DEBUG_INFORMATION + qDebug() << Q_FUNC_INFO; +#endif + + for(auto it = actionsOther.begin(); it != actionsOther.end(); ++it) + { + QAction *action = it.key(); + bool checked = action->isChecked(); + + // Set new check state + action->blockSignals(true); + action->setChecked(it.value()); + action->blockSignals(false); + + // Save old check state + it.value() = checked; + } +} + +void ActionButtonHandler::saveAndSetActionState(bool checkAction) +{ +#ifdef DEBUG_INFORMATION + qDebug() << Q_FUNC_INFO << "actionChecked" << checkAction; +#endif + + for(auto it = actionsOther.begin(); it != actionsOther.end(); ++it) + { + QAction *action = it.key(); + + // Save check state + it.value() = action->isChecked(); + + // Set new state + action->blockSignals(true); + action->setChecked(checkAction); + action->blockSignals(false); + } +} + +} // namespace gui +} // namespace atools diff --git a/src/gui/actionbuttonhandler.h b/src/gui/actionbuttonhandler.h new file mode 100644 index 00000000..64d25f0b --- /dev/null +++ b/src/gui/actionbuttonhandler.h @@ -0,0 +1,94 @@ +/***************************************************************************** +* Copyright 2015-2022 Alexander Barthel alex@littlenavmap.org +* +* 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 3 of the License, or +* (at your option) any later version. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program. If not, see . +*****************************************************************************/ + +#ifndef ATOOLS_ACTIONBUTTONHANDLER_H +#define ATOOLS_ACTIONBUTTONHANDLER_H + +#include +#include + +class QAction; + +namespace atools { +namespace gui { + +/* + * ZHandler takes care of none/all/selection actions in toolbar buttons. + * + * A press on all/none will show all or no features and a second press on all/none will revert to the selection. + * There is no need to connect actions directly. Use this handlers signals instead. + * + * The handler does not take ownership of actions. All actions have to be checkable. + */ +class ActionButtonHandler : + public QObject +{ + Q_OBJECT + +public: + explicit ActionButtonHandler(QObject *parent); + virtual ~ActionButtonHandler() override; + + /* Set action which will toggle between all and selected features. */ + void setAllAction(QAction *action); + + /* Set action which will toggle between no and selected features. */ + void setNoneAction(QAction *action); + + /* Add any action which can be checked or unchecked by all and none actions */ + void addOtherAction(QAction *action); + +signals: + /* Sent when all is triggered. Other actions will be selected accordingly using blocked signals */ + void actionAllTriggered(QAction *action); + + /* Sent when none is triggered. Other actions will be selected accordingly using blocked signals */ + void actionNoneTriggered(QAction *action); + + /* Sent when any but none or all action is triggered */ + void actionOtherTriggered(QAction *action); + +private: + void noneTriggered(); + void allTriggered(); + void otherTriggered(); + + /* Revert action checkstate to saved values */ + void toggleSavedStateWithActions(); + + /* Save state of actions and set state to actionChecked */ + void saveAndSetActionState(bool checkAction); + + QAction *actionNone, *actionAll; + + /* All other actions with their states saved as value before pressing none/all. + * Value is used to restore state when pressing none/all a second time. */ + QHash actionsOther; + + enum + { + INVALID, + NONE, /* None was last pressed */ + ALL, /* None was last time pressed */ + ACTION /* Other actions was last pressed */ + } lastTriggered = INVALID; +}; + +} // namespace gui +} // namespace atools + +#endif // ATOOLS_ACTIONBUTTONHANDLER_H