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