mirror of https://github.com/WerWolv/ImHex.git
fix: Visual glitches with highlights and selections in the hex editor view
This commit is contained in:
parent
ca17054a1e
commit
c69d3bc7f4
|
@ -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;
|
||||
|
|
|
@ -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());
|
||||
}
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue