mirror of
https://github.com/NohamR/Reclass.git
synced 2026-05-10 19:59:21 +00:00
Hide project tree by default, remove 1px menu border, darken hover/selected theme colors
This commit is contained in:
158
src/main.cpp
158
src/main.cpp
@@ -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() {
|
||||||
|
|||||||
@@ -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",
|
||||||
|
|||||||
@@ -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",
|
||||||
|
|||||||
@@ -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",
|
||||||
|
|||||||
Reference in New Issue
Block a user