diff --git a/src/app/GUI/mainwindow.h b/src/app/GUI/mainwindow.h
index cc5b50fe5..4c8b4f549 100644
--- a/src/app/GUI/mainwindow.h
+++ b/src/app/GUI/mainwindow.h
@@ -59,6 +59,10 @@
#include "widgets/uilayout.h"
#include "widgets/toolbox.h"
+#ifndef Q_OS_MAC
+#include "widgets/persistentmenu.h"
+#endif
+
class VideoEncoder;
class RenderWidget;
class ActionButton;
@@ -280,7 +284,11 @@ class MainWindow : public QMainWindow
QMenu *mPathMenu;
QMenu *mEffectsMenu;
QMenu *mSceneMenu;
+#ifndef Q_OS_MAC
+ Friction::Ui::PersistentMenu *mViewMenu;
+#else
QMenu *mViewMenu;
+#endif
QMenu *mPanelsMenu;
QMenu *mRenderMenu;
diff --git a/src/app/GUI/menu.cpp b/src/app/GUI/menu.cpp
index eb7c6efd2..48506ff25 100644
--- a/src/app/GUI/menu.cpp
+++ b/src/app/GUI/menu.cpp
@@ -333,7 +333,13 @@ void MainWindow::setupMenuBar()
});
cmdAddAction(clearRecentAct);
+#ifndef Q_OS_MAC
+ mViewMenu = new Ui::PersistentMenu(tr("View", "MenuBar"), this);
+ mViewMenu->setOnlyCheckable(true);
+ mMenuBar->addMenu(mViewMenu);
+#else
mViewMenu = mMenuBar->addMenu(tr("View", "MenuBar"));
+#endif
mObjectMenu = mMenuBar->addMenu(tr("Object", "MenuBar"));
@@ -505,7 +511,13 @@ void MainWindow::setupMenuBar()
mEffectsMenu->setEnabled(false);
setupMenuEffects();
- const auto zoomMenu = mViewMenu->addMenu(QIcon::fromTheme("zoom"), tr("Zoom","MenuBar_View"));
+#ifndef Q_OS_MAC
+ const auto zoomMenu = mViewMenu->addPersistentMenu(QIcon::fromTheme("zoom"),
+ tr("Zoom","MenuBar_View"));
+#else
+ const auto zoomMenu = mViewMenu->addMenu(QIcon::fromTheme("zoom"),
+ tr("Zoom","MenuBar_View"));
+#endif
mZoomInAction = zoomMenu->addAction(tr("Zoom In", "MenuBar_View_Zoom"));
mZoomInAction->setIcon(QIcon::fromTheme("zoom_in"));
@@ -566,8 +578,13 @@ void MainWindow::setupMenuBar()
});
cmdAddAction(mResetZoomAction);
+#ifndef Q_OS_MAC
+ const auto filteringMenu = mViewMenu->addPersistentMenu(QIcon::fromTheme("user-desktop"),
+ tr("Filtering", "MenuBar_View"));
+#else
const auto filteringMenu = mViewMenu->addMenu(QIcon::fromTheme("user-desktop"),
tr("Filtering", "MenuBar_View"));
+#endif
mNoneQuality = filteringMenu->addAction(
tr("None", "MenuBar_View_Filtering"), [this]() {
diff --git a/src/ui/CMakeLists.txt b/src/ui/CMakeLists.txt
index 50a00572f..c35a3d353 100644
--- a/src/ui/CMakeLists.txt
+++ b/src/ui/CMakeLists.txt
@@ -171,6 +171,7 @@ set(
widgets/labeledslider.h
widgets/markereditor.h
widgets/performancesettingswidget.h
+ widgets/persistentmenu.h
widgets/presetsettingswidget.h
widgets/qdoubleslider.h
widgets/qrealanimatorvalueslider.h
diff --git a/src/ui/widgets/persistentmenu.h b/src/ui/widgets/persistentmenu.h
new file mode 100644
index 000000000..72e79ffe2
--- /dev/null
+++ b/src/ui/widgets/persistentmenu.h
@@ -0,0 +1,79 @@
+/*
+#
+# Friction - https://friction.graphics
+#
+# Copyright (c) Ole-André Rodlie and contributors
+#
+# 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, version 3.
+#
+# 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 .
+#
+# See 'README.md' for more information.
+#
+*/
+
+#ifndef FRICTION_PERSISTENTMENU_H
+#define FRICTION_PERSISTENTMENU_H
+
+#include "ui_global.h"
+
+#include
+#include
+#include
+
+namespace Friction
+{
+ namespace Ui
+ {
+ class UI_EXPORT PersistentMenu : public QMenu
+ {
+ Q_OBJECT
+ public:
+ using QMenu::QMenu;
+
+ PersistentMenu* addPersistentMenu(const QIcon &icon,
+ const QString &title,
+ const bool onlyCheckable = false)
+ {
+ PersistentMenu *subMenu = new PersistentMenu(title, this);
+ subMenu->setOnlyCheckable(onlyCheckable);
+ subMenu->setIcon(icon);
+ this->addMenu(subMenu);
+ return subMenu;
+ }
+ void setOnlyCheckable(const bool checked)
+ {
+ mOnlyCheckable = checked;
+ }
+
+ private:
+ bool mOnlyCheckable = false;
+
+ protected:
+ void mouseReleaseEvent(QMouseEvent *event) override
+ {
+ QAction *action = actionAt(event->pos());
+ if (action && action->menu()) {
+ QMenu::mouseReleaseEvent(event);
+ return;
+ }
+ if ((action && !mOnlyCheckable) ||
+ (action && mOnlyCheckable && action->isCheckable())) {
+ action->activate(QAction::Trigger);
+ } else {
+ QMenu::mouseReleaseEvent(event);
+ }
+ }
+ };
+ }
+}
+
+#endif // FRICTION_PERSISTENTMENU_H
diff --git a/src/ui/widgets/toolinteract.cpp b/src/ui/widgets/toolinteract.cpp
index ba9910a09..df5d26fc6 100644
--- a/src/ui/widgets/toolinteract.cpp
+++ b/src/ui/widgets/toolinteract.cpp
@@ -24,6 +24,7 @@
#include "Private/document.h"
#include "GUI/coloranimatorbutton.h"
+#include "widgets/persistentmenu.h"
#include
#include
@@ -50,7 +51,7 @@ ToolInteract::ToolInteract(QWidget *parent)
void ToolInteract::setupGizmoButton()
{
const auto button = new QToolButton(this);
- const auto menu = new QMenu(button);
+ const auto menu = new PersistentMenu(button);
button->setObjectName("ToolBoxGizmo");
button->setPopupMode(QToolButton::MenuButtonPopup);
@@ -155,7 +156,7 @@ void ToolInteract::setupSnapButton()
{
const auto grid = Document::sInstance->getGrid();
const auto button = new QToolButton(this);
- const auto menu = new QMenu(button);
+ const auto menu = new PersistentMenu(button);
button->setObjectName("ToolBoxGizmo");
button->setPopupMode(QToolButton::MenuButtonPopup);
@@ -309,7 +310,7 @@ void ToolInteract::setupGridButton()
{
const auto grid = Document::sInstance->getGrid();
const auto button = new QToolButton(this);
- const auto menu = new QMenu(button);
+ const auto menu = new PersistentMenu(button);
button->setObjectName("ToolBoxGizmo");
button->setPopupMode(QToolButton::MenuButtonPopup);
@@ -362,8 +363,8 @@ void ToolInteract::setupGridButton()
}
menu->addSeparator();
- const auto optMenu = menu->addMenu(QIcon::fromTheme("preferences"),
- tr("Settings"));
+ const auto optMenu = menu->addPersistentMenu(QIcon::fromTheme("preferences"),
+ tr("Settings"));
menu->addSeparator();
setupGridAction(button, Core::Grid::Option::SizeX);