mirror of
https://github.com/NohamR/Reclass.git
synced 2026-05-10 19:59:21 +00:00
fix: Linux menu bar renders as horizontal tool buttons instead of collapsed extension popup
On Linux, QMenuBar inside a custom title bar widget (setMenuWidget) collapses all items into the extension overflow popup. Replace with QToolButton widgets on Linux that share the same QMenu objects. Includes hover-to-switch behavior via event filter on open menus. Windows and macOS paths are unchanged — guarded by #ifdef __linux__ and runtime m_useToolButtons flag.
This commit is contained in:
@@ -615,6 +615,7 @@ MainWindow::MainWindow(QWidget* parent) : QMainWindow(parent) {
|
|||||||
createSymbolsDock();
|
createSymbolsDock();
|
||||||
|
|
||||||
createMenus();
|
createMenus();
|
||||||
|
if (m_titleBar) m_titleBar->finalizeMenuBar();
|
||||||
createStatusBar();
|
createStatusBar();
|
||||||
|
|
||||||
// Eliminate gap between central widget and status bar
|
// Eliminate gap between central widget and status bar
|
||||||
|
|||||||
@@ -4,6 +4,7 @@
|
|||||||
#include <QMouseEvent>
|
#include <QMouseEvent>
|
||||||
#include <QPainter>
|
#include <QPainter>
|
||||||
#include <QStyle>
|
#include <QStyle>
|
||||||
|
#include <QTimer>
|
||||||
#include <QWindow>
|
#include <QWindow>
|
||||||
|
|
||||||
namespace rcx {
|
namespace rcx {
|
||||||
@@ -25,11 +26,23 @@ TitleBarWidget::TitleBarWidget(QWidget* parent)
|
|||||||
m_appLabel->setAttribute(Qt::WA_TransparentForMouseEvents);
|
m_appLabel->setAttribute(Qt::WA_TransparentForMouseEvents);
|
||||||
layout->addWidget(m_appLabel);
|
layout->addWidget(m_appLabel);
|
||||||
|
|
||||||
// Menu bar
|
// Menu bar — hidden on Linux; visible on Windows.
|
||||||
|
// On Linux, QMenuBar inside a custom widget collapses all items into an
|
||||||
|
// extension popup. We keep it hidden and mirror its menus as QToolButtons
|
||||||
|
// via finalizeMenuBar() after createMenus() populates it.
|
||||||
m_menuBar = new QMenuBar(this);
|
m_menuBar = new QMenuBar(this);
|
||||||
m_menuBar->setNativeMenuBar(false);
|
m_menuBar->setNativeMenuBar(false);
|
||||||
|
#ifdef __linux__
|
||||||
|
m_useToolButtons = true;
|
||||||
|
m_menuBar->hide();
|
||||||
|
m_menuBtnLayout = new QHBoxLayout;
|
||||||
|
m_menuBtnLayout->setContentsMargins(0, 0, 0, 0);
|
||||||
|
m_menuBtnLayout->setSpacing(0);
|
||||||
|
layout->addLayout(m_menuBtnLayout);
|
||||||
|
#else
|
||||||
m_menuBar->setSizePolicy(QSizePolicy::Minimum, QSizePolicy::Expanding);
|
m_menuBar->setSizePolicy(QSizePolicy::Minimum, QSizePolicy::Expanding);
|
||||||
layout->addWidget(m_menuBar);
|
layout->addWidget(m_menuBar);
|
||||||
|
#endif
|
||||||
|
|
||||||
layout->addStretch();
|
layout->addStretch();
|
||||||
|
|
||||||
@@ -116,6 +129,17 @@ void TitleBarWidget::applyTheme(const Theme& theme) {
|
|||||||
m_btnMin->setStyleSheet(btnStyle);
|
m_btnMin->setStyleSheet(btnStyle);
|
||||||
m_btnMax->setStyleSheet(btnStyle);
|
m_btnMax->setStyleSheet(btnStyle);
|
||||||
|
|
||||||
|
// Linux menu tool buttons
|
||||||
|
if (m_useToolButtons) {
|
||||||
|
QString menuBtnStyle = QStringLiteral(
|
||||||
|
"QToolButton { background: transparent; border: none; padding: 0 8px; color: %1; }"
|
||||||
|
"QToolButton:hover { background: %2; }"
|
||||||
|
"QToolButton::menu-indicator { image: none; }")
|
||||||
|
.arg(theme.text.name(), theme.hover.name());
|
||||||
|
for (auto* btn : m_menuButtons)
|
||||||
|
btn->setStyleSheet(menuBtnStyle);
|
||||||
|
}
|
||||||
|
|
||||||
// Close button: themed red hover
|
// Close button: themed red hover
|
||||||
m_btnClose->setStyleSheet(QStringLiteral(
|
m_btnClose->setStyleSheet(QStringLiteral(
|
||||||
"QToolButton { background: transparent; border: none; }"
|
"QToolButton { background: transparent; border: none; }"
|
||||||
@@ -164,6 +188,58 @@ void TitleBarWidget::setMenuBarTitleCase(bool titleCase) {
|
|||||||
action->setText("&" + result);
|
action->setText("&" + result);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
// Sync tool button labels on Linux
|
||||||
|
if (m_useToolButtons) {
|
||||||
|
auto actions = m_menuBar->actions();
|
||||||
|
for (int i = 0; i < m_menuButtons.size() && i < actions.size(); ++i)
|
||||||
|
m_menuButtons[i]->setText(actions[i]->text());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void TitleBarWidget::finalizeMenuBar() {
|
||||||
|
if (!m_useToolButtons) return;
|
||||||
|
// Create a QToolButton for each top-level menu in the hidden QMenuBar
|
||||||
|
for (auto* action : m_menuBar->actions()) {
|
||||||
|
if (!action->menu()) continue;
|
||||||
|
auto* btn = new QToolButton(this);
|
||||||
|
btn->setText(action->text());
|
||||||
|
btn->setMenu(action->menu());
|
||||||
|
btn->setPopupMode(QToolButton::InstantPopup);
|
||||||
|
btn->setAutoRaise(true);
|
||||||
|
btn->setFocusPolicy(Qt::NoFocus);
|
||||||
|
btn->setSizePolicy(QSizePolicy::Minimum, QSizePolicy::Expanding);
|
||||||
|
btn->setStyleSheet(QStringLiteral(
|
||||||
|
"QToolButton { background: transparent; border: none; padding: 0 8px; }"
|
||||||
|
"QToolButton:hover { background: %1; }"
|
||||||
|
"QToolButton::menu-indicator { image: none; }")
|
||||||
|
.arg(m_theme.hover.name()));
|
||||||
|
btn->installEventFilter(this);
|
||||||
|
btn->menu()->installEventFilter(this);
|
||||||
|
m_menuBtnLayout->addWidget(btn);
|
||||||
|
m_menuButtons.append(btn);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool TitleBarWidget::eventFilter(QObject* obj, QEvent* event) {
|
||||||
|
if (!m_useToolButtons) return QWidget::eventFilter(obj, event);
|
||||||
|
|
||||||
|
// Watch for mouse movement inside an open QMenu — if the cursor moves
|
||||||
|
// over a sibling menu button, close this menu and open the other.
|
||||||
|
if (event->type() == QEvent::MouseMove) {
|
||||||
|
auto* menu = qobject_cast<QMenu*>(obj);
|
||||||
|
if (!menu || !menu->isVisible()) return false;
|
||||||
|
QPoint globalPos = QCursor::pos();
|
||||||
|
for (auto* btn : m_menuButtons) {
|
||||||
|
if (btn->menu() == menu) continue;
|
||||||
|
QRect btnRect(btn->mapToGlobal(QPoint(0, 0)), btn->size());
|
||||||
|
if (btnRect.contains(globalPos)) {
|
||||||
|
menu->close();
|
||||||
|
QTimer::singleShot(0, btn, [btn]() { btn->showMenu(); });
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return QWidget::eventFilter(obj, event);
|
||||||
}
|
}
|
||||||
|
|
||||||
void TitleBarWidget::updateMaximizeIcon() {
|
void TitleBarWidget::updateMaximizeIcon() {
|
||||||
|
|||||||
@@ -18,6 +18,7 @@ public:
|
|||||||
void setShowIcon(bool show);
|
void setShowIcon(bool show);
|
||||||
void setMenuBarTitleCase(bool titleCase);
|
void setMenuBarTitleCase(bool titleCase);
|
||||||
bool menuBarTitleCase() const { return m_titleCase; }
|
bool menuBarTitleCase() const { return m_titleCase; }
|
||||||
|
void finalizeMenuBar();
|
||||||
|
|
||||||
void updateMaximizeIcon();
|
void updateMaximizeIcon();
|
||||||
|
|
||||||
@@ -25,16 +26,20 @@ protected:
|
|||||||
void mousePressEvent(QMouseEvent* event) override;
|
void mousePressEvent(QMouseEvent* event) override;
|
||||||
void mouseDoubleClickEvent(QMouseEvent* event) override;
|
void mouseDoubleClickEvent(QMouseEvent* event) override;
|
||||||
void paintEvent(QPaintEvent* event) override;
|
void paintEvent(QPaintEvent* event) override;
|
||||||
|
bool eventFilter(QObject* obj, QEvent* event) override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
QLabel* m_appLabel = nullptr;
|
QLabel* m_appLabel = nullptr;
|
||||||
QMenuBar* m_menuBar = nullptr;
|
QMenuBar* m_menuBar = nullptr;
|
||||||
|
QHBoxLayout* m_menuBtnLayout = nullptr;
|
||||||
|
QVector<QToolButton*> m_menuButtons;
|
||||||
QToolButton* m_btnMin = nullptr;
|
QToolButton* m_btnMin = nullptr;
|
||||||
QToolButton* m_btnMax = nullptr;
|
QToolButton* m_btnMax = nullptr;
|
||||||
QToolButton* m_btnClose = nullptr;
|
QToolButton* m_btnClose = nullptr;
|
||||||
|
|
||||||
Theme m_theme;
|
Theme m_theme;
|
||||||
bool m_titleCase = false;
|
bool m_titleCase = false;
|
||||||
|
bool m_useToolButtons = false;
|
||||||
|
|
||||||
QToolButton* makeChromeButton(const QString& iconPath);
|
QToolButton* makeChromeButton(const QString& iconPath);
|
||||||
void toggleMaximize();
|
void toggleMaximize();
|
||||||
|
|||||||
Reference in New Issue
Block a user