HexEditor: Port HexEditor to GML compilation

This commit is contained in:
tetektoza 2023-09-28 17:06:49 +02:00 committed by Tim Schumacher
parent bcec05a7cb
commit 935aaab757
15 changed files with 147 additions and 51 deletions

View file

@ -4,24 +4,21 @@ serenity_component(
TARGETS HexEditor
)
stringify_gml(HexEditorWindow.gml HexEditorWindowGML.h hex_editor_window_gml)
stringify_gml(GoToOffsetDialog.gml GoToOffsetDialogGML.h go_to_offset_dialog_gml)
stringify_gml(FindDialog.gml FindDialogGML.h find_dialog_gml)
compile_gml(HexEditorWidget.gml HexEditorWidgetGML.cpp)
compile_gml(GoToOffsetWidget.gml GoToOffsetWidgetGML.cpp)
compile_gml(FindWidget.gml FindWidgetGML.cpp)
set(SOURCES
FindDialog.cpp
FindWidgetGML.cpp
GoToOffsetDialog.cpp
GoToOffsetWidgetGML.cpp
HexDocument.cpp
HexEditor.cpp
HexEditorWidgetGML.cpp
HexEditorWidget.cpp
main.cpp
)
set(GENERATED_SOURCES
FindDialogGML.h
GoToOffsetDialogGML.h
HexEditorWindowGML.h
)
serenity_app(HexEditor ICON app-hex-editor)
target_link_libraries(HexEditor PRIVATE LibCore LibGfx LibGUI LibConfig LibDesktop LibFileSystemAccessClient LibMain LibTextCodec)

View file

