mirror of
https://github.com/NohamR/Reclass.git
synced 2026-05-10 19:59:21 +00:00
fix: sidebar dock tabs get functional close buttons when tabified
When Project and Modules docks are tabified together, Qt creates a tab bar with close buttons via setupDockTabBars(). The dock lookup only searched m_docDocks, so sidebar dock close buttons were installed but never connected — clicking × did nothing. Now the lookup also checks m_workspaceDock, m_scannerDock, and m_symbolsDock. Middle-click close and right-click context menu also work for sidebar tabs. Sidebar tabs get a minimal context menu (Close + Float/Dock) while doc tabs keep the full menu.
This commit is contained in:
192
src/main.cpp
192
src/main.cpp
@@ -2112,6 +2112,15 @@ void MainWindow::setupDockTabBars() {
|
|||||||
tabBar->setTabVisible(i, false);
|
tabBar->setTabVisible(i, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Helper: find any dock widget by title (doc tabs + sidebar docks)
|
||||||
|
auto findDockByTitle = [this](const QString& title) -> QDockWidget* {
|
||||||
|
for (auto* d : m_docDocks)
|
||||||
|
if (d->windowTitle() == title) return d;
|
||||||
|
for (auto* d : {m_workspaceDock, m_scannerDock, m_symbolsDock})
|
||||||
|
if (d && d->windowTitle() == title) return d;
|
||||||
|
return nullptr;
|
||||||
|
};
|
||||||
|
|
||||||
// Install tab buttons for any tab that doesn't have them yet
|
// Install tab buttons for any tab that doesn't have them yet
|
||||||
for (int i = 0; i < tabBar->count(); ++i) {
|
for (int i = 0; i < tabBar->count(); ++i) {
|
||||||
if (tabBar->tabText(i) == sentinelTitle)
|
if (tabBar->tabText(i) == sentinelTitle)
|
||||||
@@ -2123,12 +2132,8 @@ void MainWindow::setupDockTabBars() {
|
|||||||
auto* btns = new DockTabButtons(tabBar);
|
auto* btns = new DockTabButtons(tabBar);
|
||||||
btns->applyTheme(theme.hover);
|
btns->applyTheme(theme.hover);
|
||||||
|
|
||||||
// Find dock by matching tab title
|
// Find dock by matching tab title (doc tabs + sidebar docks)
|
||||||
QString title = tabBar->tabText(i);
|
QDockWidget* target = findDockByTitle(tabBar->tabText(i));
|
||||||
QDockWidget* target = nullptr;
|
|
||||||
for (auto* d : m_docDocks) {
|
|
||||||
if (d->windowTitle() == title) { target = d; break; }
|
|
||||||
}
|
|
||||||
if (target) {
|
if (target) {
|
||||||
connect(btns->closeBtn, &QToolButton::clicked,
|
connect(btns->closeBtn, &QToolButton::clicked,
|
||||||
target, &QDockWidget::close);
|
target, &QDockWidget::close);
|
||||||
@@ -2145,115 +2150,125 @@ void MainWindow::setupDockTabBars() {
|
|||||||
int idx = tabBar->tabAt(pos);
|
int idx = tabBar->tabAt(pos);
|
||||||
if (idx < 0) return;
|
if (idx < 0) return;
|
||||||
|
|
||||||
// Find target dock
|
// Find target dock (doc tabs + sidebar docks)
|
||||||
QString tabTitle = tabBar->tabText(idx);
|
QString tabTitle = tabBar->tabText(idx);
|
||||||
QDockWidget* target = nullptr;
|
QDockWidget* target = nullptr;
|
||||||
for (auto* d : m_docDocks)
|
for (auto* d : m_docDocks)
|
||||||
if (d->windowTitle() == tabTitle) { target = d; break; }
|
if (d->windowTitle() == tabTitle) { target = d; break; }
|
||||||
|
if (!target) {
|
||||||
|
for (auto* d : {m_workspaceDock, m_scannerDock, m_symbolsDock})
|
||||||
|
if (d && d->windowTitle() == tabTitle) { target = d; break; }
|
||||||
|
}
|
||||||
if (!target) return;
|
if (!target) return;
|
||||||
|
|
||||||
auto tabIt = m_tabs.find(target);
|
bool isDocDock = m_docDocks.contains(target);
|
||||||
|
|
||||||
QMenu menu;
|
QMenu menu;
|
||||||
|
|
||||||
// Close
|
// Close
|
||||||
menu.addAction(makeIcon(":/vsicons/close.svg"), "Close",
|
menu.addAction(makeIcon(":/vsicons/close.svg"), "Close",
|
||||||
QKeySequence(Qt::CTRL | Qt::Key_W),
|
|
||||||
[target]() { target->close(); });
|
[target]() { target->close(); });
|
||||||
|
|
||||||
menu.addSeparator();
|
// Doc-only actions
|
||||||
|
if (isDocDock) {
|
||||||
|
auto tabIt = m_tabs.find(target);
|
||||||
|
|
||||||
// Close All Tabs
|
menu.addSeparator();
|
||||||
menu.addAction(makeIcon(":/vsicons/close-all.svg"), "Close All Tabs",
|
|
||||||
[this]() { closeAllDocDocks(); });
|
|
||||||
|
|
||||||
// Close All But This
|
// Close All Tabs
|
||||||
if (m_docDocks.size() > 1) {
|
menu.addAction(makeIcon(":/vsicons/close-all.svg"), "Close All Tabs",
|
||||||
menu.addAction("Close All But This", [this, target]() {
|
[this]() { closeAllDocDocks(); });
|
||||||
auto docks = m_docDocks;
|
|
||||||
for (auto* d : docks)
|
// Close All But This
|
||||||
if (d != target) d->close();
|
if (m_docDocks.size() > 1) {
|
||||||
});
|
menu.addAction("Close All But This", [this, target]() {
|
||||||
|
auto docks = m_docDocks;
|
||||||
|
for (auto* d : docks)
|
||||||
|
if (d != target) d->close();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
menu.addSeparator();
|
||||||
|
|
||||||
|
// Copy Full Path / Open Containing Folder (only if saved)
|
||||||
|
if (tabIt != m_tabs.end() && !tabIt->doc->filePath.isEmpty()) {
|
||||||
|
QString path = tabIt->doc->filePath;
|
||||||
|
menu.addAction(makeIcon(":/vsicons/clippy.svg"), "Copy Full Path",
|
||||||
|
[path]() { QGuiApplication::clipboard()->setText(path); });
|
||||||
|
menu.addAction(makeIcon(":/vsicons/folder-opened.svg"),
|
||||||
|
"Open Containing Folder", [path]() {
|
||||||
|
QDesktopServices::openUrl(
|
||||||
|
QUrl::fromLocalFile(QFileInfo(path).absolutePath()));
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
menu.addSeparator();
|
menu.addSeparator();
|
||||||
|
|
||||||
// Copy Full Path / Open Containing Folder (only if saved)
|
|
||||||
if (tabIt != m_tabs.end() && !tabIt->doc->filePath.isEmpty()) {
|
|
||||||
QString path = tabIt->doc->filePath;
|
|
||||||
menu.addAction(makeIcon(":/vsicons/clippy.svg"), "Copy Full Path",
|
|
||||||
[path]() { QGuiApplication::clipboard()->setText(path); });
|
|
||||||
menu.addAction(makeIcon(":/vsicons/folder-opened.svg"),
|
|
||||||
"Open Containing Folder", [path]() {
|
|
||||||
QDesktopServices::openUrl(
|
|
||||||
QUrl::fromLocalFile(QFileInfo(path).absolutePath()));
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
// Float / Dock
|
// Float / Dock
|
||||||
menu.addAction(target->isFloating() ? "Dock" : "Float", [target]() {
|
menu.addAction(target->isFloating() ? "Dock" : "Float", [target]() {
|
||||||
target->setFloating(!target->isFloating());
|
target->setFloating(!target->isFloating());
|
||||||
});
|
});
|
||||||
|
|
||||||
menu.addSeparator();
|
// New Document Groups (doc tabs only, >1 visible tab)
|
||||||
|
if (isDocDock) {
|
||||||
|
menu.addSeparator();
|
||||||
|
|
||||||
menu.addSeparator();
|
int visibleTabs = 0;
|
||||||
|
for (int i = 0; i < tabBar->count(); ++i)
|
||||||
// New Document Groups (only if >1 visible tab — excludes sentinels)
|
if (tabBar->isTabVisible(i)) ++visibleTabs;
|
||||||
int visibleTabs = 0;
|
if (visibleTabs > 1) {
|
||||||
for (int i = 0; i < tabBar->count(); ++i)
|
menu.addAction(makeIcon(":/vsicons/split-horizontal.svg"),
|
||||||
if (tabBar->isTabVisible(i)) ++visibleTabs;
|
"New Horizontal Document Group",
|
||||||
if (visibleTabs > 1) {
|
[this, target]() {
|
||||||
menu.addAction(makeIcon(":/vsicons/split-horizontal.svg"),
|
Qt::DockWidgetArea area = dockWidgetArea(target);
|
||||||
"New Horizontal Document Group",
|
if (area == Qt::NoDockWidgetArea) area = Qt::TopDockWidgetArea;
|
||||||
[this, target]() {
|
removeDockWidget(target);
|
||||||
Qt::DockWidgetArea area = dockWidgetArea(target);
|
addDockWidget(area, target, Qt::Horizontal);
|
||||||
if (area == Qt::NoDockWidgetArea) area = Qt::TopDockWidgetArea;
|
target->show();
|
||||||
removeDockWidget(target);
|
QList<QDockWidget*> docks;
|
||||||
addDockWidget(area, target, Qt::Horizontal);
|
QList<int> sizes;
|
||||||
target->show();
|
for (auto* d : m_docDocks) {
|
||||||
QList<QDockWidget*> docks;
|
if (!d->isFloating() && d->isVisible() && dockWidgetArea(d) == area) {
|
||||||
QList<int> sizes;
|
docks.append(d);
|
||||||
for (auto* d : m_docDocks) {
|
sizes.append(width() / 2);
|
||||||
if (!d->isFloating() && d->isVisible() && dockWidgetArea(d) == area) {
|
}
|
||||||
docks.append(d);
|
|
||||||
sizes.append(width() / 2);
|
|
||||||
}
|
}
|
||||||
}
|
if (docks.size() >= 2)
|
||||||
if (docks.size() >= 2)
|
resizeDocks(docks, sizes, Qt::Horizontal);
|
||||||
resizeDocks(docks, sizes, Qt::Horizontal);
|
QTimer::singleShot(0, this, [this, target]() {
|
||||||
QTimer::singleShot(0, this, [this, target]() {
|
auto* s = createSentinelDock();
|
||||||
auto* s = createSentinelDock();
|
tabifyDockWidget(target, s);
|
||||||
tabifyDockWidget(target, s);
|
target->raise();
|
||||||
target->raise();
|
QTimer::singleShot(0, this, [this]() { setupDockTabBars(); });
|
||||||
QTimer::singleShot(0, this, [this]() { setupDockTabBars(); });
|
});
|
||||||
});
|
});
|
||||||
});
|
menu.addAction(makeIcon(":/vsicons/split-vertical.svg"),
|
||||||
menu.addAction(makeIcon(":/vsicons/split-vertical.svg"),
|
"New Vertical Document Group",
|
||||||
"New Vertical Document Group",
|
[this, target]() {
|
||||||
[this, target]() {
|
Qt::DockWidgetArea area = dockWidgetArea(target);
|
||||||
Qt::DockWidgetArea area = dockWidgetArea(target);
|
if (area == Qt::NoDockWidgetArea) area = Qt::TopDockWidgetArea;
|
||||||
if (area == Qt::NoDockWidgetArea) area = Qt::TopDockWidgetArea;
|
removeDockWidget(target);
|
||||||
removeDockWidget(target);
|
addDockWidget(area, target, Qt::Vertical);
|
||||||
addDockWidget(area, target, Qt::Vertical);
|
target->show();
|
||||||
target->show();
|
QList<QDockWidget*> docks;
|
||||||
QList<QDockWidget*> docks;
|
QList<int> sizes;
|
||||||
QList<int> sizes;
|
for (auto* d : m_docDocks) {
|
||||||
for (auto* d : m_docDocks) {
|
if (!d->isFloating() && d->isVisible() && dockWidgetArea(d) == area) {
|
||||||
if (!d->isFloating() && d->isVisible() && dockWidgetArea(d) == area) {
|
docks.append(d);
|
||||||
docks.append(d);
|
sizes.append(height() / 2);
|
||||||
sizes.append(height() / 2);
|
}
|
||||||
}
|
}
|
||||||
}
|
if (docks.size() >= 2)
|
||||||
if (docks.size() >= 2)
|
resizeDocks(docks, sizes, Qt::Vertical);
|
||||||
resizeDocks(docks, sizes, Qt::Vertical);
|
QTimer::singleShot(0, this, [this, target]() {
|
||||||
QTimer::singleShot(0, this, [this, target]() {
|
auto* s = createSentinelDock();
|
||||||
auto* s = createSentinelDock();
|
tabifyDockWidget(target, s);
|
||||||
tabifyDockWidget(target, s);
|
target->raise();
|
||||||
target->raise();
|
QTimer::singleShot(0, this, [this]() { setupDockTabBars(); });
|
||||||
QTimer::singleShot(0, this, [this]() { setupDockTabBars(); });
|
});
|
||||||
});
|
});
|
||||||
});
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
menu.exec(tabBar->mapToGlobal(pos));
|
menu.exec(tabBar->mapToGlobal(pos));
|
||||||
@@ -2270,7 +2285,10 @@ bool MainWindow::eventFilter(QObject* obj, QEvent* event) {
|
|||||||
if (idx >= 0) {
|
if (idx >= 0) {
|
||||||
QString title = tabBar->tabText(idx);
|
QString title = tabBar->tabText(idx);
|
||||||
for (auto* d : m_docDocks) {
|
for (auto* d : m_docDocks) {
|
||||||
if (d->windowTitle() == title) { d->close(); break; }
|
if (d->windowTitle() == title) { d->close(); return true; }
|
||||||
|
}
|
||||||
|
for (auto* d : {m_workspaceDock, m_scannerDock, m_symbolsDock}) {
|
||||||
|
if (d && d->windowTitle() == title) { d->close(); return true; }
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user