/* * Copyright (c) 2018-2020, Andreas Kling * Copyright (c) 2021, Mustafa Quraish * Copyright (c) 2022, the SerenityOS developers. * Copyright (c) 2022, Timothy Slater * * SPDX-License-Identifier: BSD-2-Clause */ #pragma once #include "HexDocument.h" #include "SearchResultsModel.h" #include "Selection.h" #include #include #include #include #include #include #include #include #include namespace HexEditor { class HexEditor : public GUI::AbstractScrollableWidget { C_OBJECT(HexEditor) public: enum EditMode { Hex, Text }; virtual ~HexEditor() override = default; size_t buffer_size() const { return m_document->size(); } ErrorOr open_new_file(size_t size); void open_file(NonnullOwnPtr file); ErrorOr fill_selection(u8 fill_byte); Optional get_byte(size_t position); ByteBuffer get_selected_bytes(); ErrorOr save_as(NonnullOwnPtr); ErrorOr save(); bool undo(); bool redo(); GUI::UndoStack& undo_stack(); void select_all(); Selection const& selection() const { return m_selection; } bool has_selection() const { return !m_selection.is_empty() && m_document->size() > 0; } size_t selection_start_offset() const { return m_selection.start; } bool copy_selected_text_to_clipboard(); bool copy_selected_hex_to_clipboard(); bool copy_selected_hex_to_clipboard_as_c_code(); size_t bytes_per_row() const { return m_bytes_per_row; } void set_bytes_per_row(size_t); void set_position(size_t position); void set_selection(size_t position, size_t length); void highlight(size_t start, size_t end); Optional find(ByteBuffer& needle, size_t start = 0); Optional find_and_highlight(ByteBuffer& needle, size_t start = 0); Vector find_all(ByteBuffer& needle, size_t start = 0); Vector find_all_strings(size_t min_length = 4); Function on_status_change; Function on_change; void show_create_annotation_dialog(); void show_edit_annotation_dialog(Annotation&); void show_delete_annotation_dialog(Annotation&); HexDocument& document() { return *m_document; } protected: HexEditor(); virtual void paint_event(GUI::PaintEvent&) override; virtual void mousedown_event(GUI::MouseEvent&) override; virtual void mouseup_event(GUI::MouseEvent&) override; virtual void mousemove_event(GUI::MouseEvent&) override; virtual void keydown_event(GUI::KeyEvent&) override; virtual void context_menu_event(GUI::ContextMenuEvent&) override; virtual void theme_change_event(GUI::ThemeChangeEvent&) override; private: size_t m_line_spacing { 4 }; size_t m_content_length { 0 }; size_t m_bytes_per_row { 16 }; bool m_in_drag_select { false }; Selection m_selection; size_t m_position { 0 }; bool m_cursor_at_low_nibble { false }; EditMode m_edit_mode { Hex }; NonnullOwnPtr m_document; GUI::UndoStack m_undo_stack; Optional m_hovered_annotation; RefPtr m_context_menu; RefPtr m_add_annotation_action; RefPtr m_edit_annotation_action; RefPtr m_delete_annotation_action; static constexpr int m_padding = 5; void scroll_position_into_view(size_t position); size_t total_rows() const { return ceil_div(m_content_length, m_bytes_per_row); } size_t line_height() const { return font().pixel_size_rounded_up() + m_line_spacing; } size_t character_width() const { return font().glyph_fixed_width(); } size_t cell_width() const { return character_width() * 3; } int offset_area_width() const { return m_padding + font().width_rounded_up("0X12345678"sv) + m_padding; } int hex_area_width() const { return m_padding + m_bytes_per_row * cell_width() + m_padding; } int text_area_width() const { return m_padding + m_bytes_per_row * character_width() + m_padding; } struct OffsetData { size_t offset; EditMode panel; }; Optional offset_at(Gfx::IntPoint position) const; ErrorOr hex_mode_keydown_event(GUI::KeyEvent&); ErrorOr text_mode_keydown_event(GUI::KeyEvent&); void set_content_length(size_t); void update_content_size(); void update_status(); void did_change(); ErrorOr did_complete_action(size_t position, u8 old_value, u8 new_value); ErrorOr did_complete_action(size_t position, ByteBuffer&& old_values, ByteBuffer&& new_values); }; }