@ -8,7 +8,6 @@
#include <AK/Array.h>
#include <AK/Hex.h>
#include <AK/StringView.h>
#include <Applications/HexEditor/FindDialogGML.h>
#include <LibGUI/BoxLayout.h>
#include <LibGUI/Button.h>
#include <LibGUI/MessageBox.h>
@ -32,7 +31,13 @@ static constexpr Array<Option, 2> options = {
GUI::Dialog::ExecResult FindDialog::show(GUI::Window* parent_window, String& out_text, ByteBuffer& out_buffer, bool& find_all)
{
auto dialog = FindDialog::construct();
auto dialog_or_error = FindDialog::try_create();
if (dialog_or_error.is_error()) {
GUI::MessageBox::show(parent_window, "Couldn't load find dialog"sv, "Error while opening find dialog"sv, GUI::MessageBox::Type::Error);
return ExecResult::Aborted;
}
auto dialog = dialog_or_error.release_value();
if (parent_window)
dialog->set_icon(parent_window->icon());
@ -91,7 +96,15 @@ Result<ByteBuffer, String> FindDialog::process_input(String text_value, OptionId
}
}
FindDialog::FindDialog()
ErrorOr<NonnullRefPtr<FindDialog>> FindDialog::try_create()
{
auto find_widget = TRY(HexEditor::FindWidget::try_create());
auto find_dialog = TRY(adopt_nonnull_ref_or_enomem(new (nothrow)
FindDialog(move(find_widget))));
return find_dialog;
}
FindDialog::FindDialog(NonnullRefPtr<HexEditor::FindWidget> find_widget)
: Dialog(nullptr)
{
resize(280, 146);
@ -99,15 +112,14 @@ FindDialog::FindDialog()
set_resizable(false);
set_title("Find");
auto main_widget = set_main_widget<GUI::Widget>();
main_widget->load_from_gml(find_dialog_gml).release_value_but_fixme_should_propagate_errors();
set_main_widget(find_widget);
m_text_editor = *main_widget->find_descendant_of_type_named<GUI::TextBox>("text_editor");
m_find_button = *main_widget->find_descendant_of_type_named<GUI::Button>("find_button");
m_find_all_button = *main_widget->find_descendant_of_type_named<GUI::Button>("find_all_button");
m_cancel_button = *main_widget->find_descendant_of_type_named<GUI::Button>("cancel_button");
m_text_editor = *find_widget->find_descendant_of_type_named<GUI::TextBox>("text_editor");
m_find_button = *find_widget->find_descendant_of_type_named<GUI::Button>("find_button");
m_find_all_button = *find_widget->find_descendant_of_type_named<GUI::Button>("find_all_button");
m_cancel_button = *find_widget->find_descendant_of_type_named<GUI::Button>("cancel_button");
auto& radio_container = *main_widget->find_descendant_of_type_named<GUI::Widget>("radio_container");
auto& radio_container = *find_widget->find_descendant_of_type_named<GUI::Widget>("radio_container");
for (size_t i = 0; i < options.size(); i++) {
auto action = options[i];
auto& radio = radio_container.add<GUI::RadioButton>();

View file

@ -6,6 +6,7 @@
#pragma once
#include "FindWidget.h"
#include <AK/Result.h>
#include <AK/String.h>
#include <LibGUI/Dialog.h>
@ -17,10 +18,11 @@ enum OptionId {
};
class FindDialog : public GUI::Dialog {
C_OBJECT(FindDialog);
C_OBJECT_ABSTRACT(FindDialog);
public:
static ExecResult show(GUI::Window* parent_window, String& out_tex, ByteBuffer& out_buffer, bool& find_all);
static ErrorOr<NonnullRefPtr<FindDialog>> try_create();
private:
Result<ByteBuffer, String> process_input(String text_value, OptionId opt);
@ -29,7 +31,7 @@ private:
OptionId selected_option() const { return m_selected_option; }
bool find_all() const { return m_find_all; }
FindDialog();
FindDialog(NonnullRefPtr<HexEditor::FindWidget> find_widget);
virtual ~FindDialog() override = default;
RefPtr<GUI::TextEditor> m_text_editor;

View file

@ -1,4 +1,4 @@
@GUI::Widget {
@HexEditor::FindWidget {
name: "main"
fixed_width: 280
fixed_height: 146

View file

@ -0,0 +1,23 @@
/*
* Copyright (c) 2023, the SerenityOS developers
*
* SPDX-License-Identifier: BSD-2-Clause
*/
#pragma once
#include <LibGUI/Widget.h>
namespace HexEditor {
class FindWidget : public GUI::Widget {
C_OBJECT_ABSTRACT(FindWidget)
public:
static ErrorOr<NonnullRefPtr<FindWidget>> try_create();
virtual ~FindWidget() override = default;
private:
FindWidget() = default;
};
}

View file

@ -5,7 +5,6 @@
*/
#include "GoToOffsetDialog.h"
#include <Applications/HexEditor/GoToOffsetDialogGML.h>
#include <LibGUI/BoxLayout.h>
#include <LibGUI/Button.h>
#include <LibGUI/ComboBox.h>
@ -18,7 +17,14 @@
GUI::Dialog::ExecResult GoToOffsetDialog::show(GUI::Window* parent_window, int& history_offset, int& out_offset, int selection_offset, int buffer_size)
{
auto dialog = GoToOffsetDialog::construct();
auto dialog_or_error = GoToOffsetDialog::try_create();
if (dialog_or_error.is_error()) {
GUI::MessageBox::show(parent_window, "Couldn't load \"go to offset\" dialog"sv, "Error while opening \"go to offset\" dialog"sv, GUI::MessageBox::Type::Error);
return ExecResult::Aborted;
}
auto dialog = dialog_or_error.release_value();
dialog->m_selection_offset = selection_offset;
dialog->m_buffer_size = buffer_size;
@ -88,7 +94,15 @@ void GoToOffsetDialog::update_statusbar()
m_statusbar->set_text(1, String::formatted("DEC: {}", new_offset).release_value_but_fixme_should_propagate_errors());
}
GoToOffsetDialog::GoToOffsetDialog()
ErrorOr<NonnullRefPtr<GoToOffsetDialog>> GoToOffsetDialog::try_create()
{
auto offset_widget = TRY(HexEditor::GoToOffsetWidget::try_create());
auto offset_dialog = TRY(adopt_nonnull_ref_or_enomem(new (nothrow)
GoToOffsetDialog(move(offset_widget))));
return offset_dialog;
}
GoToOffsetDialog::GoToOffsetDialog(NonnullRefPtr<HexEditor::GoToOffsetWidget> goto_offset_widget)
: Dialog(nullptr)
{
resize(300, 80);
@ -96,14 +110,13 @@ GoToOffsetDialog::GoToOffsetDialog()
set_resizable(false);
set_title("Go to Offset");
auto main_widget = set_main_widget<GUI::Widget>();
main_widget->load_from_gml(go_to_offset_dialog_gml).release_value_but_fixme_should_propagate_errors();
set_main_widget(goto_offset_widget);
m_text_editor = *main_widget->find_descendant_of_type_named<GUI::TextBox>("text_editor");
m_go_button = *main_widget->find_descendant_of_type_named<GUI::Button>("go_button");
m_offset_type_box = *main_widget->find_descendant_of_type_named<GUI::ComboBox>("offset_type");
m_offset_from_box = *main_widget->find_descendant_of_type_named<GUI::ComboBox>("offset_from");
m_statusbar = *main_widget->find_descendant_of_type_named<GUI::Statusbar>("statusbar");
m_text_editor = *goto_offset_widget->find_descendant_of_type_named<GUI::TextBox>("text_editor");
m_go_button = *goto_offset_widget->find_descendant_of_type_named<GUI::Button>("go_button");
m_offset_type_box = *goto_offset_widget->find_descendant_of_type_named<GUI::ComboBox>("offset_type");
m_offset_from_box = *goto_offset_widget->find_descendant_of_type_named<GUI::ComboBox>("offset_from");
m_statusbar = *goto_offset_widget->find_descendant_of_type_named<GUI::Statusbar>("statusbar");
m_offset_type.append("Decimal"sv);
m_offset_type.append("Hexadecimal"sv);

View file

@ -6,18 +6,20 @@
#pragma once
#include "GoToOffsetWidget.h"
#include <AK/Result.h>
#include <AK/Vector.h>
#include <LibGUI/Dialog.h>
class GoToOffsetDialog : public GUI::Dialog {
C_OBJECT(GoToOffsetDialog);
C_OBJECT_ABSTRACT(GoToOffsetDialog);
public:
static ExecResult show(GUI::Window* parent_window, int& history_offset, int& out_offset, int selection_offset, int end);
static ErrorOr<NonnullRefPtr<GoToOffsetDialog>> try_create();
private:
GoToOffsetDialog();
GoToOffsetDialog(NonnullRefPtr<HexEditor::GoToOffsetWidget> goto_offset_widget);
virtual ~GoToOffsetDialog() override = default;
void update_statusbar();
int process_input();

View file

@ -1,4 +1,4 @@
@GUI::Widget {
@HexEditor::GoToOffsetWidget {
name: "main"
fixed_width: 300
fixed_height: 80

View file

@ -0,0 +1,23 @@
/*
* Copyright (c) 2023, the SerenityOS developers
*
* SPDX-License-Identifier: BSD-2-Clause
*/
#pragma once
#include <LibGUI/Widget.h>
namespace HexEditor {
class GoToOffsetWidget : public GUI::Widget {
C_OBJECT_ABSTRACT(GoToOffsetWidget)
public:
static ErrorOr<NonnullRefPtr<GoToOffsetWidget>> try_create();
virtual ~GoToOffsetWidget() override = default;
private:
GoToOffsetWidget() = default;
};
}

View file

@ -30,6 +30,8 @@
#include <string.h>
#include <unistd.h>
namespace HexEditor {
HexEditor::HexEditor()
: m_document(make<HexDocumentMemory>(ByteBuffer::create_zeroed(0).release_value_but_fixme_should_propagate_errors()))
{
@ -287,7 +289,7 @@ void HexEditor::mousedown_event(GUI::MouseEvent& event)
if (offset >= m_document->size())
return;
dbgln_if(HEX_DEBUG, "HexEditor::mousedown_event(hex): offset={}", offset);
dbgln_if(HEX_DEBUG, "Editor::mousedown_event(hex): offset={}", offset);
m_edit_mode = EditMode::Hex;
m_cursor_at_low_nibble = false;
@ -310,7 +312,7 @@ void HexEditor::mousedown_event(GUI::MouseEvent& event)
if (offset >= m_document->size())
return;
dbgln_if(HEX_DEBUG, "HexEditor::mousedown_event(text): offset={}", offset);
dbgln_if(HEX_DEBUG, "Editor::mousedown_event(text): offset={}", offset);
m_position = offset;
m_cursor_at_low_nibble = false;
@ -416,7 +418,7 @@ void HexEditor::scroll_position_into_view(size_t position)
void HexEditor::keydown_event(GUI::KeyEvent& event)
{
dbgln_if(HEX_DEBUG, "HexEditor::keydown_event key={}", static_cast<u8>(event.key()));
dbgln_if(HEX_DEBUG, "Editor::keydown_event key={}", static_cast<u8>(event.key()));
auto move_and_update_cursor_by = [&](i64 cursor_location_change) {
size_t new_position = m_position + cursor_location_change;
@ -914,3 +916,5 @@ GUI::UndoStack& HexEditor::undo_stack()
{
return m_undo_stack;
}
}

View file

@ -21,6 +21,8 @@
#include <LibGfx/Font/Font.h>
#include <LibGfx/TextAlignment.h>
namespace HexEditor {
class HexEditor : public GUI::AbstractScrollableWidget {
C_OBJECT(HexEditor)
public:
@ -111,3 +113,5 @@ private:
void reset_cursor_blink_state();
};
}

View file

@ -15,7 +15,6 @@
#include <AK/Forward.h>
#include <AK/Optional.h>
#include <AK/StringBuilder.h>
#include <Applications/HexEditor/HexEditorWindowGML.h>
#include <LibConfig/Client.h>
#include <LibDesktop/Launcher.h>
#include <LibFileSystemAccessClient/Client.h>
@ -36,15 +35,20 @@
#include <LibTextCodec/Decoder.h>
#include <string.h>
REGISTER_WIDGET(HexEditor, HexEditor);
namespace HexEditor {
HexEditorWidget::HexEditorWidget()
ErrorOr<NonnullRefPtr<HexEditorWidget>> HexEditorWidget::create()
{
load_from_gml(hex_editor_window_gml).release_value_but_fixme_should_propagate_errors();
auto widget = TRY(try_create());
TRY(widget->setup());
return widget;
}
ErrorOr<void> HexEditorWidget::setup()
{
m_toolbar = *find_descendant_of_type_named<GUI::Toolbar>("toolbar");
m_toolbar_container = *find_descendant_of_type_named<GUI::ToolbarContainer>("toolbar_container");
m_editor = *find_descendant_of_type_named<HexEditor>("editor");
m_editor = *find_descendant_of_type_named<::HexEditor::HexEditor>("editor");
m_statusbar = *find_descendant_of_type_named<GUI::Statusbar>("statusbar");
m_search_results = *find_descendant_of_type_named<GUI::TableView>("search_results");
m_search_results_container = *find_descendant_of_type_named<GUI::Widget>("search_results_container");
@ -60,9 +64,9 @@ HexEditorWidget::HexEditorWidget()
m_editor->update();
};
m_editor->on_status_change = [this](int position, HexEditor::EditMode edit_mode, int selection_start, int selection_end) {
m_editor->on_status_change = [this](int position, HexEditor::HexEditor::EditMode edit_mode, int selection_start, int selection_end) {
m_statusbar->set_text(0, String::formatted("Offset: {:#08X}", position).release_value_but_fixme_should_propagate_errors());
m_statusbar->set_text(1, String::formatted("Edit Mode: {}", edit_mode == HexEditor::EditMode::Hex ? "Hex" : "Text").release_value_but_fixme_should_propagate_errors());
m_statusbar->set_text(1, String::formatted("Edit Mode: {}", edit_mode == HexEditor::HexEditor::EditMode::Hex ? "Hex" : "Text").release_value_but_fixme_should_propagate_errors());
m_statusbar->set_text(2, String::formatted("Selection Start: {}", selection_start).release_value_but_fixme_should_propagate_errors());
m_statusbar->set_text(3, String::formatted("Selection End: {}", selection_end).release_value_but_fixme_should_propagate_errors());
m_statusbar->set_text(4, String::formatted("Selected Bytes: {}", m_editor->selection_size()).release_value_but_fixme_should_propagate_errors());
@ -279,6 +283,8 @@ HexEditorWidget::HexEditorWidget()
GUI::Application::the()->on_action_leave = [this](GUI::Action&) {
m_statusbar->set_override_text({});
};
return {};
}
void HexEditorWidget::update_inspector_values(size_t position)
@ -647,3 +653,5 @@ void HexEditorWidget::drop_event(GUI::DropEvent& event)
open_file(response.value().filename(), response.value().release_stream());
}
}
}

View file

@ -1,4 +1,4 @@
@GUI::Widget {
@HexEditor::HexEditorWidget {
name: "main"
fill_with_background_color: true
layout: @GUI::VerticalBoxLayout {

View file

@ -19,18 +19,23 @@
#include <LibGUI/Widget.h>
#include <LibGUI/Window.h>
class HexEditor;
namespace HexEditor {
class HexEditorWidget final : public GUI::Widget {
C_OBJECT(HexEditorWidget)
C_OBJECT_ABSTRACT(HexEditorWidget)
public:
virtual ~HexEditorWidget() override = default;
void open_file(String const& filename, NonnullOwnPtr<Core::File>);
ErrorOr<void> initialize_menubar(GUI::Window&);
bool request_close();
static ErrorOr<NonnullRefPtr<HexEditorWidget>> create();
protected:
static ErrorOr<NonnullRefPtr<HexEditorWidget>> try_create();
private:
HexEditorWidget();
ErrorOr<void> setup();
HexEditorWidget() = default;
void set_path(StringView);
void update_title();
void set_search_results_visible(bool visible);
@ -85,3 +90,5 @@ private:
bool m_value_inspector_little_endian { true };
bool m_selecting_from_inspector { false };
};
}

View file

@ -37,7 +37,8 @@ ErrorOr<int> serenity_main(Main::Arguments arguments)
window->restore_size_and_position("HexEditor"sv, "Window"sv, { { 640, 400 } });
window->save_size_and_position_on_close("HexEditor"sv, "Window"sv);
auto hex_editor_widget = window->set_main_widget<HexEditorWidget>();
auto hex_editor_widget = TRY(HexEditor::HexEditorWidget::create());
window->set_main_widget(hex_editor_widget);
window->on_close_request = [&]() -> GUI::Window::CloseRequestDecision {
if (hex_editor_widget->request_close())