2020-11-10 14:26:38 +00:00
|
|
|
#pragma once
|
|
|
|
|
2022-05-27 18:42:07 +00:00
|
|
|
#include <hex/api/content_registry.hpp>
|
|
|
|
|
2022-02-01 17:09:40 +00:00
|
|
|
#include <hex/ui/view.hpp>
|
2022-05-27 18:42:07 +00:00
|
|
|
#include <hex/helpers/concepts.hpp>
|
2021-12-07 21:47:41 +00:00
|
|
|
#include <hex/helpers/encoding_file.hpp>
|
2020-11-10 14:26:38 +00:00
|
|
|
|
2022-05-27 18:42:07 +00:00
|
|
|
#include <algorithm>
|
|
|
|
#include <limits>
|
2021-12-07 21:47:41 +00:00
|
|
|
|
|
|
|
namespace hex::plugin::builtin {
|
2020-11-10 14:26:38 +00:00
|
|
|
|
|
|
|
class ViewHexEditor : public View {
|
|
|
|
public:
|
2021-04-20 19:46:48 +00:00
|
|
|
ViewHexEditor();
|
2020-11-10 14:26:38 +00:00
|
|
|
|
2020-12-22 17:10:01 +00:00
|
|
|
void drawContent() override;
|
2020-11-10 14:26:38 +00:00
|
|
|
|
|
|
|
private:
|
2022-05-27 18:42:07 +00:00
|
|
|
constexpr static auto InvalidSelection = std::numeric_limits<u64>::max();
|
2020-11-12 20:20:51 +00:00
|
|
|
|
2022-05-27 18:42:07 +00:00
|
|
|
void registerShortcuts();
|
|
|
|
void registerEvents();
|
|
|
|
void registerMenuItems();
|
2020-11-15 22:04:46 +00:00
|
|
|
|
2022-05-27 18:42:07 +00:00
|
|
|
void drawCell(u64 address, u8 *data, size_t size, bool hovered);
|
|
|
|
void drawPopup();
|
|
|
|
void drawSelectionFrame(u32 x, u32 y, u64 byteAddress, u16 bytesPerCell, const ImVec2 &cellPos, const ImVec2 &cellSize);
|
2020-11-15 22:04:46 +00:00
|
|
|
|
2022-05-27 18:42:07 +00:00
|
|
|
public:
|
|
|
|
void setSelection(const Region ®ion) { this->setSelection(region.getStartAddress(), region.getEndAddress()); }
|
2022-06-19 13:09:38 +00:00
|
|
|
void setSelection(u128 start, u128 end) {
|
2022-06-14 09:58:50 +00:00
|
|
|
if (!ImHexApi::Provider::isValid())
|
|
|
|
return;
|
|
|
|
if (start == InvalidSelection && end == InvalidSelection)
|
|
|
|
return;
|
|
|
|
|
|
|
|
if (start == InvalidSelection)
|
|
|
|
start = end;
|
|
|
|
if (end == InvalidSelection)
|
|
|
|
end = start;
|
2020-11-12 08:38:52 +00:00
|
|
|
|
2022-07-23 18:46:20 +00:00
|
|
|
auto provider = ImHexApi::Provider::get();
|
|
|
|
|
|
|
|
const size_t maxAddress = provider->getActualSize() + provider->getBaseAddress() - 1;
|
2021-01-11 12:50:04 +00:00
|
|
|
|
2022-05-27 18:42:07 +00:00
|
|
|
this->m_selectionChanged = this->m_selectionStart != start || this->m_selectionEnd != end;
|
2020-11-12 08:38:52 +00:00
|
|
|
|
2022-06-19 13:09:38 +00:00
|
|
|
this->m_selectionStart = std::clamp<u128>(start, 0, maxAddress);
|
|
|
|
this->m_selectionEnd = std::clamp<u128>(end, 0, maxAddress);
|
2020-12-01 01:21:40 +00:00
|
|
|
|
2022-05-27 18:42:07 +00:00
|
|
|
if (this->m_selectionChanged) {
|
|
|
|
EventManager::post<EventRegionSelected>(this->getSelection());
|
|
|
|
}
|
|
|
|
}
|
2021-02-14 00:11:55 +00:00
|
|
|
|
2022-05-27 18:42:07 +00:00
|
|
|
[[nodiscard]] Region getSelection() const {
|
|
|
|
const auto start = std::min(this->m_selectionStart, this->m_selectionEnd);
|
|
|
|
const auto end = std::max(this->m_selectionStart, this->m_selectionEnd);
|
|
|
|
const size_t size = end - start + 1;
|
2022-02-03 23:29:47 +00:00
|
|
|
|
2022-05-27 18:42:07 +00:00
|
|
|
return { start, size };
|
|
|
|
}
|
2022-01-09 20:27:59 +00:00
|
|
|
|
2022-05-27 18:42:07 +00:00
|
|
|
[[nodiscard]] bool isSelectionValid() const {
|
|
|
|
return this->m_selectionStart != InvalidSelection && this->m_selectionEnd != InvalidSelection;
|
|
|
|
}
|
2022-02-13 19:13:59 +00:00
|
|
|
|
2022-05-27 18:42:07 +00:00
|
|
|
void jumpToSelection() {
|
|
|
|
this->m_shouldJumpToSelection = true;
|
|
|
|
}
|
2020-11-15 22:04:46 +00:00
|
|
|
|
2022-05-27 18:42:07 +00:00
|
|
|
void scrollToSelection() {
|
|
|
|
this->m_shouldScrollToSelection = true;
|
|
|
|
}
|
2020-11-20 10:57:14 +00:00
|
|
|
|
2022-05-28 20:31:40 +00:00
|
|
|
void jumpIfOffScreen() {
|
|
|
|
this->m_shouldJumpWhenOffScreen = true;
|
|
|
|
}
|
|
|
|
|
2022-05-27 18:42:07 +00:00
|
|
|
public:
|
|
|
|
class Popup {
|
|
|
|
public:
|
|
|
|
virtual ~Popup() = default;
|
|
|
|
virtual void draw(ViewHexEditor *editor) = 0;
|
|
|
|
};
|
2020-11-15 23:07:42 +00:00
|
|
|
|
2022-05-27 18:42:07 +00:00
|
|
|
[[nodiscard]] bool isAnyPopupOpen() const {
|
|
|
|
return this->m_currPopup != nullptr;
|
|
|
|
}
|
|
|
|
|
|
|
|
template<std::derived_from<Popup> T>
|
|
|
|
[[nodiscard]] bool isPopupOpen() const {
|
|
|
|
return dynamic_cast<T*>(this->m_currPopup.get()) != nullptr;
|
|
|
|
}
|
|
|
|
|
|
|
|
template<std::derived_from<Popup> T, typename ... Args>
|
|
|
|
void openPopup(Args && ...args) {
|
|
|
|
this->m_currPopup = std::make_unique<T>(std::forward<Args>(args)...);
|
|
|
|
this->m_shouldOpenPopup = true;
|
|
|
|
}
|
|
|
|
|
|
|
|
void closePopup() {
|
|
|
|
this->m_currPopup.reset();
|
|
|
|
}
|
|
|
|
|
|
|
|
private:
|
|
|
|
void drawEditor(const ImVec2 &size);
|
|
|
|
void drawFooter(const ImVec2 &size);
|
|
|
|
|
|
|
|
void handleSelection(u64 address, u32 bytesPerCell, const u8 *data, bool cellHovered);
|
|
|
|
|
|
|
|
private:
|
|
|
|
u16 m_bytesPerRow = 16;
|
|
|
|
|
|
|
|
ContentRegistry::HexEditor::DataVisualizer *m_currDataVisualizer;
|
|
|
|
|
|
|
|
bool m_shouldJumpToSelection = false;
|
|
|
|
bool m_shouldScrollToSelection = false;
|
2022-05-28 20:31:40 +00:00
|
|
|
bool m_shouldJumpWhenOffScreen = false;
|
2022-05-27 18:42:07 +00:00
|
|
|
|
|
|
|
bool m_selectionChanged = false;
|
|
|
|
u64 m_selectionStart = InvalidSelection;
|
|
|
|
u64 m_selectionEnd = InvalidSelection;
|
|
|
|
|
|
|
|
u16 m_visibleRowCount = 0;
|
|
|
|
|
|
|
|
std::optional<u64> m_editingAddress;
|
|
|
|
bool m_shouldModifyValue = false;
|
|
|
|
bool m_enteredEditingMode = false;
|
2022-06-17 08:16:58 +00:00
|
|
|
bool m_shouldUpdateEditingValue = false;
|
2022-05-27 18:42:07 +00:00
|
|
|
std::vector<u8> m_editingBytes;
|
|
|
|
|
|
|
|
color_t m_selectionColor = 0x00;
|
|
|
|
bool m_upperCaseHex = true;
|
|
|
|
bool m_grayOutZero = true;
|
|
|
|
bool m_showAscii = true;
|
|
|
|
|
|
|
|
bool m_shouldOpenPopup = false;
|
|
|
|
std::unique_ptr<Popup> m_currPopup;
|
|
|
|
|
|
|
|
std::optional<EncodingFile> m_currCustomEncoding;
|
2020-11-10 14:26:38 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
}
|