#include "sciedit.h" #include #include #include static sptr_t toBgr(const QColor &color) { return (color.blue() << 16) | (color.green() << 8) | color.red(); } SciEdit::SciEdit(QWidget * parent) : ScintillaEdit(parent) { connect(this, &ScintillaEditBase::updateUi, this, [this](){ int curPos = currentPos(); emit cursorPosChanged(lineFromPosition(curPos) + 1, column(curPos)); updateLineNumberMarginWidth(); }); // 连接文本变化信号 connect(this, QOverload::of(&ScintillaEditBase::modified), this, &SciEdit::textChanged); setLineNumbersEnabled(true); } void SciEdit::setStyleFont(const QFont &font, int style) { styleSetFont(style, font.family().toUtf8().constData()); styleSetSizeFractional(style, long(font.pointSizeF() * SC_FONT_SIZE_MULTIPLIER)); } void SciEdit::setFolding(FoldType foldType, int margin) { if (foldType == NoFoldType) { setMarginWidthN(margin, 0L); return; } int mask = modEventMask(); setModEventMask(mask | SC_MOD_CHANGEFOLD); setFoldFlags(SC_FOLDFLAG_LINEAFTER_CONTRACTED); setMarginTypeN(margin, SC_MARGIN_SYMBOL); setMarginMaskN(margin, SC_MASK_FOLDERS); setMarginSensitiveN(margin, 1); setMarkerDefine(SC_MARKNUM_FOLDEROPEN, SC_MARK_BOXMINUS); setMarkerDefine(SC_MARKNUM_FOLDER, SC_MARK_BOXPLUS); setMarkerDefine(SC_MARKNUM_FOLDERSUB, SC_MARK_VLINE); setMarkerDefine(SC_MARKNUM_FOLDERTAIL, SC_MARK_LCORNER); setMarkerDefine(SC_MARKNUM_FOLDEREND, SC_MARK_BOXPLUSCONNECTED); setMarkerDefine(SC_MARKNUM_FOLDEROPENMID, SC_MARK_BOXMINUSCONNECTED); setMarkerDefine(SC_MARKNUM_FOLDERMIDTAIL, SC_MARK_TCORNER); setMarginWidthN(margin, 14); return; } void SciEdit::setLexer(Scintilla::ILexer5 *lexer) { setILexer((sptr_t)lexer); m_lexerName = lexer ? QString::fromUtf8(lexer->GetName()) : QString(); if (lexer == nullptr) { clearDocumentStyle(); } applyLexerStyles(); colourise(0, -1); } void SciEdit::setLineNumbersEnabled(bool enabled) { m_lineNumbersEnabled = enabled; setMarginTypeN(0, SC_MARGIN_NUMBER); updateLineNumberMarginWidth(); } void SciEdit::setEditorFont(const QFont &font) { m_editorFont = font; applyTheme(m_isDarkTheme); } void SciEdit::applyTheme(bool dark) { m_isDarkTheme = dark; const QColor bg = dark ? QColor(0x1e, 0x1e, 0x1e) : QColor(0xff, 0xff, 0xff); const QColor fg = dark ? QColor(0xd4, 0xd4, 0xd4) : QColor(0x00, 0x00, 0x00); const QColor caret = dark ? QColor(0xff, 0xff, 0xff) : QColor(0x00, 0x00, 0x00); const QColor selectionBg = dark ? QColor(0x26, 0x4f, 0x78) : QColor(0xcc, 0xe8, 0xff); const QColor caretLineBg = dark ? QColor(0x2a, 0x2a, 0x2a) : QColor(0xf5, 0xf5, 0xf5); const QColor lineNumberFg = dark ? QColor(0x85, 0x85, 0x85) : QColor(0x80, 0x80, 0x80); const QColor lineNumberBg = dark ? QColor(0x25, 0x25, 0x26) : QColor(0xf0, 0xf0, 0xf0); styleResetDefault(); if (!m_editorFont.family().isEmpty()) { setStyleFont(m_editorFont, STYLE_DEFAULT); } styleSetFore(STYLE_DEFAULT, toBgr(fg)); styleSetBack(STYLE_DEFAULT, toBgr(bg)); styleClearAll(); setCaretFore(toBgr(caret)); setSelFore(true, toBgr(fg)); setSelBack(true, toBgr(selectionBg)); setCaretLineVisible(true); setCaretLineBack(toBgr(caretLineBg)); styleSetFore(STYLE_LINENUMBER, toBgr(lineNumberFg)); styleSetBack(STYLE_LINENUMBER, toBgr(lineNumberBg)); setMarginBackN(0, toBgr(lineNumberBg)); updateLineNumberMarginWidth(); applyLexerStyles(); } void SciEdit::sendColor(unsigned int iMessage, uptr_t wParam, const QColor &color) const { send(iMessage, wParam, toBgr(color)); } void SciEdit::setMarkerDefine(int markerNumber, int markerSymbol) { markerDefine(markerNumber, markerSymbol); // necessary? if (markerSymbol != SC_MARK_EMPTY) { sendColor(SCI_MARKERSETFORE, markerNumber, QColor(Qt::white)); sendColor(SCI_MARKERSETBACK, markerNumber, QColor(128, 128, 128)); } } void SciEdit::updateLineNumberMarginWidth() { if (!m_lineNumbersEnabled) { setMarginWidthN(0, 0); return; } const int lines = qMax(1, lineCount()); const int digits = QString::number(lines).size(); if (digits == m_lastLineNumberDigits && marginWidthN(0) > 0) { return; } m_lastLineNumberDigits = digits; const QString sample = QString(digits, QLatin1Char('9')); const QByteArray sampleBytes = sample.toUtf8(); const sptr_t width = textWidth(STYLE_LINENUMBER, sampleBytes.constData()) + 10; setMarginWidthN(0, width); } void SciEdit::applyLexerStyles() { if (m_lexerName.isEmpty()) { return; } const bool dark = m_isDarkTheme; const QColor comment = dark ? QColor(0x6a, 0x99, 0x55) : QColor(0x00, 0x80, 0x00); const QColor docComment = dark ? QColor(0x60, 0x80, 0x4f) : QColor(0x00, 0x80, 0x00); const QColor keyword = dark ? QColor(0x56, 0x9c, 0xd6) : QColor(0x00, 0x00, 0xff); const QColor type = dark ? QColor(0x4e, 0xc9, 0xb0) : QColor(0x2b, 0x91, 0xaf); const QColor number = dark ? QColor(0xb5, 0xce, 0xa8) : QColor(0x09, 0x86, 0x58); const QColor string = dark ? QColor(0xce, 0x91, 0x78) : QColor(0xa3, 0x15, 0x15); const QColor preprocessor = dark ? QColor(0xc5, 0x86, 0xc0) : QColor(0xaf, 0x00, 0xdb); const QColor tag = dark ? QColor(0x56, 0x9c, 0xd6) : QColor(0x80, 0x00, 0x00); const QColor attr = dark ? QColor(0x9c, 0xdc, 0xfe) : QColor(0xff, 0x00, 0x00); auto setFore = [&](int style, const QColor &c) { styleSetFore(style, toBgr(c)); }; auto setBold = [&](int style, bool b) { styleSetBold(style, b); }; if (m_lexerName == QStringLiteral("cpp")) { setFore(SCE_C_COMMENT, comment); setFore(SCE_C_COMMENTLINE, comment); setFore(SCE_C_COMMENTDOC, docComment); setFore(SCE_C_COMMENTLINEDOC, docComment); setFore(SCE_C_COMMENTDOCKEYWORD, docComment); setFore(SCE_C_COMMENTDOCKEYWORDERROR, docComment); setFore(SCE_C_NUMBER, number); setFore(SCE_C_STRING, string); setFore(SCE_C_CHARACTER, string); setFore(SCE_C_PREPROCESSOR, preprocessor); setFore(SCE_C_WORD, keyword); setBold(SCE_C_WORD, true); setFore(SCE_C_WORD2, type); setBold(SCE_C_WORD2, true); } else if (m_lexerName == QStringLiteral("python")) { setFore(SCE_P_COMMENTLINE, comment); setFore(SCE_P_NUMBER, number); setFore(SCE_P_STRING, string); setFore(SCE_P_CHARACTER, string); setFore(SCE_P_WORD, keyword); setBold(SCE_P_WORD, true); setFore(SCE_P_WORD2, type); setBold(SCE_P_WORD2, true); setFore(SCE_P_DECORATOR, preprocessor); setFore(SCE_P_CLASSNAME, type); setFore(SCE_P_DEFNAME, type); } else if (m_lexerName == QStringLiteral("hypertext")) { setFore(SCE_H_COMMENT, comment); setFore(SCE_H_TAG, tag); setFore(SCE_H_TAGUNKNOWN, tag); setFore(SCE_H_ATTRIBUTE, attr); setFore(SCE_H_ATTRIBUTEUNKNOWN, attr); setFore(SCE_H_NUMBER, number); setFore(SCE_H_DOUBLESTRING, string); setFore(SCE_H_SINGLESTRING, string); setFore(SCE_H_ENTITY, preprocessor); } else if (m_lexerName == QStringLiteral("xml")) { setFore(SCE_H_COMMENT, comment); setFore(SCE_H_TAG, tag); setFore(SCE_H_TAGUNKNOWN, tag); setFore(SCE_H_ATTRIBUTE, attr); setFore(SCE_H_ATTRIBUTEUNKNOWN, attr); setFore(SCE_H_NUMBER, number); setFore(SCE_H_DOUBLESTRING, string); setFore(SCE_H_SINGLESTRING, string); setFore(SCE_H_ENTITY, preprocessor); } else if (m_lexerName == QStringLiteral("json")) { setFore(SCE_JSON_NUMBER, number); setFore(SCE_JSON_STRING, string); setFore(SCE_JSON_PROPERTYNAME, attr); setFore(SCE_JSON_OPERATOR, preprocessor); setFore(SCE_JSON_LINECOMMENT, comment); setFore(SCE_JSON_BLOCKCOMMENT, comment); } else if (m_lexerName == QStringLiteral("css")) { setFore(SCE_CSS_COMMENT, comment); setFore(SCE_CSS_CLASS, attr); setFore(SCE_CSS_ID, attr); setFore(SCE_CSS_TAG, tag); setFore(SCE_CSS_ATTRIBUTE, attr); setFore(SCE_CSS_DOUBLESTRING, string); setFore(SCE_CSS_SINGLESTRING, string); setFore(SCE_CSS_VALUE, string); setFore(SCE_CSS_IDENTIFIER, keyword); setBold(SCE_CSS_IDENTIFIER, true); } }