Hide project tree by default, remove 1px menu border, darken hover/selected theme colors

This commit is contained in:
untitled
2026-02-15 08:29:59 -07:00
parent 4c6bb9564f
commit 4192a4dad3
4 changed files with 70 additions and 100 deletions

View File

@@ -161,6 +161,13 @@ public:
s = QSize(s.width() + 24, s.height() + 4); s = QSize(s.width() + 24, s.height() + 4);
return s; return s;
} }
int pixelMetric(PixelMetric metric, const QStyleOption* opt,
const QWidget* w) const override {
// Kill the 1px frame margin Fusion reserves around QMenu contents
if (metric == PM_MenuPanelWidth)
return 0;
return QProxyStyle::pixelMetric(metric, opt, w);
}
void drawPrimitive(PrimitiveElement elem, const QStyleOption* opt, void drawPrimitive(PrimitiveElement elem, const QStyleOption* opt,
QPainter* p, const QWidget* w) const override { QPainter* p, const QWidget* w) const override {
// Kill Fusion's 3D bevel on QMenu — the OS drop shadow is enough // Kill Fusion's 3D bevel on QMenu — the OS drop shadow is enough
@@ -206,7 +213,7 @@ static void applyGlobalTheme(const rcx::Theme& theme) {
QPalette pal; QPalette pal;
pal.setColor(QPalette::Window, theme.background); pal.setColor(QPalette::Window, theme.background);
pal.setColor(QPalette::WindowText, theme.text); pal.setColor(QPalette::WindowText, theme.text);
pal.setColor(QPalette::Base, theme.backgroundAlt); pal.setColor(QPalette::Base, theme.background);
pal.setColor(QPalette::AlternateBase, theme.surface); pal.setColor(QPalette::AlternateBase, theme.surface);
pal.setColor(QPalette::Text, theme.text); pal.setColor(QPalette::Text, theme.text);
pal.setColor(QPalette::Button, theme.button); pal.setColor(QPalette::Button, theme.button);
@@ -674,6 +681,7 @@ QMdiSubWindow* MainWindow::createTab(RcxDocument* doc) {
sub->setWindowTitle(rootName(it2->doc->tree, it2->ctrl->viewRootId())); sub->setWindowTitle(rootName(it2->doc->tree, it2->ctrl->viewRootId()));
} }
updateWindowTitle(); updateWindowTitle();
rebuildWorkspaceModel();
}); });
}); });
@@ -746,6 +754,25 @@ static void buildBallDemo(NodeTree& tree) {
// Material[2] materials at offset 128 (112 + 16 for float[4]) // Material[2] materials at offset 128 (112 + 16 for float[4])
{ Node n; n.kind = NodeKind::Array; n.name = "materials"; n.parentId = ballId; n.offset = 128; n.elementKind = NodeKind::Struct; n.arrayLen = 2; n.refId = matId; tree.addNode(n); } { Node n; n.kind = NodeKind::Array; n.name = "materials"; n.parentId = ballId; n.offset = 128; n.elementKind = NodeKind::Struct; n.arrayLen = 2; n.refId = matId; tree.addNode(n); }
// Unnamed struct (128 bytes of hex64 fields)
Node unnamed;
unnamed.kind = NodeKind::Struct;
unnamed.name = "instance";
unnamed.structTypeName = "Unnamed";
unnamed.parentId = 0;
unnamed.offset = 0;
int ui = tree.addNode(unnamed);
uint64_t unnamedId = tree.nodes[ui].id;
for (int i = 0; i < 16; i++) {
Node n;
n.kind = NodeKind::Hex64;
n.name = QStringLiteral("field_%1").arg(i * 8, 2, 16, QChar('0'));
n.parentId = unnamedId;
n.offset = i * 8;
tree.addNode(n);
}
} }
void MainWindow::newFile() { void MainWindow::newFile() {
@@ -794,41 +821,7 @@ void MainWindow::newDocument() {
} }
void MainWindow::selfTest() { void MainWindow::selfTest() {
// Tab 1: Ball demo
project_new(); project_new();
// Tab 2: Unnamed struct with hex64 fields
{
auto* doc = new RcxDocument(this);
QByteArray data(256, '\0');
doc->loadData(data);
doc->tree.baseAddress = 0x00400000;
Node s;
s.kind = NodeKind::Struct;
s.name = "instance";
s.structTypeName = "Unnamed";
s.parentId = 0;
s.offset = 0;
int si = doc->tree.addNode(s);
uint64_t sId = doc->tree.nodes[si].id;
for (int i = 0; i < 16; i++) {
Node n;
n.kind = NodeKind::Hex64;
n.name = QStringLiteral("field_%1").arg(i * 8, 2, 16, QChar('0'));
n.parentId = sId;
n.offset = i * 8;
doc->tree.addNode(n);
}
createTab(doc);
rebuildWorkspaceModel();
}
// Focus Ball tab
if (auto* first = m_mdiArea->subWindowList().value(0))
m_mdiArea->setActiveSubWindow(first);
} }
void MainWindow::openFile() { void MainWindow::openFile() {
@@ -1014,6 +1007,13 @@ void MainWindow::applyTheme(const Theme& theme) {
statusBar()->setPalette(sbPal); statusBar()->setPalette(sbPal);
} }
// Workspace tree: text color matches menu bar
if (m_workspaceTree) {
QPalette tp = m_workspaceTree->palette();
tp.setColor(QPalette::Text, theme.textDim);
m_workspaceTree->setPalette(tp);
}
// Split pane tab widgets // Split pane tab widgets
for (auto& state : m_tabs) { for (auto& state : m_tabs) {
for (auto& pane : state.panes) { for (auto& pane : state.panes) {
@@ -1422,7 +1422,7 @@ void MainWindow::project_close(QMdiSubWindow* sub) {
// ── Workspace Dock ── // ── Workspace Dock ──
void MainWindow::createWorkspaceDock() { void MainWindow::createWorkspaceDock() {
m_workspaceDock = new QDockWidget("Workspace", this); m_workspaceDock = new QDockWidget("Project Tree", this);
m_workspaceDock->setObjectName("WorkspaceDock"); m_workspaceDock->setObjectName("WorkspaceDock");
m_workspaceDock->setAllowedAreas(Qt::LeftDockWidgetArea | Qt::RightDockWidgetArea); m_workspaceDock->setAllowedAreas(Qt::LeftDockWidgetArea | Qt::RightDockWidgetArea);
@@ -1432,81 +1432,51 @@ void MainWindow::createWorkspaceDock() {
m_workspaceTree->setModel(m_workspaceModel); m_workspaceTree->setModel(m_workspaceModel);
m_workspaceTree->setHeaderHidden(true); m_workspaceTree->setHeaderHidden(true);
m_workspaceTree->setEditTriggers(QAbstractItemView::NoEditTriggers); m_workspaceTree->setEditTriggers(QAbstractItemView::NoEditTriggers);
m_workspaceTree->setExpandsOnDoubleClick(false);
// Match editor font m_workspaceTree->setMouseTracking(true);
{
QSettings settings("Reclass", "Reclass");
QString fontName = settings.value("font", "JetBrains Mono").toString();
QFont f(fontName, 12);
f.setFixedPitch(true);
m_workspaceTree->setFont(f);
}
m_workspaceDock->setWidget(m_workspaceTree); m_workspaceDock->setWidget(m_workspaceTree);
addDockWidget(Qt::LeftDockWidgetArea, m_workspaceDock); addDockWidget(Qt::LeftDockWidgetArea, m_workspaceDock);
m_workspaceDock->hide(); m_workspaceDock->hide();
connect(m_workspaceTree, &QTreeView::doubleClicked, this, [this](const QModelIndex& index) { connect(m_workspaceTree, &QTreeView::doubleClicked, this, [this](const QModelIndex& index) {
// Data roles: UserRole=QMdiSubWindow*, UserRole+1=structId, UserRole+2=nodeId auto structIdVar = index.data(Qt::UserRole + 1);
uint64_t structId = structIdVar.isValid() ? structIdVar.toULongLong() : 0;
if (structId == rcx::kGroupSentinel) {
// "Project" folder: toggle expand/collapse
m_workspaceTree->setExpanded(index, !m_workspaceTree->isExpanded(index));
return;
}
auto subVar = index.data(Qt::UserRole); auto subVar = index.data(Qt::UserRole);
if (!subVar.isValid()) return; if (!subVar.isValid()) return;
auto* sub = static_cast<QMdiSubWindow*>(subVar.value<void*>()); auto* sub = static_cast<QMdiSubWindow*>(subVar.value<void*>());
if (!sub || !m_tabs.contains(sub)) return; if (!sub || !m_tabs.contains(sub)) return;
m_mdiArea->setActiveSubWindow(sub); m_mdiArea->setActiveSubWindow(sub);
auto structIdVar = index.data(Qt::UserRole + 1); // Type/Enum node: navigate to it
auto nodeIdVar = index.data(Qt::UserRole + 2); auto& tree = m_tabs[sub].doc->tree;
int ni = tree.indexOfId(structId);
if (structIdVar.isValid()) { if (ni >= 0) tree.nodes[ni].collapsed = false;
// Double-clicked a struct: set as view root m_tabs[sub].ctrl->setViewRootId(structId);
uint64_t structId = structIdVar.toULongLong(); m_tabs[sub].ctrl->scrollToNodeId(structId);
auto& tree = m_tabs[sub].doc->tree;
int ni = tree.indexOfId(structId);
if (ni >= 0) tree.nodes[ni].collapsed = false;
m_tabs[sub].ctrl->setViewRootId(structId);
m_tabs[sub].ctrl->scrollToNodeId(structId);
} else if (nodeIdVar.isValid()) {
// Double-clicked a field: find its root struct, set as view root, scroll to field
uint64_t nodeId = nodeIdVar.toULongLong();
auto& tree = m_tabs[sub].doc->tree;
// Walk up to find root struct
uint64_t rootId = 0;
uint64_t cur = nodeId;
while (cur != 0) {
int idx = tree.indexOfId(cur);
if (idx < 0) break;
if (tree.nodes[idx].parentId == 0) { rootId = cur; break; }
cur = tree.nodes[idx].parentId;
}
if (rootId != 0) {
int ri = tree.indexOfId(rootId);
if (ri >= 0) tree.nodes[ri].collapsed = false;
m_tabs[sub].ctrl->setViewRootId(rootId);
}
m_tabs[sub].ctrl->scrollToNodeId(nodeId);
} else if (!index.parent().isValid()) {
// Double-clicked project root: clear view root to show all
m_tabs[sub].ctrl->setViewRootId(0);
}
}); });
} }
void MainWindow::rebuildWorkspaceModel() { void MainWindow::rebuildWorkspaceModel() {
m_workspaceModel->clear(); QVector<rcx::TabInfo> tabs;
for (auto it = m_tabs.begin(); it != m_tabs.end(); ++it) {
auto* sub = m_mdiArea->activeSubWindow(); TabState& tab = it.value();
if (!sub || !m_tabs.contains(sub)) return; QString name = tab.doc->filePath.isEmpty()
? rootName(tab.doc->tree, tab.ctrl->viewRootId())
TabState& tab = m_tabs[sub]; : QFileInfo(tab.doc->filePath).fileName();
QString tabName = tab.doc->filePath.isEmpty() tabs.append({ &tab.doc->tree, name, static_cast<void*>(it.key()) });
? rootName(tab.doc->tree, tab.ctrl->viewRootId()) }
: QFileInfo(tab.doc->filePath).fileName(); rcx::buildProjectExplorer(m_workspaceModel, tabs);
m_workspaceTree->expandToDepth(1);
buildWorkspaceModel(m_workspaceModel, tab.doc->tree, tabName,
static_cast<void*>(sub));
m_workspaceTree->expandAll();
} }
void MainWindow::showPluginsDialog() { void MainWindow::showPluginsDialog() {

View File

@@ -10,8 +10,8 @@
"textDim": "#858585", "textDim": "#858585",
"textMuted": "#585858", "textMuted": "#585858",
"textFaint": "#505050", "textFaint": "#505050",
"hover": "#2b2b2b", "hover": "#1e1e1e",
"selected": "#232323", "selected": "#1e1e1e",
"selection": "#2b2b2b", "selection": "#2b2b2b",
"syntaxKeyword": "#569cd6", "syntaxKeyword": "#569cd6",
"syntaxNumber": "#b5cea8", "syntaxNumber": "#b5cea8",

View File

@@ -10,8 +10,8 @@
"textDim": "#858585", "textDim": "#858585",
"textMuted": "#636369", "textMuted": "#636369",
"textFaint": "#4d4d55", "textFaint": "#4d4d55",
"hover": "#3e3e42", "hover": "#2c2c2f",
"selected": "#2d2d30", "selected": "#262629",
"selection": "#264f78", "selection": "#264f78",
"syntaxKeyword": "#569cd6", "syntaxKeyword": "#569cd6",
"syntaxNumber": "#b5cea8", "syntaxNumber": "#b5cea8",

View File

@@ -10,8 +10,8 @@
"textDim": "#7a7a6e", "textDim": "#7a7a6e",
"textMuted": "#555550", "textMuted": "#555550",
"textFaint": "#464646", "textFaint": "#464646",
"hover": "#373737", "hover": "#282828",
"selected": "#2d2d2d", "selected": "#262626",
"selection": "#21213A", "selection": "#21213A",
"syntaxKeyword": "#AA9565", "syntaxKeyword": "#AA9565",
"syntaxNumber": "#AAA98C", "syntaxNumber": "#AAA98C",