fix: Visual glitches with highlights and selections in the hex editor view

This commit is contained in:
WerWolv 2024-05-15 18:26:15 +02:00
parent ca17054a1e
commit c69d3bc7f4
2 changed files with 37 additions and 35 deletions

View File

@ -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<u64> m_cursorPosition;
ScrollPosition m_scrollPosition;
Region m_frameStartSelectionRegion = Region::Invalid();
u16 m_bytesPerRow = 16;
std::endian m_dataVisualizerEndianness = std::endian::little;
std::shared_ptr<ContentRegistry::HexEditor::DataVisualizer> m_currDataVisualizer;

View File

@ -1,3 +1,4 @@
#include <algorithm>
#include <ui/hex_editor.hpp>
#include <hex/api/content_registry.hpp>
@ -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<void*>(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<char, 2> 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<UserData*>(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<color_t> HexEditor::applySelectionColor(u64 byteAddress, std::optional<color_t> 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());
}
}