From bf6ed3d5409df7740e1b01ce9b81d14e17213c1f Mon Sep 17 00:00:00 2001 From: WerWolv Date: Sat, 21 Nov 2020 00:12:58 +0100 Subject: [PATCH] Added proper data inspector view --- CMakeLists.txt | 1 + include/event.hpp | 3 +- include/views/view_data_inspector.hpp | 57 ++++++ libs/ImGui/include/imgui_memory_editor.h | 217 ++--------------------- source/main.cpp | 2 + source/views/view_data_inspector.cpp | 140 +++++++++++++++ source/views/view_pattern.cpp | 8 +- 7 files changed, 219 insertions(+), 209 deletions(-) create mode 100644 include/views/view_data_inspector.hpp create mode 100644 source/views/view_data_inspector.cpp diff --git a/CMakeLists.txt b/CMakeLists.txt index 31b8dad5e..5c1503889 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -36,6 +36,7 @@ add_executable(ImHex source/views/view_help.cpp source/views/view_tools.cpp source/views/view_strings.cpp + source/views/view_data_inspector.cpp libs/glad/source/glad.c diff --git a/include/event.hpp b/include/event.hpp index e9888f69c..d8df5fc73 100644 --- a/include/event.hpp +++ b/include/event.hpp @@ -8,7 +8,8 @@ namespace hex { enum class Events { DataChanged, PatternChanged, - FileDropped + FileDropped, + ByteSelected }; struct EventHandler { diff --git a/include/views/view_data_inspector.hpp b/include/views/view_data_inspector.hpp new file mode 100644 index 000000000..e4d8b3fd9 --- /dev/null +++ b/include/views/view_data_inspector.hpp @@ -0,0 +1,57 @@ +#pragma once + +#include "views/view.hpp" + +#include +#include +#include + +namespace hex { + + namespace prv { class Provider; } + + struct GUID { + u32 data1; + u16 data2; + u16 data3; + u8 data4[8]; + }; + + union PreviewData { + u8 unsigned8; + s8 signed8; + u16 unsigned16; + s16 signed16; + u32 unsigned32; + s32 signed32; + u64 unsigned64; + s64 signed64; + char8_t ansiChar; + char16_t wideChar; + u8 utf8Char[4]; + float float32; + double float64; + __time32_t time32; + __time64_t time64; + GUID guid; + }; + + class ViewDataInspector : public View { + public: + explicit ViewDataInspector(prv::Provider* &dataProvider); + ~ViewDataInspector() override; + + void createView() override; + void createMenu() override; + + private: + prv::Provider* &m_dataProvider; + bool m_windowOpen = true; + bool m_shouldInvalidate = true; + + PreviewData m_previewData = { 0 }; + size_t m_validBytes = 0; + std::vector> m_cachedData; + }; + +} \ No newline at end of file diff --git a/libs/ImGui/include/imgui_memory_editor.h b/libs/ImGui/include/imgui_memory_editor.h index bca0426c8..665ab6d2a 100644 --- a/libs/ImGui/include/imgui_memory_editor.h +++ b/libs/ImGui/include/imgui_memory_editor.h @@ -47,6 +47,8 @@ #include // sprintf, scanf #include // uint8_t, etc. +#include "views/view.hpp" + #ifdef _MSC_VER #define _PRISizeT "I" #define ImSnprintf _snprintf @@ -77,7 +79,6 @@ struct MemoryEditor bool ReadOnly; // = false // disable any editing. int Cols; // = 16 // number of columns to display. bool OptShowOptions; // = true // display options button/context menu. when disabled, options will be locked unless you provide your own UI for them. - bool OptShowDataPreview; // = false // display a footer previewing the decimal/binary/hex/float representation of the currently selected bytes. bool OptShowHexII; // = false // display values in HexII representation instead of regular hexadecimal: hide null/zero bytes, ascii values as ".X". bool OptShowAscii; // = true // display ASCII representation on the right side. bool OptGreyOutZeroes; // = true // display null/zero bytes using the TextDisabled color. @@ -109,7 +110,6 @@ struct MemoryEditor ReadOnly = false; Cols = 16; OptShowOptions = true; - OptShowDataPreview = false; OptShowHexII = false; OptShowAscii = true; OptGreyOutZeroes = true; @@ -189,8 +189,6 @@ struct MemoryEditor if (ImGui::Begin(title, &Open, ImGuiWindowFlags_NoScrollbar)) { - if (ImGui::IsWindowHovered(ImGuiHoveredFlags_RootAndChildWindows) && ImGui::IsMouseReleased(ImGuiMouseButton_Right)) - ImGui::OpenPopup("context"); DrawContents(mem_data, mem_size, base_display_addr); if (ContentsWidthChanged) { @@ -229,8 +227,6 @@ struct MemoryEditor float footer_height = 0; if (OptShowOptions) footer_height += height_separator + ImGui::GetFrameHeightWithSpacing() * 1; - if (OptShowDataPreview) - footer_height += height_separator + ImGui::GetFrameHeightWithSpacing() * 1 + ImGui::GetTextLineHeightWithSpacing() * 3; ImGui::BeginChild("offset", ImVec2(0, s.LineHeight), false, ImGuiWindowFlags_NoMove | ImGuiWindowFlags_NoNav); ImGui::Text("% *c ", s.AddrDigitsCount, ' '); @@ -267,8 +263,6 @@ struct MemoryEditor if (DataPreviewAddrEnd >= mem_size) DataPreviewAddrEnd = (size_t)-1; - size_t preview_data_type_size = OptShowDataPreview ? DataTypeGetSize(PreviewDataType) : 0; - size_t data_editing_addr_backup = DataEditingAddr; size_t data_editing_addr_next = (size_t)-1; if (DataEditingAddr != (size_t)-1) @@ -428,9 +422,15 @@ struct MemoryEditor DataPreviewAddr = addr; DataPreviewAddrEnd = addr; + + hex::View::postEvent(hex::Events::ByteSelected, &DataPreviewAddr); } if (!ReadOnly && ImGui::IsItemHovered() && ((ImGui::IsMouseClicked(0) && ImGui::GetIO().KeyShift) || ImGui::IsMouseDragging(0))) { DataPreviewAddrEnd = addr; + + size_t dataPreviewStart = std::min(DataPreviewAddr, DataPreviewAddrEnd); + + hex::View::postEvent(hex::Events::ByteSelected, &dataPreviewStart); } } } @@ -513,19 +513,12 @@ struct MemoryEditor DataEditingAddr = DataPreviewAddr = data_editing_addr_next; } - const bool lock_show_data_preview = OptShowDataPreview; if (OptShowOptions) { ImGui::Separator(); DrawOptionsLine(s, mem_data, mem_size, base_display_addr); } - if (lock_show_data_preview) - { - ImGui::Separator(); - DrawPreviewLine(s, mem_data, mem_size, base_display_addr); - } - // Notify the main window of our ideal child content size (FIXME: we are missing an API to get the contents size from the child) ImGui::SetCursorPosX(s.WindowWidth); } @@ -538,13 +531,12 @@ struct MemoryEditor // Options menu if (ImGui::Button("Options")) - ImGui::OpenPopup("context"); - if (ImGui::BeginPopup("context")) - { + ImGui::OpenPopup("options"); + + if (ImGui::BeginPopup("options")) { ImGui::PushItemWidth(56); if (ImGui::DragInt("##cols", &Cols, 0.2f, 4, 32, "%d cols")) { ContentsWidthChanged = true; if (Cols < 1) Cols = 1; } ImGui::PopItemWidth(); - ImGui::Checkbox("Show Data Preview", &OptShowDataPreview); ImGui::Checkbox("Show HexII", &OptShowHexII); if (ImGui::Checkbox("Show Ascii", &OptShowAscii)) { ContentsWidthChanged = true; } ImGui::Checkbox("Grey out zeroes", &OptGreyOutZeroes); @@ -582,66 +574,7 @@ struct MemoryEditor } } - void DrawPreviewLine(const Sizes& s, void* mem_data_void, size_t mem_size, size_t base_display_addr) - { - IM_UNUSED(base_display_addr); - ImU8* mem_data = (ImU8*)mem_data_void; - ImGuiStyle& style = ImGui::GetStyle(); - ImGui::AlignTextToFramePadding(); - ImGui::Text("Preview as:"); - ImGui::SameLine(); - ImGui::PushItemWidth((s.GlyphWidth * 10.0f) + style.FramePadding.x * 2.0f + style.ItemInnerSpacing.x); - if (ImGui::BeginCombo("##combo_type", DataTypeGetDesc(PreviewDataType), ImGuiComboFlags_HeightLargest)) - { - for (int n = 0; n < ImGuiDataType_COUNT; n++) - if (ImGui::Selectable(DataTypeGetDesc((ImGuiDataType)n), PreviewDataType == n)) - PreviewDataType = (ImGuiDataType)n; - ImGui::EndCombo(); - } - ImGui::PopItemWidth(); - ImGui::SameLine(); - ImGui::PushItemWidth((s.GlyphWidth * 6.0f) + style.FramePadding.x * 2.0f + style.ItemInnerSpacing.x); - ImGui::Combo("##combo_endianess", &PreviewEndianess, "LE\0BE\0\0"); - ImGui::PopItemWidth(); - - char buf[128] = ""; - float x = s.GlyphWidth * 6.0f; - bool has_value = DataPreviewAddr != (size_t)-1; - if (has_value) - DrawPreviewData(DataPreviewAddr, mem_data, mem_size, PreviewDataType, DataFormat_Dec, buf, (size_t)IM_ARRAYSIZE(buf)); - ImGui::Text("Dec"); ImGui::SameLine(x); ImGui::TextUnformatted(has_value ? buf : "N/A"); - if (has_value) - DrawPreviewData(DataPreviewAddr, mem_data, mem_size, PreviewDataType, DataFormat_Hex, buf, (size_t)IM_ARRAYSIZE(buf)); - ImGui::Text("Hex"); ImGui::SameLine(x); ImGui::TextUnformatted(has_value ? buf : "N/A"); - if (has_value) - DrawPreviewData(DataPreviewAddr, mem_data, mem_size, PreviewDataType, DataFormat_Bin, buf, (size_t)IM_ARRAYSIZE(buf)); - buf[IM_ARRAYSIZE(buf) - 1] = 0; - ImGui::Text("Bin"); ImGui::SameLine(x); ImGui::TextUnformatted(has_value ? buf : "N/A"); - } - - // Utilities for Data Preview - const char* DataTypeGetDesc(ImGuiDataType data_type) const - { - const char* descs[] = { "Int8", "Uint8", "Int16", "Uint16", "Int32", "Uint32", "Int64", "Uint64", "Float", "Double" }; - IM_ASSERT(data_type >= 0 && data_type < ImGuiDataType_COUNT); - return descs[data_type]; - } - - size_t DataTypeGetSize(ImGuiDataType data_type) const - { - const size_t sizes[] = { 1, 1, 2, 2, 4, 4, 8, 8, sizeof(float), sizeof(double) }; - IM_ASSERT(data_type >= 0 && data_type < ImGuiDataType_COUNT); - return sizes[data_type]; - } - - const char* DataFormatGetDesc(DataFormat data_format) const - { - const char* descs[] = { "Bin", "Dec", "Hex" }; - IM_ASSERT(data_format >= 0 && data_format < DataFormat_COUNT); - return descs[data_format]; - } - - bool IsBigEndian() const + static bool IsBigEndian() { uint16_t x = 1; char c[2]; @@ -688,132 +621,6 @@ struct MemoryEditor fp = IsBigEndian() ? EndianessCopyBigEndian : EndianessCopyLittleEndian; return fp(dst, src, size, PreviewEndianess); } - - const char* FormatBinary(const uint8_t* buf, int width) const - { - IM_ASSERT(width <= 64); - size_t out_n = 0; - static char out_buf[64 + 8 + 1]; - int n = width / 8; - for (int j = n - 1; j >= 0; --j) - { - for (int i = 0; i < 8; ++i) - out_buf[out_n++] = (buf[j] & (1 << (7 - i))) ? '1' : '0'; - out_buf[out_n++] = ' '; - } - IM_ASSERT(out_n < IM_ARRAYSIZE(out_buf)); - out_buf[out_n] = 0; - return out_buf; - } - - // [Internal] - void DrawPreviewData(size_t addr, const ImU8* mem_data, size_t mem_size, ImGuiDataType data_type, DataFormat data_format, char* out_buf, size_t out_buf_size) const - { - uint8_t buf[8]; - size_t elem_size = DataTypeGetSize(data_type); - size_t size = addr + elem_size > mem_size ? mem_size - addr : elem_size; - if (ReadFn) - for (int i = 0, n = (int)size; i < n; ++i) - buf[i] = ReadFn(mem_data, addr + i); - else - memcpy(buf, mem_data + addr, size); - - if (data_format == DataFormat_Bin) - { - uint8_t binbuf[8]; - EndianessCopy(binbuf, buf, size); - ImSnprintf(out_buf, out_buf_size, "%s", FormatBinary(binbuf, (int)size * 8)); - return; - } - - out_buf[0] = 0; - switch (data_type) - { - case ImGuiDataType_S8: - { - int8_t int8 = 0; - EndianessCopy(&int8, buf, size); - if (data_format == DataFormat_Dec) { ImSnprintf(out_buf, out_buf_size, "%hhd", int8); return; } - if (data_format == DataFormat_Hex) { ImSnprintf(out_buf, out_buf_size, "0x%02x", int8 & 0xFF); return; } - break; - } - case ImGuiDataType_U8: - { - uint8_t uint8 = 0; - EndianessCopy(&uint8, buf, size); - if (data_format == DataFormat_Dec) { ImSnprintf(out_buf, out_buf_size, "%hhu", uint8); return; } - if (data_format == DataFormat_Hex) { ImSnprintf(out_buf, out_buf_size, "0x%02x", uint8 & 0XFF); return; } - break; - } - case ImGuiDataType_S16: - { - int16_t int16 = 0; - EndianessCopy(&int16, buf, size); - if (data_format == DataFormat_Dec) { ImSnprintf(out_buf, out_buf_size, "%hd", int16); return; } - if (data_format == DataFormat_Hex) { ImSnprintf(out_buf, out_buf_size, "0x%04x", int16 & 0xFFFF); return; } - break; - } - case ImGuiDataType_U16: - { - uint16_t uint16 = 0; - EndianessCopy(&uint16, buf, size); - if (data_format == DataFormat_Dec) { ImSnprintf(out_buf, out_buf_size, "%hu", uint16); return; } - if (data_format == DataFormat_Hex) { ImSnprintf(out_buf, out_buf_size, "0x%04x", uint16 & 0xFFFF); return; } - break; - } - case ImGuiDataType_S32: - { - int32_t int32 = 0; - EndianessCopy(&int32, buf, size); - if (data_format == DataFormat_Dec) { ImSnprintf(out_buf, out_buf_size, "%d", int32); return; } - if (data_format == DataFormat_Hex) { ImSnprintf(out_buf, out_buf_size, "0x%08x", int32); return; } - break; - } - case ImGuiDataType_U32: - { - uint32_t uint32 = 0; - EndianessCopy(&uint32, buf, size); - if (data_format == DataFormat_Dec) { ImSnprintf(out_buf, out_buf_size, "%u", uint32); return; } - if (data_format == DataFormat_Hex) { ImSnprintf(out_buf, out_buf_size, "0x%08x", uint32); return; } - break; - } - case ImGuiDataType_S64: - { - int64_t int64 = 0; - EndianessCopy(&int64, buf, size); - if (data_format == DataFormat_Dec) { ImSnprintf(out_buf, out_buf_size, "%lld", (long long)int64); return; } - if (data_format == DataFormat_Hex) { ImSnprintf(out_buf, out_buf_size, "0x%016llx", (long long)int64); return; } - break; - } - case ImGuiDataType_U64: - { - uint64_t uint64 = 0; - EndianessCopy(&uint64, buf, size); - if (data_format == DataFormat_Dec) { ImSnprintf(out_buf, out_buf_size, "%llu", (long long)uint64); return; } - if (data_format == DataFormat_Hex) { ImSnprintf(out_buf, out_buf_size, "0x%016llx", (long long)uint64); return; } - break; - } - case ImGuiDataType_Float: - { - float float32 = 0.0f; - EndianessCopy(&float32, buf, size); - if (data_format == DataFormat_Dec) { ImSnprintf(out_buf, out_buf_size, "%f", float32); return; } - if (data_format == DataFormat_Hex) { ImSnprintf(out_buf, out_buf_size, "%a", float32); return; } - break; - } - case ImGuiDataType_Double: - { - double float64 = 0.0; - EndianessCopy(&float64, buf, size); - if (data_format == DataFormat_Dec) { ImSnprintf(out_buf, out_buf_size, "%f", float64); return; } - if (data_format == DataFormat_Hex) { ImSnprintf(out_buf, out_buf_size, "%a", float64); return; } - break; - } - case ImGuiDataType_COUNT: - break; - } // Switch - IM_ASSERT(0); // Shouldn't reach - } }; #undef _PRISizeT diff --git a/source/main.cpp b/source/main.cpp index 554484215..1eab4e95b 100644 --- a/source/main.cpp +++ b/source/main.cpp @@ -9,6 +9,7 @@ #include "views/view_help.hpp" #include "views/view_tools.hpp" #include "views/view_strings.hpp" +#include "views/view_data_inspector.hpp" #include "providers/provider.hpp" @@ -25,6 +26,7 @@ int main() { window.addView(dataProvider, patternData); window.addView(dataProvider, patternData); window.addView(dataProvider, patternData); + window.addView(dataProvider); window.addView(dataProvider); window.addView(dataProvider); window.addView(dataProvider); diff --git a/source/views/view_data_inspector.cpp b/source/views/view_data_inspector.cpp new file mode 100644 index 000000000..66dde714e --- /dev/null +++ b/source/views/view_data_inspector.cpp @@ -0,0 +1,140 @@ +#include "views/view_data_inspector.hpp" + +#include "providers/provider.hpp" +#include "utils.hpp" + +#include + +extern int ImTextCharFromUtf8(unsigned int* out_char, const char* in_text, const char* in_text_end); + +namespace hex { + + ViewDataInspector::ViewDataInspector(prv::Provider* &dataProvider) : View(), m_dataProvider(dataProvider) { + View::subscribeEvent(Events::ByteSelected, [this](const void* userData){ + size_t offset = *static_cast(userData); + + this->m_validBytes = std::min(this->m_dataProvider->getSize() - offset, sizeof(PreviewData)); + std::memset(&this->m_previewData, 0x00, sizeof(PreviewData)); + this->m_dataProvider->read(offset, &this->m_previewData, sizeof(PreviewData)); + + this->m_shouldInvalidate = true; + }); + } + + ViewDataInspector::~ViewDataInspector() { + View::unsubscribeEvent(Events::ByteSelected); + } + + void ViewDataInspector::createView() { + if (!this->m_windowOpen) + return; + + if (this->m_shouldInvalidate) { + this->m_shouldInvalidate = false; + + this->m_cachedData.clear(); + + { + std::string binary; + for (u8 i = 0; i < 8; i++) + binary += ((this->m_previewData.unsigned8 << i) & 0x80) == 0 ? '0' : '1'; + this->m_cachedData.emplace_back("Binary (8 bit)", binary); + } + + this->m_cachedData.emplace_back("uint8_t", hex::format("%u", this->m_previewData.unsigned8)); + this->m_cachedData.emplace_back("int8_t", hex::format("%d", this->m_previewData.unsigned8)); + this->m_cachedData.emplace_back("uint16_t", hex::format("%u", this->m_previewData.unsigned16)); + this->m_cachedData.emplace_back("int16_t", hex::format("%d", this->m_previewData.unsigned16)); + this->m_cachedData.emplace_back("uint32_t", hex::format("%lu", this->m_previewData.unsigned32)); + this->m_cachedData.emplace_back("int32_t", hex::format("%ld", this->m_previewData.unsigned32)); + this->m_cachedData.emplace_back("uint64_t", hex::format("%llu", this->m_previewData.unsigned64)); + this->m_cachedData.emplace_back("int64_t", hex::format("%lld", this->m_previewData.unsigned64)); + + this->m_cachedData.emplace_back("ANSI Character / char8_t", hex::format("%c", this->m_previewData.ansiChar)); + this->m_cachedData.emplace_back("Wide Character / char16_t", hex::format("%lc", this->m_previewData.wideChar)); + { + char buffer[5] = { 0 }; + std::memcpy(buffer, &this->m_previewData.utf8Char, 4); + u32 utf8 = 0; + ImTextCharFromUtf8(&utf8, buffer, buffer + 4); + this->m_cachedData.emplace_back("UTF-8 code point", hex::format("U+%08lx", utf8)); + } + + this->m_cachedData.emplace_back("float (32 bit)", hex::format("%e", this->m_previewData.float32)); + this->m_cachedData.emplace_back("double (64 bit)", hex::format("%e", this->m_previewData.float64)); + + { + std::tm * ptm = _localtime32(&this->m_previewData.time32); + char buffer[32]; + if (std::strftime(buffer, 32, "%a, %d.%m.%Y %H:%M:%S", ptm)) + this->m_cachedData.emplace_back("__time32_t", buffer); + else + this->m_cachedData.emplace_back("__time32_t", "Invalid"); + } + + { + std::tm * ptm = _localtime64(&this->m_previewData.time64); + char buffer[64]; + if (std::strftime(buffer, 64, "%a, %d.%m.%Y %H:%M:%S", ptm) != 0) + this->m_cachedData.emplace_back("__time64_t", buffer); + else + this->m_cachedData.emplace_back("__time64_t", "Invalid"); + } + + this->m_cachedData.emplace_back("GUID", hex::format("{%08lX-%04hX-%04hX-%02hhX%02hhX-%02hhX%02hhX%02hhX%02hhX%02hhX%02hhX}", + this->m_previewData.guid.data1, this->m_previewData.guid.data2, this->m_previewData.guid.data3, + this->m_previewData.guid.data4[0], this->m_previewData.guid.data4[1], this->m_previewData.guid.data4[2], this->m_previewData.guid.data4[3], + this->m_previewData.guid.data4[4], this->m_previewData.guid.data4[5], this->m_previewData.guid.data4[6], this->m_previewData.guid.data4[7])); + } + + + if (ImGui::Begin("Data Preview", &this->m_windowOpen)) { + if (this->m_dataProvider != nullptr && this->m_dataProvider->isReadable()) { + if (ImGui::BeginChild("##scrolling")) { + if (ImGui::BeginTable("##datainspector", 2, ImGuiTableFlags_Borders | ImGuiTableFlags_Resizable | ImGuiTableFlags_RowBg)) { + ImGui::TableSetupColumn("Name"); + ImGui::TableSetupColumn("Value"); + + ImGui::TableHeadersRow(); + u32 rowCount = 0; + for (const auto &[name, value] : this->m_cachedData) { + ImGui::TableNextRow(); + ImGui::TableNextColumn(); + ImGui::TextUnformatted(name.c_str()); + ImGui::TableNextColumn(); + ImGui::TextUnformatted(value.c_str()); + ImGui::TableSetBgColor(ImGuiTableBgTarget_RowBg0, + ((rowCount % 2) == 0) ? 0xFF101010 : 0xFF303030); + rowCount++; + } + + { + ImGui::TableNextRow(); + ImGui::TableNextColumn(); + ImGui::TextUnformatted("RGBA Color"); + ImGui::TableNextColumn(); + ImGui::ColorButton("##nolabel", ImColor(this->m_previewData.unsigned32), + ImGuiColorEditFlags_None, ImVec2(ImGui::GetColumnWidth(), 15)); + ImGui::TableSetBgColor(ImGuiTableBgTarget_RowBg0, + ((rowCount % 2) == 0) ? 0xFF101010 : 0xFF303030); + rowCount++; + } + + + ImGui::EndTable(); + } + } + ImGui::EndChild(); + } + } + ImGui::End(); + } + + void ViewDataInspector::createMenu() { + if (ImGui::BeginMenu("View")) { + ImGui::MenuItem("Data Preview View", "", &this->m_windowOpen); + ImGui::EndMenu(); + } + } + +} \ No newline at end of file diff --git a/source/views/view_pattern.cpp b/source/views/view_pattern.cpp index 175b5ed6b..dd091eff0 100644 --- a/source/views/view_pattern.cpp +++ b/source/views/view_pattern.cpp @@ -96,10 +96,12 @@ namespace hex { return; if (ImGui::Begin("Pattern", &this->m_windowOpen, ImGuiWindowFlags_None)) { - this->m_textEditor.Render("Pattern"); + if (this->m_dataProvider != nullptr && this->m_dataProvider->isAvailable()) { + this->m_textEditor.Render("Pattern"); - if (this->m_textEditor.IsTextChanged()) { - this->parsePattern(this->m_textEditor.GetText().data()); + if (this->m_textEditor.IsTextChanged()) { + this->parsePattern(this->m_textEditor.GetText().data()); + } } } ImGui::End();