From c69d3bc7f4eb4b1bf4f8b986271e8a211ad64f7c Mon Sep 17 00:00:00 2001 From: WerWolv Date: Wed, 15 May 2024 18:26:15 +0200 Subject: [PATCH] fix: Visual glitches with highlights and selections in the hex editor view --- plugins/ui/include/ui/hex_editor.hpp | 16 +++++--- plugins/ui/source/ui/hex_editor.cpp | 56 +++++++++++++--------------- 2 files changed, 37 insertions(+), 35 deletions(-) diff --git a/plugins/ui/include/ui/hex_editor.hpp b/plugins/ui/include/ui/hex_editor.hpp index 1329ab723..15688d80e 100644 --- a/plugins/ui/include/ui/hex_editor.hpp +++ b/plugins/ui/include/ui/hex_editor.hpp @@ -38,7 +38,7 @@ namespace hex::ui { return m_unsyncedPosition.get(m_provider); } - const ImS64& get() const { + [[nodiscard]] const ImS64& get() const { if (m_synced) return m_syncedPosition; else @@ -73,7 +73,6 @@ namespace hex::ui { class HexEditor { public: explicit HexEditor(prv::Provider *provider = nullptr); - ~HexEditor(); void draw(float height = ImGui::GetContentRegionAvail().y); HexEditor(const HexEditor&) = default; @@ -87,13 +86,14 @@ namespace hex::ui { m_currValidRegion = { Region::Invalid(), false }; m_scrollPosition.setProvider(provider); } - prv::Provider* getProvider() const { + + [[nodiscard]] prv::Provider* getProvider() const { return m_provider; } void setUnknownDataCharacter(char character) { m_unknownDataCharacter = character; } private: - enum class CellType { None, Hex, ASCII }; + enum class CellType : u8 { None, Hex, ASCII }; void drawCell(u64 address, const u8 *data, size_t size, bool hovered, CellType cellType); void drawSelectionFrame(u32 x, u32 y, Region selection, u64 byteAddress, u16 bytesPerCell, const ImVec2 &cellPos, const ImVec2 &cellSize, const ImColor &backgroundColor) const; @@ -299,7 +299,11 @@ namespace hex::ui { m_editingAddress = std::nullopt; } - enum class Mode { Overwrite, Insert }; + enum class Mode : u8 { + Overwrite, + Insert + }; + void setMode(Mode mode) { if (mode == Mode::Insert) { // Don't enter insert mode if the provider doesn't support resizing the underlying data @@ -327,6 +331,8 @@ namespace hex::ui { std::optional m_cursorPosition; ScrollPosition m_scrollPosition; + Region m_frameStartSelectionRegion = Region::Invalid(); + u16 m_bytesPerRow = 16; std::endian m_dataVisualizerEndianness = std::endian::little; std::shared_ptr m_currDataVisualizer; diff --git a/plugins/ui/source/ui/hex_editor.cpp b/plugins/ui/source/ui/hex_editor.cpp index c619d7718..3befd5d76 100644 --- a/plugins/ui/source/ui/hex_editor.cpp +++ b/plugins/ui/source/ui/hex_editor.cpp @@ -1,3 +1,4 @@ +#include #include #include @@ -24,7 +25,7 @@ namespace hex::ui { if (size == 1) { const u8 c = data[0]; - if (std::isprint(c)) + if (std::isprint(c) != 0) ImGui::Text("%c", c); else ImGui::TextDisabled("."); @@ -53,8 +54,8 @@ namespace hex::ui { ImGui::PushID(reinterpret_cast(address)); ON_SCOPE_EXIT { ImGui::PopID(); }; - char buffer[2] = { std::isprint(data[0]) ? char(data[0]) : '.', 0x00 }; - ImGui::InputText("##editing_input", buffer, 2, TextInputFlags | ImGuiInputTextFlags_CallbackEdit, [](ImGuiInputTextCallbackData *data) -> int { + std::array buffer = { std::isprint(data[0]) != 0 ? char(data[0]) : '.', 0x00 }; + ImGui::InputText("##editing_input", buffer.data(), buffer.size(), TextInputFlags | ImGuiInputTextFlags_CallbackEdit, [](ImGuiInputTextCallbackData *data) -> int { auto &userData = *static_cast(data->UserData); if (data->BufTextLen >= userData.maxChars) { @@ -78,10 +79,6 @@ namespace hex::ui { } - HexEditor::~HexEditor() { - - } - constexpr static u16 getByteColumnSeparatorCount(u16 columnCount) { return (columnCount - 1) / 8; } @@ -91,17 +88,16 @@ namespace hex::ui { } std::optional HexEditor::applySelectionColor(u64 byteAddress, std::optional color) { - if (m_mode == Mode::Insert) - return color.value_or(0); + if (m_mode == Mode::Overwrite) { + if (m_frameStartSelectionRegion != Region::Invalid()) { + auto selection = m_frameStartSelectionRegion; - if (isSelectionValid()) { - auto selection = getSelection(); - - if (byteAddress >= selection.getStartAddress() && byteAddress <= selection.getEndAddress()) { - if (color.has_value()) - color = (ImAlphaBlendColors(color.value(), m_selectionColor)) & 0x00FFFFFF; - else - color = m_selectionColor; + if (byteAddress >= selection.getStartAddress() && byteAddress <= selection.getEndAddress()) { + if (color.has_value()) + color = (ImAlphaBlendColors(color.value(), m_selectionColor)) & 0x00FFFFFF; + else + color = m_selectionColor; + } } } @@ -130,7 +126,7 @@ namespace hex::ui { const auto [decoded, advance] = encodingFile.getEncodingFor(buffer); const ImColor color = [&]{ - if (decoded.length() == 1 && std::isalnum(decoded[0])) + if (decoded.length() == 1 && std::isalnum(decoded[0]) != 0) return ImGuiExt::GetCustomColorU32(ImGuiCustomCol_AdvancedEncodingASCII); else if (decoded.length() == 1 && advance == 1) return ImGuiExt::GetCustomColorU32(ImGuiCustomCol_AdvancedEncodingSingleChar); @@ -403,27 +399,27 @@ namespace hex::ui { case Mode::Overwrite: { // Draw vertical line at the left of first byte and the start of the line if (x == 0 || byteAddress == selection.getStartAddress()) - drawList->AddLine(cellPos, cellPos + ImVec2(0, cellSize.y), ImColor(SelectionFrameColor), 1_scaled); + drawList->AddLine(ImTrunc(cellPos), ImTrunc(cellPos + ImVec2(0, cellSize.y)), ImColor(SelectionFrameColor), 1_scaled); // Draw vertical line at the right of the last byte and the end of the line if (x == u16((m_bytesPerRow / bytesPerCell) - 1) || (byteAddress + bytesPerCell) > selection.getEndAddress()) - drawList->AddLine(cellPos + ImVec2(cellSize.x, -1), cellPos + cellSize, ImColor(SelectionFrameColor), 1_scaled); + drawList->AddLine(ImTrunc(cellPos + ImVec2(cellSize.x, 0)), ImTrunc(cellPos + cellSize), ImColor(SelectionFrameColor), 1_scaled); // Draw horizontal line at the top of the bytes if (y == 0 || (byteAddress - m_bytesPerRow) < selection.getStartAddress()) - drawList->AddLine(cellPos, cellPos + ImVec2(cellSize.x + 1, 0), ImColor(SelectionFrameColor), 1_scaled); + drawList->AddLine(ImTrunc(cellPos), ImTrunc(cellPos + ImVec2(cellSize.x, 0)), ImColor(SelectionFrameColor), 1_scaled); // Draw horizontal line at the bottom of the bytes if ((byteAddress + m_bytesPerRow) > selection.getEndAddress()) - drawList->AddLine(cellPos + ImVec2(0, cellSize.y), cellPos + cellSize + ImVec2(1, 0), ImColor(SelectionFrameColor), 1_scaled); + drawList->AddLine(ImTrunc(cellPos + ImVec2(0, cellSize.y)), ImTrunc(cellPos + cellSize + scaled({ 1, 0 })), ImColor(SelectionFrameColor), 1_scaled); break; } case Mode::Insert: { - bool cursorVisible = (!ImGui::GetIO().ConfigInputTextCursorBlink) || (m_cursorBlinkTimer <= 0.0f) || std::fmod(m_cursorBlinkTimer, 1.20f) <= 0.80f; + bool cursorVisible = (!ImGui::GetIO().ConfigInputTextCursorBlink) || (m_cursorBlinkTimer <= 0.0F) || std::fmod(m_cursorBlinkTimer, 1.20F) <= 0.80F; if (cursorVisible && byteAddress == selection.getStartAddress()) { // Draw vertical line at the left of first byte and the start of the line - drawList->AddLine(cellPos, cellPos + ImVec2(0, cellSize.y), ImColor(SelectionFrameColor), 1_scaled); + drawList->AddLine(ImTrunc(cellPos), ImTrunc(cellPos + ImVec2(0, cellSize.y)), ImColor(SelectionFrameColor), 1_scaled); } } } @@ -450,6 +446,7 @@ namespace hex::ui { } const auto selection = getSelection(); + m_frameStartSelectionRegion = selection; if (m_provider == nullptr || m_provider->getActualSize() == 0) { ImGuiExt::TextFormattedCentered("{}", "hex.ui.hex_editor.no_bytes"_lang); @@ -799,13 +796,13 @@ namespace hex::ui { // Scroll to the cursor if it's either at the top or bottom edge of the screen if (m_shouldScrollToSelection && isSelectionValid()) { // Make sure simply clicking on a byte at the edge of the screen won't cause scrolling - if ((ImGui::IsMouseDragging(ImGuiMouseButton_Left) && *m_selectionStart != *m_selectionEnd)) { - if (y == (m_scrollPosition + 3)) { - if (i128(m_selectionEnd.value() - m_provider->getBaseAddress() - m_provider->getCurrentPageAddress()) <= (ImS64(m_scrollPosition + 3) * m_bytesPerRow)) { + if ((ImGui::IsMouseDragging(ImGuiMouseButton_Left))) { + if ((*m_selectionStart >= (*m_selectionEnd + m_bytesPerRow)) && y == (m_scrollPosition + 1)) { + if (i128(m_selectionEnd.value() - m_provider->getBaseAddress() - m_provider->getCurrentPageAddress()) <= (ImS64(m_scrollPosition + 1) * m_bytesPerRow)) { m_shouldScrollToSelection = false; m_scrollPosition -= 3; } - } else if (y == ((m_scrollPosition + m_visibleRowCount) - 1)) { + } else if ((*m_selectionStart <= (*m_selectionEnd - m_bytesPerRow)) && y == ((m_scrollPosition + m_visibleRowCount) - 1)) { if (i128(m_selectionEnd.value() - m_provider->getBaseAddress() - m_provider->getCurrentPageAddress()) >= (ImS64((m_scrollPosition + m_visibleRowCount) - 2) * m_bytesPerRow)) { m_shouldScrollToSelection = false; m_scrollPosition += 3; @@ -993,8 +990,7 @@ namespace hex::ui { m_currDataVisualizer = visualizer; m_encodingLineStartAddresses.clear(); - if (m_bytesPerRow < visualizer->getBytesPerCell()) - m_bytesPerRow = visualizer->getBytesPerCell(); + m_bytesPerRow = std::max(m_bytesPerRow, visualizer->getBytesPerCell()); } }