From aa07c232f14da81b4fd9f5f0f26f6f5b73d5749c Mon Sep 17 00:00:00 2001 From: Sam Atkins Date: Mon, 29 Jan 2024 19:57:27 +0000 Subject: [PATCH] HexEditor: Optionally display annotations in the side panel --- .../HexEditor/HexEditorWidget.cpp | 56 +++++++++++++++++-- .../HexEditor/HexEditorWidget.gml | 10 ++++ .../Applications/HexEditor/HexEditorWidget.h | 7 +++ 3 files changed, 67 insertions(+), 6 deletions(-) diff --git a/Userland/Applications/HexEditor/HexEditorWidget.cpp b/Userland/Applications/HexEditor/HexEditorWidget.cpp index 8140dd68cd..33fbbc3136 100644 --- a/Userland/Applications/HexEditor/HexEditorWidget.cpp +++ b/Userland/Applications/HexEditor/HexEditorWidget.cpp @@ -3,6 +3,7 @@ * Copyright (c) 2021, Mustafa Quraish * Copyright (c) 2022, the SerenityOS developers. * Copyright (c) 2022, Timothy Slater + * Copyright (c) 2024, Sam Atkins * * SPDX-License-Identifier: BSD-2-Clause */ @@ -27,6 +28,7 @@ #include #include #include +#include #include #include #include @@ -50,6 +52,8 @@ ErrorOr HexEditorWidget::setup() m_toolbar_container = *find_descendant_of_type_named("toolbar_container"); m_editor = *find_descendant_of_type_named<::HexEditor::HexEditor>("editor"); m_statusbar = *find_descendant_of_type_named("statusbar"); + m_annotations = *find_descendant_of_type_named("annotations"); + m_annotations_container = *find_descendant_of_type_named("annotations_container"); m_search_results = *find_descendant_of_type_named("search_results"); m_search_results_container = *find_descendant_of_type_named("search_results_container"); m_side_panel_container = *find_descendant_of_type_named("side_panel_container"); @@ -92,6 +96,16 @@ ErrorOr HexEditorWidget::setup() m_redo_action->set_enabled(m_editor->undo_stack().can_redo()); }; + initialize_annotations_model(); + m_annotations->set_activates_on_selection(true); + m_annotations->on_activation = [this](GUI::ModelIndex const& index) { + if (!index.is_valid()) + return; + auto start_offset = m_annotations->model()->data(index, (GUI::ModelRole)AnnotationsModel::CustomRole::StartOffset).to_integer(); + m_editor->set_position(start_offset); + m_editor->update(); + }; + m_search_results->set_activates_on_selection(true); m_search_results->on_activation = [this](const GUI::ModelIndex& index) { if (!index.is_valid()) @@ -117,6 +131,7 @@ ErrorOr HexEditorWidget::setup() } set_path({}); + initialize_annotations_model(); window()->set_modified(false); } }); @@ -226,6 +241,11 @@ ErrorOr HexEditorWidget::setup() Config::write_bool("HexEditor"sv, "Layout"sv, "ShowToolbar"sv, action.is_checked()); }); + m_layout_annotations_action = GUI::Action::create_checkable("&Annotations", [&](auto& action) { + set_annotations_visible(action.is_checked()); + Config::write_bool("HexEditor"sv, "Layout"sv, "ShowAnnotations"sv, action.is_checked()); + }); + m_layout_search_results_action = GUI::Action::create_checkable("&Search Results", [&](auto& action) { set_search_results_visible(action.is_checked()); Config::write_bool("HexEditor"sv, "Layout"sv, "ShowSearchResults"sv, action.is_checked()); @@ -500,6 +520,9 @@ ErrorOr HexEditorWidget::initialize_menubar(GUI::Window& window) m_layout_toolbar_action->set_checked(show_toolbar); m_toolbar_container->set_visible(show_toolbar); + auto show_annotations = Config::read_bool("HexEditor"sv, "Layout"sv, "ShowAnnotations"sv, false); + set_annotations_visible(show_annotations); + auto show_search_results = Config::read_bool("HexEditor"sv, "Layout"sv, "ShowSearchResults"sv, false); set_search_results_visible(show_search_results); @@ -507,6 +530,7 @@ ErrorOr HexEditorWidget::initialize_menubar(GUI::Window& window) set_value_inspector_visible(show_value_inspector); view_menu->add_action(*m_layout_toolbar_action); + view_menu->add_action(*m_layout_annotations_action); view_menu->add_action(*m_layout_search_results_action); view_menu->add_action(*m_layout_value_inspector_action); view_menu->add_separator(); @@ -601,6 +625,7 @@ void HexEditorWidget::open_file(ByteString const& filename, NonnullOwnPtrset_modified(false); m_editor->open_file(move(file)); set_path(filename); + initialize_annotations_model(); GUI::Application::the()->set_most_recently_open_file(filename); } @@ -617,13 +642,34 @@ bool HexEditorWidget::request_close() return result == GUI::MessageBox::ExecResult::No; } +void HexEditorWidget::update_side_panel_visibility() +{ + m_side_panel_container->set_visible( + m_annotations_container->is_visible() + || m_search_results_container->is_visible() + || m_value_inspector_container->is_visible()); +} + +void HexEditorWidget::set_annotations_visible(bool visible) +{ + m_layout_annotations_action->set_checked(visible); + m_annotations_container->set_visible(visible); + update_side_panel_visibility(); +} + +void HexEditorWidget::initialize_annotations_model() +{ + auto sorting_model = MUST(GUI::SortingProxyModel::create(m_editor->document().annotations())); + sorting_model->set_sort_role((GUI::ModelRole)AnnotationsModel::CustomRole::StartOffset); + sorting_model->sort(AnnotationsModel::Column::Start, GUI::SortOrder::Ascending); + m_annotations->set_model(sorting_model); +} + void HexEditorWidget::set_search_results_visible(bool visible) { m_layout_search_results_action->set_checked(visible); m_search_results_container->set_visible(visible); - - // Ensure side panel container is visible if either search result or value inspector are turned on - m_side_panel_container->set_visible(visible || m_value_inspector_container->is_visible()); + update_side_panel_visibility(); } void HexEditorWidget::set_value_inspector_visible(bool visible) @@ -633,9 +679,7 @@ void HexEditorWidget::set_value_inspector_visible(bool visible) m_layout_value_inspector_action->set_checked(visible); m_value_inspector_container->set_visible(visible); - - // Ensure side panel container is visible if either search result or value inspector are turned on - m_side_panel_container->set_visible(visible || m_search_results_container->is_visible()); + update_side_panel_visibility(); } void HexEditorWidget::drag_enter_event(GUI::DragEvent& event) diff --git a/Userland/Applications/HexEditor/HexEditorWidget.gml b/Userland/Applications/HexEditor/HexEditorWidget.gml index 9aaedf335e..f9faaf5fe9 100644 --- a/Userland/Applications/HexEditor/HexEditorWidget.gml +++ b/Userland/Applications/HexEditor/HexEditorWidget.gml @@ -44,6 +44,16 @@ activates_on_selection: true } } + + @GUI::Widget { + name: "annotations_container" + visible: false + layout: @GUI::VerticalBoxLayout {} + + @GUI::TableView { + name: "annotations" + } + } } } diff --git a/Userland/Applications/HexEditor/HexEditorWidget.h b/Userland/Applications/HexEditor/HexEditorWidget.h index 52a66b7d7e..9227647e73 100644 --- a/Userland/Applications/HexEditor/HexEditorWidget.h +++ b/Userland/Applications/HexEditor/HexEditorWidget.h @@ -3,6 +3,7 @@ * Copyright (c) 2021, Mustafa Quraish * Copyright (c) 2022, the SerenityOS developers. * Copyright (c) 2022, Timothy Slater + * Copyright (c) 2024, Sam Atkins * * SPDX-License-Identifier: BSD-2-Clause */ @@ -38,6 +39,9 @@ private: HexEditorWidget() = default; void set_path(StringView); void update_title(); + void update_side_panel_visibility(); + void set_annotations_visible(bool visible); + void initialize_annotations_model(); void set_search_results_visible(bool visible); void set_value_inspector_visible(bool visible); void update_inspector_values(size_t position); @@ -67,6 +71,7 @@ private: RefPtr m_find_action; RefPtr m_goto_offset_action; RefPtr m_layout_toolbar_action; + RefPtr m_layout_annotations_action; RefPtr m_layout_search_results_action; RefPtr m_layout_value_inspector_action; @@ -86,6 +91,8 @@ private: RefPtr m_side_panel_container; RefPtr m_value_inspector_container; RefPtr m_value_inspector; + RefPtr m_annotations_container; + RefPtr m_annotations; bool m_value_inspector_little_endian { true }; bool m_selecting_from_inspector { false };