Replace Iosevka with JetBrains Mono, fix scrollbar and inline edit UX

- Replace embedded Iosevka font with JetBrains Mono as default font
- Fix wide horizontal scrollbar by enabling SCI_SETSCROLLWIDTHTRACKING
- Remove 28-char trailing whitespace padding from all lines
- Fix arrow keys not collapsing selection in inline edit mode
- Dim struct/array braces ({ and };) to match hex node styling
- Resize margin immediately on font change
This commit is contained in:
IChooseYou
2026-02-10 06:00:17 -07:00
committed by sysadmin
parent 276dcae444
commit 1d6fddb51e
12 changed files with 131 additions and 39 deletions

View File

@@ -18,6 +18,7 @@ struct ComposeState {
int currentLine = 0; int currentLine = 0;
int typeW = kColType; // global type column width (fallback) int typeW = kColType; // global type column width (fallback)
int nameW = kColName; // global name column width (fallback) int nameW = kColName; // global name column width (fallback)
int offsetHexDigits = 8; // hex digit tier for offset margin
bool baseEmitted = false; // only first root struct shows base address bool baseEmitted = false; // only first root struct shows base address
// Precomputed for O(1) lookups // Precomputed for O(1) lookups
@@ -144,7 +145,7 @@ void composeLeaf(ComposeState& state, const NodeTree& tree,
lm.isContinuation = isCont; lm.isContinuation = isCont;
lm.lineKind = isCont ? LineKind::Continuation : LineKind::Field; lm.lineKind = isCont ? LineKind::Continuation : LineKind::Field;
lm.nodeKind = node.kind; lm.nodeKind = node.kind;
lm.offsetText = fmt::fmtOffsetMargin(tree.baseAddress + absAddr, isCont); lm.offsetText = fmt::fmtOffsetMargin(tree.baseAddress + absAddr, isCont, state.offsetHexDigits);
lm.markerMask = computeMarkers(node, prov, absAddr, isCont, depth); lm.markerMask = computeMarkers(node, prov, absAddr, isCont, depth);
lm.foldLevel = computeFoldLevel(depth, false); lm.foldLevel = computeFoldLevel(depth, false);
lm.effectiveTypeW = typeW; lm.effectiveTypeW = typeW;
@@ -191,7 +192,7 @@ void composeParent(ComposeState& state, const NodeTree& tree,
lm.nodeId = node.id; lm.nodeId = node.id;
lm.depth = depth; lm.depth = depth;
lm.lineKind = LineKind::Field; lm.lineKind = LineKind::Field;
lm.offsetText = fmt::fmtOffsetMargin(tree.baseAddress + absAddr, false); lm.offsetText = fmt::fmtOffsetMargin(tree.baseAddress + absAddr, false, state.offsetHexDigits);
lm.nodeKind = node.kind; lm.nodeKind = node.kind;
lm.markerMask = (1u << M_CYCLE) | (1u << M_ERR); lm.markerMask = (1u << M_CYCLE) | (1u << M_ERR);
lm.foldLevel = computeFoldLevel(depth, false); lm.foldLevel = computeFoldLevel(depth, false);
@@ -208,7 +209,7 @@ void composeParent(ComposeState& state, const NodeTree& tree,
lm.nodeId = node.id; lm.nodeId = node.id;
lm.depth = depth; lm.depth = depth;
lm.lineKind = LineKind::ArrayElementSeparator; lm.lineKind = LineKind::ArrayElementSeparator;
lm.offsetText = fmt::fmtOffsetMargin(tree.baseAddress + absAddr, false); lm.offsetText = fmt::fmtOffsetMargin(tree.baseAddress + absAddr, false, state.offsetHexDigits);
lm.nodeKind = node.kind; lm.nodeKind = node.kind;
lm.foldLevel = computeFoldLevel(depth, false); lm.foldLevel = computeFoldLevel(depth, false);
lm.markerMask = 0; lm.markerMask = 0;
@@ -234,7 +235,7 @@ void composeParent(ComposeState& state, const NodeTree& tree,
lm.nodeId = node.id; lm.nodeId = node.id;
lm.depth = depth; lm.depth = depth;
lm.lineKind = LineKind::Header; lm.lineKind = LineKind::Header;
lm.offsetText = fmt::fmtOffsetMargin(tree.baseAddress + absAddr, false); lm.offsetText = fmt::fmtOffsetMargin(tree.baseAddress + absAddr, false, state.offsetHexDigits);
lm.nodeKind = node.kind; lm.nodeKind = node.kind;
lm.isRootHeader = false; lm.isRootHeader = false;
lm.foldHead = true; lm.foldHead = true;
@@ -288,10 +289,10 @@ void composeParent(ComposeState& state, const NodeTree& tree,
lm.lineKind = LineKind::Footer; lm.lineKind = LineKind::Footer;
lm.nodeKind = node.kind; lm.nodeKind = node.kind;
lm.isRootHeader = isRootHeader; // root footer: flush left (no fold prefix) lm.isRootHeader = isRootHeader; // root footer: flush left (no fold prefix)
lm.offsetText.clear();
lm.foldLevel = computeFoldLevel(depth, false); lm.foldLevel = computeFoldLevel(depth, false);
lm.markerMask = 0; lm.markerMask = 0;
int sz = tree.structSpan(node.id, &state.childMap); int sz = tree.structSpan(node.id, &state.childMap);
lm.offsetText = fmt::fmtOffsetMargin(tree.baseAddress + absAddr + sz, false, state.offsetHexDigits);
state.emitLine(fmt::fmtStructFooter(node, depth, sz), lm); state.emitLine(fmt::fmtStructFooter(node, depth, sz), lm);
} }
@@ -322,7 +323,7 @@ void composeNode(ComposeState& state, const NodeTree& tree,
lm.nodeId = node.id; lm.nodeId = node.id;
lm.depth = depth; lm.depth = depth;
lm.lineKind = node.collapsed ? LineKind::Field : LineKind::Header; lm.lineKind = node.collapsed ? LineKind::Field : LineKind::Header;
lm.offsetText = fmt::fmtOffsetMargin(tree.baseAddress + absAddr, false); lm.offsetText = fmt::fmtOffsetMargin(tree.baseAddress + absAddr, false, state.offsetHexDigits);
lm.nodeKind = node.kind; lm.nodeKind = node.kind;
lm.foldHead = true; lm.foldHead = true;
lm.foldCollapsed = node.collapsed; lm.foldCollapsed = node.collapsed;
@@ -411,6 +412,19 @@ ComposeResult compose(const NodeTree& tree, const Provider& prov, uint64_t viewR
for (int i = 0; i < tree.nodes.size(); i++) for (int i = 0; i < tree.nodes.size(); i++)
state.absOffsets[i] = tree.computeOffset(i); state.absOffsets[i] = tree.computeOffset(i);
// Compute hex digit tier from max absolute address
{
uint64_t maxAddr = tree.baseAddress;
for (int i = 0; i < tree.nodes.size(); i++) {
uint64_t addr = tree.baseAddress + (uint64_t)state.absOffsets[i];
if (addr > maxAddr) maxAddr = addr;
}
if (maxAddr <= 0xFFFFULL) state.offsetHexDigits = 4;
else if (maxAddr <= 0xFFFFFFFFULL) state.offsetHexDigits = 8;
else if (maxAddr <= 0xFFFFFFFFFFFFULL) state.offsetHexDigits = 12;
else state.offsetHexDigits = 16;
}
// Helper: compute the display type string for a node (for width calculation) // Helper: compute the display type string for a node (for width calculation)
auto nodeTypeName = [&](const Node& n) -> QString { auto nodeTypeName = [&](const Node& n) -> QString {
if (n.kind == NodeKind::Array) if (n.kind == NodeKind::Array)
@@ -491,7 +505,7 @@ ComposeResult compose(const NodeTree& tree, const Provider& prov, uint64_t viewR
lm.lineKind = LineKind::CommandRow; lm.lineKind = LineKind::CommandRow;
lm.foldLevel = SC_FOLDLEVELBASE; lm.foldLevel = SC_FOLDLEVELBASE;
lm.foldHead = false; lm.foldHead = false;
lm.offsetText = fmt::fmtOffsetMargin(tree.baseAddress, false); lm.offsetText = fmt::fmtOffsetMargin(tree.baseAddress, false, state.offsetHexDigits);
lm.markerMask = 0; lm.markerMask = 0;
lm.effectiveTypeW = state.typeW; lm.effectiveTypeW = state.typeW;
lm.effectiveNameW = state.nameW; lm.effectiveNameW = state.nameW;
@@ -510,7 +524,7 @@ ComposeResult compose(const NodeTree& tree, const Provider& prov, uint64_t viewR
composeNode(state, tree, prov, idx, 0); composeNode(state, tree, prov, idx, 0);
} }
return { state.text, state.meta, LayoutInfo{state.typeW, state.nameW} }; return { state.text, state.meta, LayoutInfo{state.typeW, state.nameW, state.offsetHexDigits} };
} }
QSet<uint64_t> NodeTree::normalizePreferAncestors(const QSet<uint64_t>& ids) const { QSet<uint64_t> NodeTree::normalizePreferAncestors(const QSet<uint64_t>& ids) const {

View File

@@ -1496,7 +1496,7 @@ void RcxController::showTypeSelectorPopup(RcxEditor* editor) {
// Get font with zoom // Get font with zoom
QSettings settings("ReclassX", "ReclassX"); QSettings settings("ReclassX", "ReclassX");
QString fontName = settings.value("font", "Consolas").toString(); QString fontName = settings.value("font", "JetBrains Mono").toString();
QFont font(fontName, 12); QFont font(fontName, 12);
font.setFixedPitch(true); font.setFixedPitch(true);
auto* sci = editor->scintilla(); auto* sci = editor->scintilla();

View File

@@ -439,6 +439,7 @@ inline bool isSyntheticLine(const LineMeta& lm) {
struct LayoutInfo { struct LayoutInfo {
int typeW = 14; // Effective type column width (default = kColType) int typeW = 14; // Effective type column width (default = kColType)
int nameW = 22; // Effective name column width (default = kColName) int nameW = 22; // Effective name column width (default = kColName)
int offsetHexDigits = 8; // Hex digits for offset margin (4/8/12/16)
}; };
// ── ComposeResult ── // ── ComposeResult ──
@@ -750,7 +751,7 @@ namespace fmt {
uint64_t addr, int depth, int subLine = 0, uint64_t addr, int depth, int subLine = 0,
const QString& comment = {}, int colType = kColType, int colName = kColName, const QString& comment = {}, int colType = kColType, int colName = kColName,
const QString& typeOverride = {}); const QString& typeOverride = {});
QString fmtOffsetMargin(uint64_t absoluteOffset, bool isContinuation); QString fmtOffsetMargin(uint64_t absoluteOffset, bool isContinuation, int hexDigits = 8);
QString fmtStructHeader(const Node& node, int depth, bool collapsed, int colType = kColType, int colName = kColName); QString fmtStructHeader(const Node& node, int depth, bool collapsed, int colType = kColType, int colName = kColName);
QString fmtStructFooter(const Node& node, int depth, int totalSize = -1); QString fmtStructFooter(const Node& node, int depth, int totalSize = -1);
QString fmtArrayHeader(const Node& node, int depth, int viewIdx, bool collapsed, int colType = kColType, int colName = kColName); QString fmtArrayHeader(const Node& node, int depth, int viewIdx, bool collapsed, int colType = kColType, int colName = kColName);

View File

@@ -32,7 +32,7 @@ static constexpr int IND_DATA_CHANGED = 13; // Amber text for changed data value
static constexpr int IND_CLASS_NAME = 14; // Teal text for root class name static constexpr int IND_CLASS_NAME = 14; // Teal text for root class name
static constexpr int IND_HINT_GREEN = 15; // Green text for hint/comment text static constexpr int IND_HINT_GREEN = 15; // Green text for hint/comment text
static QString g_fontName = "Consolas"; static QString g_fontName = "JetBrains Mono";
static QFont editorFont() { static QFont editorFont() {
QFont f(g_fontName, 12); QFont f(g_fontName, 12);
@@ -139,6 +139,10 @@ void RcxEditor::setupScintilla() {
m_sci->SendScintilla(QsciScintillaBase::SCI_SETSELFORE, (long)0, (long)0); m_sci->SendScintilla(QsciScintillaBase::SCI_SETSELFORE, (long)0, (long)0);
m_sci->SendScintilla(QsciScintillaBase::SCI_SETSELBACK, (long)0, (long)0); m_sci->SendScintilla(QsciScintillaBase::SCI_SETSELBACK, (long)0, (long)0);
// Auto-size horizontal scrollbar to actual content width (default is fixed 2000px)
m_sci->SendScintilla(QsciScintillaBase::SCI_SETSCROLLWIDTHTRACKING, 1);
m_sci->SendScintilla(QsciScintillaBase::SCI_SETSCROLLWIDTH, 1);
// Editable-field indicator - HIDDEN (no visual) // Editable-field indicator - HIDDEN (no visual)
m_sci->SendScintilla(QsciScintillaBase::SCI_INDICSETSTYLE, m_sci->SendScintilla(QsciScintillaBase::SCI_INDICSETSTYLE,
IND_EDITABLE, 5 /*INDIC_HIDDEN*/); IND_EDITABLE, 5 /*INDIC_HIDDEN*/);
@@ -240,7 +244,7 @@ void RcxEditor::setupMargins() {
// Margin 0: Offset text // Margin 0: Offset text
m_sci->setMarginType(0, QsciScintilla::TextMarginRightJustified); m_sci->setMarginType(0, QsciScintilla::TextMarginRightJustified);
m_sci->setMarginWidth(0, " 0x00000000 "); m_sci->setMarginWidth(0, " 00000000 "); // default 8-digit; resized dynamically in applyDocument()
m_sci->setMarginsBackgroundColor(kBgMargin); m_sci->setMarginsBackgroundColor(kBgMargin);
m_sci->setMarginsForegroundColor(kFgMarginDim); m_sci->setMarginsForegroundColor(kFgMarginDim);
m_sci->setMarginSensitivity(0, true); m_sci->setMarginSensitivity(0, true);
@@ -346,10 +350,18 @@ void RcxEditor::applyDocument(const ComposeResult& result) {
m_meta = result.meta; m_meta = result.meta;
m_layout = result.layout; m_layout = result.layout;
// Dynamically resize margin to fit the current hex digit tier
QString marginSizer = QString(" %1 ").arg(QString(m_layout.offsetHexDigits, '0'));
m_sci->setMarginWidth(0, marginSizer);
m_sci->setReadOnly(false); m_sci->setReadOnly(false);
m_sci->setText(result.text); m_sci->setText(result.text);
m_sci->setReadOnly(true); m_sci->setReadOnly(true);
// Reset scroll width so tracking re-measures from current content
// (tracking never shrinks automatically — only grows)
m_sci->SendScintilla(QsciScintillaBase::SCI_SETSCROLLWIDTH, 1);
// Force full re-lex to fix stale syntax coloring after edits // Force full re-lex to fix stale syntax coloring after edits
m_sci->SendScintilla(QsciScintillaBase::SCI_COLOURISE, (uintptr_t)0, (long)-1); m_sci->SendScintilla(QsciScintillaBase::SCI_COLOURISE, (uintptr_t)0, (long)-1);
@@ -370,7 +382,6 @@ void RcxEditor::applyDocument(const ComposeResult& result) {
} }
void RcxEditor::applyMarginText(const QVector<LineMeta>& meta) { void RcxEditor::applyMarginText(const QVector<LineMeta>& meta) {
// Clear all margin text
m_sci->clearMarginText(-1); m_sci->clearMarginText(-1);
for (int i = 0; i < meta.size(); i++) { for (int i = 0; i < meta.size(); i++) {
@@ -450,6 +461,21 @@ void RcxEditor::applyHexDimming(const QVector<LineMeta>& meta) {
if (len > 0) if (len > 0)
m_sci->SendScintilla(QsciScintillaBase::SCI_INDICATORFILLRANGE, pos, len); m_sci->SendScintilla(QsciScintillaBase::SCI_INDICATORFILLRANGE, pos, len);
} }
// Dim struct/array braces: entire footer line, trailing "{" on headers
if (meta[i].lineKind == LineKind::Footer) {
long pos, len; lineRangeNoEol(m_sci, i, pos, len);
if (len > 0)
m_sci->SendScintilla(QsciScintillaBase::SCI_INDICATORFILLRANGE, pos, len);
} else if (meta[i].lineKind == LineKind::Header) {
long endPos = m_sci->SendScintilla(QsciScintillaBase::SCI_GETLINEENDPOSITION, (unsigned long)i);
for (long p = endPos - 1; p >= 0; --p) {
int ch = (int)m_sci->SendScintilla(QsciScintillaBase::SCI_GETCHARAT, (unsigned long)p);
if (ch == ' ' || ch == '\t') continue;
if (ch == '{')
m_sci->SendScintilla(QsciScintillaBase::SCI_INDICATORFILLRANGE, p, 1);
break;
}
}
} }
} }
@@ -1351,12 +1377,30 @@ bool RcxEditor::handleEditKey(QKeyEvent* ke) {
if (lineText.mid(m_editState.spanStart, 2).startsWith(QStringLiteral("0x"), Qt::CaseInsensitive)) if (lineText.mid(m_editState.spanStart, 2).startsWith(QStringLiteral("0x"), Qt::CaseInsensitive))
minCol = m_editState.spanStart + 2; minCol = m_editState.spanStart + 2;
} }
// If there's an active selection, collapse it to the left end (Left only, not Backspace)
if (ke->key() == Qt::Key_Left) {
int sL, sC, eL, eC;
m_sci->getSelection(&sL, &sC, &eL, &eC);
if (sL >= 0 && (sL != eL || sC != eC)) {
int leftEnd = qMax(qMin(sC, eC), minCol);
m_sci->setCursorPosition(m_editState.line, leftEnd);
return true;
}
}
if (col <= minCol) return true; if (col <= minCol) return true;
return false; return false;
} }
case Qt::Key_Right: { case Qt::Key_Right: {
int line, col; int line, col;
m_sci->getCursorPosition(&line, &col); m_sci->getCursorPosition(&line, &col);
// If there's an active selection, collapse it to the right end first
int sL, sC, eL, eC;
m_sci->getSelection(&sL, &sC, &eL, &eC);
if (sL >= 0 && (sL != eL || sC != eC)) {
int rightEnd = qMin(qMax(sC, eC), editEndCol());
m_sci->setCursorPosition(m_editState.line, rightEnd);
return true;
}
if (col >= editEndCol()) return true; // block past end if (col >= editEndCol()) return true; // block past end
return false; return false;
} }
@@ -1468,8 +1512,9 @@ bool RcxEditor::beginInlineEdit(EditTarget target, int line) {
m_editState.editKind = NodeKind::Float; m_editState.editKind = NodeKind::Float;
// Store fixed comment column position for value editing // Store fixed comment column position for value editing
// Use large lineLength so commentCol is always computed (padding added dynamically)
if (target == EditTarget::Value) { if (target == EditTarget::Value) {
ColumnSpan cs = commentSpanFor(*lm, lineText.size(), lm->effectiveTypeW, lm->effectiveNameW); ColumnSpan cs = commentSpanFor(*lm, 9999, lm->effectiveTypeW, lm->effectiveNameW);
m_editState.commentCol = cs.valid ? cs.start : -1; m_editState.commentCol = cs.valid ? cs.start : -1;
m_editState.lastValidationOk = true; // original value is always valid m_editState.lastValidationOk = true; // original value is always valid
} else { } else {
@@ -1480,6 +1525,26 @@ bool RcxEditor::beginInlineEdit(EditTarget target, int line) {
m_sci->SendScintilla(QsciScintillaBase::SCI_SETUNDOCOLLECTION, (long)0); m_sci->SendScintilla(QsciScintillaBase::SCI_SETUNDOCOLLECTION, (long)0);
m_sci->SendScintilla(QsciScintillaBase::SCI_SETCARETWIDTH, 1); m_sci->SendScintilla(QsciScintillaBase::SCI_SETCARETWIDTH, 1);
m_sci->setReadOnly(false); m_sci->setReadOnly(false);
// For value editing: extend line with trailing spaces for the edit comment area
// (comment padding is no longer baked into every line to avoid unnecessary scroll width)
if (target == EditTarget::Value && m_editState.commentCol >= 0) {
int commentStart = norm.end + 2;
int neededLen = commentStart + kColComment;
int currentLen = (int)lineText.size();
if (currentLen < neededLen) {
int extend = neededLen - currentLen;
long lineEndPos = posFromCol(m_sci, line, currentLen);
QString pad(extend, ' ');
QByteArray padUtf8 = pad.toUtf8();
m_sci->SendScintilla(QsciScintillaBase::SCI_SETTARGETSTART, lineEndPos);
m_sci->SendScintilla(QsciScintillaBase::SCI_SETTARGETEND, lineEndPos);
m_sci->SendScintilla(QsciScintillaBase::SCI_REPLACETARGET,
(uintptr_t)padUtf8.size(), padUtf8.constData());
m_editState.linelenAfterReplace += extend;
}
}
// Switch to I-beam for editing (skip for picker-based targets) // Switch to I-beam for editing (skip for picker-based targets)
if (target != EditTarget::Type && target != EditTarget::Source if (target != EditTarget::Type && target != EditTarget::Source
&& target != EditTarget::ArrayElementType && target != EditTarget::PointerTarget && target != EditTarget::ArrayElementType && target != EditTarget::PointerTarget
@@ -2079,8 +2144,10 @@ void RcxEditor::setEditorFont(const QString& fontName) {
m_lexer->setFont(f, i); m_lexer->setFont(f, i);
m_sci->setMarginsFont(f); m_sci->setMarginsFont(f);
// Re-apply margin styles with new font // Re-apply margin styles and width with new font metrics
allocateMarginStyles(); allocateMarginStyles();
QString marginSizer = QString(" %1 ").arg(QString(m_layout.offsetHexDigits, '0'));
m_sci->setMarginWidth(0, marginSizer);
} }
void RcxEditor::setGlobalFontName(const QString& fontName) { void RcxEditor::setGlobalFontName(const QString& fontName) {

Binary file not shown.

BIN
src/fonts/JetBrainsMono.ttf Normal file

Binary file not shown.

View File

@@ -111,9 +111,10 @@ QString indent(int depth) {
// ── Offset margin ── // ── Offset margin ──
QString fmtOffsetMargin(uint64_t absoluteOffset, bool isContinuation) { QString fmtOffsetMargin(uint64_t absoluteOffset, bool isContinuation, int hexDigits) {
if (isContinuation) return QStringLiteral(" \u00B7 "); if (isContinuation) return QStringLiteral(" \u00B7 ");
return QString::number(absoluteOffset, 16).toUpper() + QChar(' '); return QString::number(absoluteOffset, 16).toUpper()
.rightJustified(hexDigits, '0') + QChar(' ');
} }
// ── Struct type name (for width calculation) ── // ── Struct type name (for width calculation) ──
@@ -313,8 +314,8 @@ QString fmtNodeLine(const Node& node, const Provider& prov,
// Blank prefix for continuation lines (same width as type+sep+name+sep) // Blank prefix for continuation lines (same width as type+sep+name+sep)
const int prefixW = colType + colName + 2 * kSepWidth; const int prefixW = colType + colName + 2 * kSepWidth;
// Comment suffix (padded or empty) // Comment suffix (only present when a comment is provided; no trailing padding)
QString cmtSuffix = comment.isEmpty() ? QString(COL_COMMENT, ' ') QString cmtSuffix = comment.isEmpty() ? QString()
: fit(comment, COL_COMMENT); : fit(comment, COL_COMMENT);
// Mat4x4: subLine 0..3 = rows // Mat4x4: subLine 0..3 = rows

View File

@@ -315,16 +315,16 @@ void MainWindow::createMenus() {
auto* actConsolas = fontMenu->addAction("Consolas"); auto* actConsolas = fontMenu->addAction("Consolas");
actConsolas->setCheckable(true); actConsolas->setCheckable(true);
actConsolas->setActionGroup(fontGroup); actConsolas->setActionGroup(fontGroup);
auto* actIosevka = fontMenu->addAction("Iosevka"); auto* actJetBrains = fontMenu->addAction("JetBrains Mono");
actIosevka->setCheckable(true); actJetBrains->setCheckable(true);
actIosevka->setActionGroup(fontGroup); actJetBrains->setActionGroup(fontGroup);
// Load saved preference // Load saved preference
QSettings settings("ReclassX", "ReclassX"); QSettings settings("ReclassX", "ReclassX");
QString savedFont = settings.value("font", "Consolas").toString(); QString savedFont = settings.value("font", "JetBrains Mono").toString();
if (savedFont == "Iosevka") actIosevka->setChecked(true); if (savedFont == "JetBrains Mono") actJetBrains->setChecked(true);
else actConsolas->setChecked(true); else actConsolas->setChecked(true);
connect(actConsolas, &QAction::triggered, this, [this]() { setEditorFont("Consolas"); }); connect(actConsolas, &QAction::triggered, this, [this]() { setEditorFont("Consolas"); });
connect(actIosevka, &QAction::triggered, this, [this]() { setEditorFont("Iosevka"); }); connect(actJetBrains, &QAction::triggered, this, [this]() { setEditorFont("JetBrains Mono"); });
view->addSeparator(); view->addSeparator();
view->addAction(m_workspaceDock->toggleViewAction()); view->addAction(m_workspaceDock->toggleViewAction());
@@ -353,7 +353,7 @@ void MainWindow::createStatusBar() {
statusBar()->setStyleSheet("QStatusBar { background: #252526; color: #858585; }"); statusBar()->setStyleSheet("QStatusBar { background: #252526; color: #858585; }");
QSettings settings("ReclassX", "ReclassX"); QSettings settings("ReclassX", "ReclassX");
QString fontName = settings.value("font", "Consolas").toString(); QString fontName = settings.value("font", "JetBrains Mono").toString();
QFont f(fontName, 12); QFont f(fontName, 12);
f.setFixedPitch(true); f.setFixedPitch(true);
statusBar()->setFont(f); statusBar()->setFont(f);
@@ -361,7 +361,7 @@ void MainWindow::createStatusBar() {
void MainWindow::applyTabWidgetStyle(QTabWidget* tw) { void MainWindow::applyTabWidgetStyle(QTabWidget* tw) {
QSettings settings("ReclassX", "ReclassX"); QSettings settings("ReclassX", "ReclassX");
QString fontName = settings.value("font", "Consolas").toString(); QString fontName = settings.value("font", "JetBrains Mono").toString();
QFont tabFont(fontName, 12); QFont tabFont(fontName, 12);
tabFont.setFixedPitch(true); tabFont.setFixedPitch(true);
tw->tabBar()->setFont(tabFont); tw->tabBar()->setFont(tabFont);
@@ -813,7 +813,7 @@ void MainWindow::updateWindowTitle() {
void MainWindow::setupRenderedSci(QsciScintilla* sci) { void MainWindow::setupRenderedSci(QsciScintilla* sci) {
QSettings settings("ReclassX", "ReclassX"); QSettings settings("ReclassX", "ReclassX");
QString fontName = settings.value("font", "Consolas").toString(); QString fontName = settings.value("font", "JetBrains Mono").toString();
QFont f(fontName, 12); QFont f(fontName, 12);
f.setFixedPitch(true); f.setFixedPitch(true);
@@ -1112,7 +1112,7 @@ void MainWindow::createWorkspaceDock() {
// Match editor font // Match editor font
{ {
QSettings settings("ReclassX", "ReclassX"); QSettings settings("ReclassX", "ReclassX");
QString fontName = settings.value("font", "Consolas").toString(); QString fontName = settings.value("font", "JetBrains Mono").toString();
QFont f(fontName, 12); QFont f(fontName, 12);
f.setFixedPitch(true); f.setFixedPitch(true);
m_workspaceTree->setFont(f); m_workspaceTree->setFont(f);
@@ -1299,13 +1299,13 @@ int main(int argc, char* argv[]) {
app.setStyle("Fusion"); // Fusion style respects dark palette well app.setStyle("Fusion"); // Fusion style respects dark palette well
// Load embedded fonts // Load embedded fonts
int fontId = QFontDatabase::addApplicationFont(":/fonts/Iosevka-Regular.ttf"); int fontId = QFontDatabase::addApplicationFont(":/fonts/JetBrainsMono.ttf");
if (fontId == -1) if (fontId == -1)
qWarning("Failed to load embedded Iosevka font"); qWarning("Failed to load embedded JetBrains Mono font");
// Apply saved font preference before creating any editors // Apply saved font preference before creating any editors
{ {
QSettings settings("ReclassX", "ReclassX"); QSettings settings("ReclassX", "ReclassX");
QString savedFont = settings.value("font", "Consolas").toString(); QString savedFont = settings.value("font", "JetBrains Mono").toString();
rcx::RcxEditor::setGlobalFontName(savedFont); rcx::RcxEditor::setGlobalFontName(savedFont);
} }

View File

@@ -4,7 +4,7 @@
<file alias="chevron-down.png">icons/chevron-down.png</file> <file alias="chevron-down.png">icons/chevron-down.png</file>
</qresource> </qresource>
<qresource prefix="/fonts"> <qresource prefix="/fonts">
<file alias="Iosevka-Regular.ttf">fonts/Iosevka-Regular.ttf</file> <file alias="JetBrainsMono.ttf">fonts/JetBrainsMono.ttf</file>
</qresource> </qresource>
<qresource prefix="/vsicons"> <qresource prefix="/vsicons">
<file alias="file.svg">vsicons/file.svg</file> <file alias="file.svg">vsicons/file.svg</file>

View File

@@ -48,8 +48,8 @@ private slots:
QCOMPARE(result.meta[2].depth, 1); QCOMPARE(result.meta[2].depth, 1);
// Offset text // Offset text
QCOMPARE(result.meta[1].offsetText, QString("0")); QCOMPARE(result.meta[1].offsetText, QString("0000 "));
QCOMPARE(result.meta[2].offsetText, QString("4")); QCOMPARE(result.meta[2].offsetText, QString("0004 "));
// Line 3 is root footer // Line 3 is root footer
QCOMPARE(result.meta[3].lineKind, LineKind::Footer); QCOMPARE(result.meta[3].lineKind, LineKind::Footer);
@@ -81,7 +81,7 @@ private slots:
// Line 1: single Vec3 line, not continuation, depth 1 // Line 1: single Vec3 line, not continuation, depth 1
QVERIFY(!result.meta[1].isContinuation); QVERIFY(!result.meta[1].isContinuation);
QCOMPARE(result.meta[1].offsetText, QString("0")); QCOMPARE(result.meta[1].offsetText, QString("0000 "));
QCOMPARE(result.meta[1].depth, 1); QCOMPARE(result.meta[1].depth, 1);
QCOMPARE(result.meta[1].nodeKind, NodeKind::Vec3); QCOMPARE(result.meta[1].nodeKind, NodeKind::Vec3);

View File

@@ -39,12 +39,21 @@ private slots:
} }
void testFmtOffsetMargin_primary() { void testFmtOffsetMargin_primary() {
QCOMPARE(fmt::fmtOffsetMargin(0x10, false), QString("10")); QCOMPARE(fmt::fmtOffsetMargin(0x10, false), QString("00000010 "));
QCOMPARE(fmt::fmtOffsetMargin(0, false), QString("0")); QCOMPARE(fmt::fmtOffsetMargin(0, false), QString("00000000 "));
} }
void testFmtOffsetMargin_continuation() { void testFmtOffsetMargin_continuation() {
QCOMPARE(fmt::fmtOffsetMargin(0x10, true), QString(" \u00B7")); QCOMPARE(fmt::fmtOffsetMargin(0x10, true), QString(" \u00B7 "));
}
void testFmtOffsetMargin_kernelAddr() {
QCOMPARE(fmt::fmtOffsetMargin(0xFFFFF80012345678ULL, false, 16),
QString("FFFFF80012345678 "));
QCOMPARE(fmt::fmtOffsetMargin(0x10, false, 16),
QString("0000000000000010 "));
QCOMPARE(fmt::fmtOffsetMargin(0x10, false, 4),
QString("0010 "));
} }
void testFmtStructHeader() { void testFmtStructHeader() {

BIN
video.mp4

Binary file not shown.