From 651ef5b9c0168f463fdf3c48a9460ed857700e16 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Burdukiewicz?= Date: Sat, 20 Jul 2024 22:52:50 +0200 Subject: [PATCH] gui: added qscintilla editor and syntax highlights MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Bartłomiej Burdukiewicz --- CMakeLists.txt | 15 +++++++++++++++ src/CMakeLists.txt | 4 +++- src/fdt/fdt-generator-qt.hpp | 9 +++++++++ src/fdt/fdt-header.hpp | 5 +++++ src/fdt/fdt-parser.cpp | 2 +- src/fdt/fdt-view.cpp | 5 ++++- src/main-window.cpp | 34 ++++++++++++++++++++++++++-------- src/main-window.ui | 15 +++++++++------ 8 files changed, 72 insertions(+), 17 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index a5067ab..4c9ea30 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -13,6 +13,21 @@ set(CMAKE_CXX_STANDARD_REQUIRED ON) add_compile_definitions("-D__cpp_concepts=202002L") +find_package(Qt6 COMPONENTS Widgets Core Qsci) + +find_path(QSCI_INCLUDE_DIR NAMES qt6/Qsci/qsciscintilla.h) +find_library(QSCI_LIBRARY NAMES qscintilla2_qt6) + +if (QSCI_INCLUDE_DIR AND QSCI_LIBRARY) + message(STATUS "Found QScintilla") +else() + message(FATAL_ERROR "QScintilla not found") +endif() + +add_library(QScintilla INTERFACE) +target_include_directories(QScintilla INTERFACE ${QSCI_INCLUDE_DIR}) +target_link_libraries(QScintilla INTERFACE ${QSCI_LIBRARY}) + find_package(Qt6 COMPONENTS Widgets Core) if (Qt6_FOUND) add_subdirectory("src") diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index ee56bce..1e76bc3 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -4,12 +4,14 @@ add_subdirectory("submodules/qhexview") file(GLOB_RECURSE fdt-viewer-headers *.hpp) file(GLOB_RECURSE fdt-viewer-sources *.cpp) +file(GLOB_RECURSE fdt-viewer-uis *.ui) add_executable(fdt-viewer ${fdt-viewer-headers} ${fdt-viewer-sources} + ${fdt-viewer-uis} ../resources.qrc ) -target_link_libraries(fdt-viewer PRIVATE Qt6::Widgets Qt6::Core QHexView) +target_link_libraries(fdt-viewer PRIVATE Qt6::Widgets Qt6::Core QScintilla QHexView) install(TARGETS fdt-viewer RUNTIME DESTINATION bin) diff --git a/src/fdt/fdt-generator-qt.hpp b/src/fdt/fdt-generator-qt.hpp index c96d750..bbe01f3 100644 --- a/src/fdt/fdt-generator-qt.hpp +++ b/src/fdt/fdt-generator-qt.hpp @@ -32,6 +32,15 @@ struct tree_info { using tree_map = hash_map; +namespace fdt { +template +concept TreeGenerator = requires(T t, std::string_view sv, const fdt::parser::token_types::property &prop) { + { t.begin_node(sv) }; + { t.end_node() }; + { t.insert_property(prop) }; +}; +} // namespace fdt + namespace fdt::qt_wrappers { constexpr auto ROLE_PROPERTY = Qt::UserRole; diff --git a/src/fdt/fdt-header.hpp b/src/fdt/fdt-header.hpp index fe09c1e..7a6a79a 100644 --- a/src/fdt/fdt-header.hpp +++ b/src/fdt/fdt-header.hpp @@ -1,6 +1,7 @@ #pragma once #include +#include namespace fdt::decode { struct header { @@ -26,6 +27,10 @@ constexpr auto is_magic_invalid(const header &v) -> bool { return v.magic != header_magic_value; } +constexpr auto is_data_truncated(const header &v, const std::size_t size) -> bool { + return size < v.totalsize; +} + constexpr auto is_version_unsupported(const header &v) -> bool { constexpr auto header_support_above = 16; return v.version <= header_support_above; diff --git a/src/fdt/fdt-parser.cpp b/src/fdt/fdt-parser.cpp index daf85cf..54af102 100644 --- a/src/fdt/fdt-parser.cpp +++ b/src/fdt/fdt-parser.cpp @@ -80,7 +80,7 @@ auto fdt::parser::parse(std::string_view view) -> std::expected #include #include +#include #include #include @@ -102,7 +103,7 @@ bool fdt::viewer::load(QByteArray &&data, QString &&name, QString &&id) { using namespace fdt::parser; using namespace fdt::qt_wrappers; - auto tokens = parse({data.data(), data.size()}); + auto tokens = parse({data.data(), static_cast(data.size())}); if (!tokens) return false; @@ -112,7 +113,9 @@ bool fdt::viewer::load(QByteArray &&data, QString &&name, QString &&id) { fdt::parser::rename_root(tokens.value(), name.toStdString()); + m_target->blockSignals(true); tree_generator generator(m_tree[id], m_target, std::move(name), std::move(id)); + m_target->blockSignals(false); for (auto &&token : tokens.value()) std::visit(overloaded{ diff --git a/src/main-window.cpp b/src/main-window.cpp index 343838c..f14436f 100644 --- a/src/main-window.cpp +++ b/src/main-window.cpp @@ -1,7 +1,5 @@ #include "main-window.hpp" -#include "fdt/fdt-parser-tokens.hpp" #include "fdt/fdt-property-types.hpp" -#include "qabstractitemview.h" #include "ui_main-window.h" #include @@ -19,6 +17,9 @@ #include #include +#include +#include + #include "submodules/qhexview/model/buffer/qmemorybuffer.h" #include "submodules/qhexview/qhexview.h" @@ -46,10 +47,10 @@ MainWindow::MainWindow(QWidget *parent) connect(m_menu.get(), &menu_manager::show_normal, this, &MainWindow::showNormal); connect(m_menu.get(), &menu_manager::quit, this, &MainWindow::close); - m_ui->text_view->setWordWrapMode(QTextOption::NoWrap); + m_ui->editor->setWrapMode(QsciScintilla::WrapNone); connect(m_menu.get(), &menu_manager::use_word_wrap, [this](const bool value) { - m_ui->text_view->setWordWrapMode(value ? QTextOption::WordWrap : QTextOption::NoWrap); + m_ui->editor->setWrapMode(value ? QsciScintilla::WrapWord : QsciScintilla::WrapNone); }); connect(m_menu.get(), &menu_manager::show_about_qt, []() { QApplication::aboutQt(); }); @@ -97,7 +98,18 @@ MainWindow::MainWindow(QWidget *parent) connect(m_ui->treeWidget, &QTreeWidget::itemSelectionChanged, this, &MainWindow::update_view); viewer_settings settings; - m_ui->text_view->setWordWrapMode(settings.view_word_wrap.value() ? QTextOption::WordWrap : QTextOption::NoWrap); + auto lexer = new QsciLexerCPP(this, false); + + lexer->setFont(QFont{}); + lexer->setColor(Qt::yellow, QsciLexerCPP::Identifier); + lexer->setColor(Qt::lightGray, QsciLexerCPP::Operator); + lexer->setColor(Qt::green, QsciLexerCPP::DoubleQuotedString); + + m_ui->editor->setLexer(lexer); + m_ui->editor->setMarginsBackgroundColor(Qt::black); + m_ui->editor->setMarginsForegroundColor(Qt::green); + m_ui->editor->setMarginType(0, QsciScintilla::NumberMargin); + m_ui->editor->setMarginWidth(0, 50); if (settings.window_show_fullscreen.value()) showFullScreen(); @@ -172,7 +184,7 @@ void MainWindow::update_view() { if (m_ui->treeWidget->selectedItems().isEmpty()) { m_ui->preview->setCurrentWidget(m_ui->text_view_page); - m_ui->text_view->clear(); + m_ui->editor->clear(); m_ui->statusbar->clearMessage(); m_ui->path->clear(); return; @@ -188,13 +200,19 @@ void MainWindow::update_view() { m_hexview->setDocument(QHexDocument::fromMemory(property.data)); } - m_ui->text_view->clear(); + m_ui->editor->clear(); update_fdt_path(item); QString ret; ret.reserve(VIEW_TEXT_CACHE_SIZE); fdt::fdt_view_dts(item, ret); - m_ui->text_view->setText(ret); + + m_ui->editor->setText(ret); + + QFontMetrics metrics(QFont{}); + const auto num = QString::number(m_ui->editor->lines()); + + m_ui->editor->setMarginWidth(0, metrics.horizontalAdvance(num) * 1.25); } void MainWindow::property_export() { diff --git a/src/main-window.ui b/src/main-window.ui index 42f7615..29549ff 100644 --- a/src/main-window.ui +++ b/src/main-window.ui @@ -28,7 +28,7 @@ - Qt::Horizontal + Qt::Orientation::Horizontal @@ -90,11 +90,7 @@ 0 - - - QFrame::NoFrame - - + @@ -122,6 +118,13 @@ + + + QsciScintilla + QWidget +
Qsci/qsciscintilla.h
+
+