mirror of
https://github.com/WerWolv/ImHex.git
synced 2026-03-30 21:05:56 -05:00
feat: Added simple insert mode to hex editor
This commit is contained in:
@@ -79,6 +79,7 @@ namespace hex::prv::undo {
|
||||
for (u32 i = 0; i < count; i += 1) {
|
||||
i64 index = startIndex + i;
|
||||
|
||||
m_undoStack[index]->undo(m_provider);
|
||||
operation->addOperation(std::move(m_undoStack[index]));
|
||||
}
|
||||
|
||||
|
||||
@@ -776,6 +776,7 @@
|
||||
"hex.builtin.view.hex_editor.menu.edit.cut": "Cut",
|
||||
"hex.builtin.view.hex_editor.menu.edit.fill": "Fill...",
|
||||
"hex.builtin.view.hex_editor.menu.edit.insert": "Insert...",
|
||||
"hex.builtin.view.hex_editor.menu.edit.insert_mode": "Insert Mode",
|
||||
"hex.builtin.view.hex_editor.menu.edit.jump_to": "Jump to",
|
||||
"hex.builtin.view.hex_editor.menu.edit.jump_to.curr_pattern": "Current Pattern",
|
||||
"hex.builtin.view.hex_editor.menu.edit.open_in_new_provider": "Open selection view...",
|
||||
|
||||
@@ -1117,7 +1117,7 @@ namespace hex::plugin::builtin {
|
||||
/* Remove */
|
||||
ContentRegistry::Interface::addMenuItem({ "hex.builtin.menu.edit", "hex.builtin.view.hex_editor.menu.edit.remove" }, ICON_VS_CLEAR_ALL, 1800, Shortcut::None,
|
||||
[this] {
|
||||
auto selection = ImHexApi::HexEditor::getSelection();
|
||||
auto selection = ImHexApi::HexEditor::getSelection();
|
||||
|
||||
this->openPopup<PopupRemove>(selection->getStartAddress(), selection->getSize());
|
||||
},
|
||||
@@ -1126,12 +1126,30 @@ namespace hex::plugin::builtin {
|
||||
/* Fill */
|
||||
ContentRegistry::Interface::addMenuItem({ "hex.builtin.menu.edit", "hex.builtin.view.hex_editor.menu.edit.fill" }, ICON_VS_PAINTCAN, 1810, Shortcut::None,
|
||||
[this] {
|
||||
auto selection = ImHexApi::HexEditor::getSelection();
|
||||
auto selection = ImHexApi::HexEditor::getSelection();
|
||||
|
||||
this->openPopup<PopupFill>(selection->getStartAddress(), selection->getSize());
|
||||
},
|
||||
[] { return ImHexApi::HexEditor::isSelectionValid() && ImHexApi::Provider::isValid() && ImHexApi::Provider::get()->isWritable(); });
|
||||
|
||||
/* Toggle Overwrite/Insert mode */
|
||||
ContentRegistry::Interface::addMenuItem({ "hex.builtin.menu.edit", "hex.builtin.view.hex_editor.menu.edit.insert_mode" }, ICON_VS_PENCIL, 1820, Shortcut::None,
|
||||
[this] {
|
||||
if (m_hexEditor.getMode() == ui::HexEditor::Mode::Insert)
|
||||
m_hexEditor.setMode(ui::HexEditor::Mode::Overwrite);
|
||||
else
|
||||
m_hexEditor.setMode(ui::HexEditor::Mode::Insert);
|
||||
},
|
||||
[] {
|
||||
return ImHexApi::HexEditor::isSelectionValid() &&
|
||||
ImHexApi::Provider::isValid() &&
|
||||
ImHexApi::Provider::get()->isWritable() &&
|
||||
ImHexApi::Provider::get()->isResizable();
|
||||
},
|
||||
[this] {
|
||||
return m_hexEditor.getMode() == ui::HexEditor::Mode::Insert;
|
||||
});
|
||||
|
||||
/* Jump to */
|
||||
ContentRegistry::Interface::addMenuItemSubMenu({ "hex.builtin.menu.edit", "hex.builtin.view.hex_editor.menu.edit.jump_to" }, ICON_VS_DEBUG_STEP_OUT, 1850,
|
||||
[] {
|
||||
|
||||
@@ -156,6 +156,11 @@ namespace hex::ui {
|
||||
EventRegionSelected::post(ImHexApi::HexEditor::ProviderRegion{ { selection.address, selection.size }, m_provider });
|
||||
m_shouldModifyValue = true;
|
||||
}
|
||||
|
||||
if (m_mode == Mode::Insert) {
|
||||
m_selectionStart = m_selectionEnd;
|
||||
m_cursorBlinkTimer = -0.3F;
|
||||
}
|
||||
}
|
||||
|
||||
[[nodiscard]] Region getSelection() const {
|
||||
@@ -294,6 +299,26 @@ namespace hex::ui {
|
||||
m_editingAddress = std::nullopt;
|
||||
}
|
||||
|
||||
enum class Mode { 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
|
||||
if (!m_provider->isResizable())
|
||||
return;
|
||||
|
||||
// Get rid of any selection in insert mode
|
||||
m_selectionStart = m_selectionEnd;
|
||||
m_cursorPosition = m_selectionEnd;
|
||||
m_selectionChanged = true;
|
||||
}
|
||||
|
||||
m_mode = mode;
|
||||
}
|
||||
|
||||
[[nodiscard]] Mode getMode() const {
|
||||
return m_mode;
|
||||
}
|
||||
|
||||
private:
|
||||
prv::Provider *m_provider = nullptr;
|
||||
|
||||
@@ -346,6 +371,9 @@ namespace hex::ui {
|
||||
static void defaultTooltipCallback(u64, const u8 *, size_t) { }
|
||||
std::function<std::optional<color_t>(u64, const u8 *, size_t)> m_foregroundColorCallback = defaultColorCallback, m_backgroundColorCallback = defaultColorCallback;
|
||||
std::function<void(u64, const u8 *, size_t)> m_tooltipCallback = defaultTooltipCallback;
|
||||
|
||||
Mode m_mode = Mode::Overwrite;
|
||||
float m_cursorBlinkTimer = -0.3F;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
@@ -91,6 +91,9 @@ 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 (isSelectionValid()) {
|
||||
auto selection = getSelection();
|
||||
|
||||
@@ -287,7 +290,13 @@ namespace hex::ui {
|
||||
m_enteredEditingMode = true;
|
||||
|
||||
m_editingBytes.resize(size);
|
||||
std::memcpy(m_editingBytes.data(), data, size);
|
||||
if (m_mode == Mode::Overwrite)
|
||||
std::memcpy(m_editingBytes.data(), data, size);
|
||||
else if (m_mode == Mode::Insert) {
|
||||
std::memset(m_editingBytes.data(), 0x00, size);
|
||||
m_provider->insert(address, size);
|
||||
}
|
||||
|
||||
m_editingCellType = cellType;
|
||||
}
|
||||
}
|
||||
@@ -342,9 +351,20 @@ namespace hex::ui {
|
||||
|
||||
if (nextEditingAddress >= m_provider->getBaseAddress() + m_provider->getCurrentPageAddress() + m_provider->getSize())
|
||||
m_editingAddress = std::nullopt;
|
||||
else
|
||||
else {
|
||||
m_editingAddress = nextEditingAddress;
|
||||
|
||||
if (m_mode == Mode::Insert) {
|
||||
std::memset(m_editingBytes.data(), 0x00, size);
|
||||
m_provider->getUndoStack().groupOperations(2, "hex.builtin.undo_operation.insert");
|
||||
m_provider->insert(nextEditingAddress, size);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (m_mode == Mode::Insert) {
|
||||
m_provider->undo();
|
||||
}
|
||||
|
||||
m_editingAddress = std::nullopt;
|
||||
}
|
||||
|
||||
@@ -379,21 +399,34 @@ namespace hex::ui {
|
||||
|
||||
const color_t SelectionFrameColor = ImGui::GetColorU32(ImGuiCol_Text);
|
||||
|
||||
// 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);
|
||||
switch (m_mode) {
|
||||
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);
|
||||
|
||||
// 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);
|
||||
// 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);
|
||||
|
||||
// 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);
|
||||
// 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);
|
||||
|
||||
// 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);
|
||||
// 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);
|
||||
|
||||
break;
|
||||
}
|
||||
case Mode::Insert: {
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void HexEditor::drawEditor(const ImVec2 &size) {
|
||||
@@ -422,6 +455,9 @@ namespace hex::ui {
|
||||
ImGuiExt::TextFormattedCentered("{}", "hex.ui.hex_editor.no_bytes"_lang);
|
||||
}
|
||||
|
||||
if (!m_editingAddress.has_value() && ImGui::IsKeyPressed(ImGuiKey_Escape))
|
||||
m_mode = Mode::Overwrite;
|
||||
|
||||
Region hoveredCell = Region::Invalid();
|
||||
if (ImGui::BeginChild("Hex View", size, ImGuiChildFlags_None, ImGuiWindowFlags_NoScrollbar | ImGuiWindowFlags_NoScrollWithMouse)) {
|
||||
this->drawScrollbar(CharacterSize);
|
||||
@@ -898,6 +934,11 @@ namespace hex::ui {
|
||||
// Human-readable units
|
||||
ImGuiExt::DimmedIconToggle(ICON_VS_SYMBOL_NUMERIC, &m_showHumanReadableUnits);
|
||||
ImGuiExt::InfoTooltip("hex.ui.hex_editor.human_readable_units_footer"_lang);
|
||||
|
||||
ImGui::SameLine(0, 10_scaled);
|
||||
if (m_mode == Mode::Insert) {
|
||||
ImGui::TextUnformatted("[ INSERT ]");
|
||||
}
|
||||
}
|
||||
|
||||
// Collapse button
|
||||
@@ -1045,6 +1086,8 @@ namespace hex::ui {
|
||||
this->drawFooter(footerSize);
|
||||
|
||||
m_selectionChanged = false;
|
||||
|
||||
m_cursorBlinkTimer += ImGui::GetIO().DeltaTime;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user