diff options
author | Itamar <itamar8910@gmail.com> | 2020-04-24 23:48:25 +0300 |
---|---|---|
committer | Andreas Kling <kling@serenityos.org> | 2020-04-25 13:16:46 +0200 |
commit | 393560d8a2de4b507497786f3203e0c0cebb13c2 (patch) | |
tree | 207abdab49a27982d944358b714be64c66ccdd3a | |
parent | 009b4ea3f418e3cd88a4b66e0d6531b871d270c7 (diff) | |
download | serenity-393560d8a2de4b507497786f3203e0c0cebb13c2.zip |
HackStudio: GUI support for setting breakpoints on source code lines
-rw-r--r-- | Base/res/icons/breakpoint.png | bin | 0 -> 305 bytes | |||
-rw-r--r-- | DevTools/HackStudio/BreakpointCallback.h | 37 | ||||
-rw-r--r-- | DevTools/HackStudio/Editor.cpp | 75 | ||||
-rw-r--r-- | DevTools/HackStudio/Editor.h | 16 | ||||
-rw-r--r-- | DevTools/HackStudio/EditorWrapper.cpp | 4 | ||||
-rw-r--r-- | DevTools/HackStudio/EditorWrapper.h | 6 | ||||
-rw-r--r-- | Libraries/LibGUI/TextEditor.h | 3 |
7 files changed, 135 insertions, 6 deletions
diff --git a/Base/res/icons/breakpoint.png b/Base/res/icons/breakpoint.png Binary files differnew file mode 100644 index 0000000000..fcfc266f91 --- /dev/null +++ b/Base/res/icons/breakpoint.png diff --git a/DevTools/HackStudio/BreakpointCallback.h b/DevTools/HackStudio/BreakpointCallback.h new file mode 100644 index 0000000000..80d1f9495d --- /dev/null +++ b/DevTools/HackStudio/BreakpointCallback.h @@ -0,0 +1,37 @@ +/* + * Copyright (c) 2020, Itamar S. <itamar8910@gmail.com> + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#pragma once +#include <AK/Function.h> +#include <AK/String.h> +#include <AK/Types.h> + +enum class BreakpointChange { + Added, + Removed, +}; + +typedef Function<void(const String& file, size_t line, BreakpointChange)> BreakpointChangeCallback; diff --git a/DevTools/HackStudio/Editor.cpp b/DevTools/HackStudio/Editor.cpp index b95d0e5a1f..2813750949 100644 --- a/DevTools/HackStudio/Editor.cpp +++ b/DevTools/HackStudio/Editor.cpp @@ -31,6 +31,7 @@ #include <LibCore/DirIterator.h> #include <LibCore/File.h> #include <LibGUI/Application.h> +#include <LibGUI/Label.h> #include <LibGUI/Painter.h> #include <LibGUI/ScrollBar.h> #include <LibGUI/SyntaxHighlighter.h> @@ -79,12 +80,20 @@ void Editor::focusout_event(Core::Event& event) GUI::TextEditor::focusout_event(event); } +Gfx::Rect Editor::breakpoint_icon_rect(size_t line_number) const +{ + auto ruler_line_rect = ruler_content_rect(line_number); + auto center = ruler_line_rect.center().translated({ ruler_line_rect.width() - 10, -line_spacing() - 3 }); + constexpr int size = 32; + return { center.x() - size / 2, center.y() - size / 2, size, size }; +} + void Editor::paint_event(GUI::PaintEvent& event) { GUI::TextEditor::paint_event(event); + GUI::Painter painter(*this); if (is_focused()) { - GUI::Painter painter(*this); painter.add_clip_rect(event.rect()); auto rect = frame_inner_rect(); @@ -95,8 +104,26 @@ void Editor::paint_event(GUI::PaintEvent& event) painter.draw_rect(rect, palette().selection()); } - if (m_hovering_editor) + if (m_hovering_lines_ruler) + window()->set_override_cursor(GUI::StandardCursor::Arrow); + else if (m_hovering_editor) window()->set_override_cursor(m_hovering_link && m_holding_ctrl ? GUI::StandardCursor::Hand : GUI::StandardCursor::IBeam); + + if (ruler_visible()) { + size_t first_visible_line = text_position_at(event.rect().top_left()).line(); + size_t last_visible_line = text_position_at(event.rect().bottom_right()).line(); + for (size_t line : m_breakpoint_lines) { + if (line < first_visible_line || line > last_visible_line) { + continue; + } + const auto& icon = breakpoint_icon_bitmap(); + painter.blit(breakpoint_icon_rect(line).center(), icon, icon.rect()); + } + if (m_execution_position.has_value()) { + const auto& icon = current_position_icon_bitmap(); + painter.blit(breakpoint_icon_rect(m_execution_position.value()).center(), icon, icon.rect()); + } + } } static HashMap<String, String>& man_paths() @@ -188,6 +215,9 @@ void Editor::mousemove_event(GUI::MouseEvent& event) if (!highlighter) return; + auto ruler_line_rect = ruler_content_rect(text_position.line()); + m_hovering_lines_ruler = (event.position().x() < ruler_line_rect.width()); + bool hide_tooltip = true; bool is_over_link = false; @@ -237,12 +267,23 @@ void Editor::mousedown_event(GUI::MouseEvent& event) return; } + auto text_position = text_position_at(event.position()); + auto ruler_line_rect = ruler_content_rect(text_position.line()); + if (event.position().x() < ruler_line_rect.width()) { + if (!m_breakpoint_lines.contains_slow(text_position.line())) { + m_breakpoint_lines.append(text_position.line()); + on_breakpoint_change(wrapper().filename_label().text(), text_position.line(), BreakpointChange::Added); + } else { + m_breakpoint_lines.remove_first_matching([&](size_t line) { return line == text_position.line(); }); + on_breakpoint_change(wrapper().filename_label().text(), text_position.line(), BreakpointChange::Removed); + } + } + if (!(event.modifiers() & Mod_Ctrl)) { GUI::TextEditor::mousedown_event(event); return; } - auto text_position = text_position_at(event.position()); if (!text_position.is_valid()) { GUI::TextEditor::mousedown_event(event); return; @@ -338,3 +379,31 @@ void Editor::navigate_to_include_if_available(String path) on_open(it->value); } + +void Editor::set_execution_position(size_t line_number) +{ + m_execution_position = line_number; + update(breakpoint_icon_rect(line_number)); +} + +void Editor::clear_execution_position() +{ + if (!m_execution_position.has_value()) { + return; + } + size_t previous_position = m_execution_position.value(); + m_execution_position = {}; + update(breakpoint_icon_rect(previous_position)); +} + +const Gfx::Bitmap& Editor::breakpoint_icon_bitmap() +{ + static auto bitmap = Gfx::Bitmap::load_from_file("/res/icons/breakpoint.png"); + return *bitmap; +} + +const Gfx::Bitmap& Editor::current_position_icon_bitmap() +{ + static auto bitmap = Gfx::Bitmap::load_from_file("/res/icons/16x16/go-forward.png"); + return *bitmap; +} diff --git a/DevTools/HackStudio/Editor.h b/DevTools/HackStudio/Editor.h index d188e3655c..e4197da613 100644 --- a/DevTools/HackStudio/Editor.h +++ b/DevTools/HackStudio/Editor.h @@ -26,6 +26,8 @@ #pragma once +#include "BreakpointCallback.h" +#include <AK/Optional.h> #include <LibGUI/TextEditor.h> #include <LibWeb/Forward.h> @@ -42,6 +44,12 @@ public: EditorWrapper& wrapper(); const EditorWrapper& wrapper() const; + const Vector<size_t>& breakpoint_lines() const { return m_breakpoint_lines; } + void set_execution_position(size_t line_number); + void clear_execution_position(); + + BreakpointChangeCallback on_breakpoint_change; + private: virtual void focusin_event(Core::Event&) override; virtual void focusout_event(Core::Event&) override; @@ -56,6 +64,10 @@ private: void show_documentation_tooltip_if_available(const String&, const Gfx::Point& screen_location); void navigate_to_include_if_available(String); + Gfx::Rect breakpoint_icon_rect(size_t line_number) const; + static const Gfx::Bitmap& breakpoint_icon_bitmap(); + static const Gfx::Bitmap& current_position_icon_bitmap(); + explicit Editor(); RefPtr<GUI::Window> m_documentation_tooltip_window; @@ -65,4 +77,8 @@ private: bool m_hovering_editor { false }; bool m_hovering_link { false }; bool m_holding_ctrl { false }; + bool m_hovering_lines_ruler { false }; + + Vector<size_t> m_breakpoint_lines; + Optional<size_t> m_execution_position; }; diff --git a/DevTools/HackStudio/EditorWrapper.cpp b/DevTools/HackStudio/EditorWrapper.cpp index 5a638f98e3..1ee9eefb68 100644 --- a/DevTools/HackStudio/EditorWrapper.cpp +++ b/DevTools/HackStudio/EditorWrapper.cpp @@ -35,7 +35,7 @@ extern RefPtr<EditorWrapper> g_current_editor_wrapper; extern Function<void(String)> g_open_file; -EditorWrapper::EditorWrapper() +EditorWrapper::EditorWrapper(BreakpointChangeCallback breakpoint_change_callback) { set_layout<GUI::VerticalBoxLayout>(); @@ -72,6 +72,8 @@ EditorWrapper::EditorWrapper() m_editor->on_open = [this](String path) { g_open_file(path); }; + + m_editor->on_breakpoint_change = move(breakpoint_change_callback); } EditorWrapper::~EditorWrapper() diff --git a/DevTools/HackStudio/EditorWrapper.h b/DevTools/HackStudio/EditorWrapper.h index 9cf8947222..31aa679590 100644 --- a/DevTools/HackStudio/EditorWrapper.h +++ b/DevTools/HackStudio/EditorWrapper.h @@ -26,6 +26,9 @@ #pragma once +#include "BreakpointCallback.h" +#include <AK/Function.h> +#include <AK/Vector.h> #include <LibGUI/Widget.h> #include <string.h> @@ -40,11 +43,12 @@ public: const Editor& editor() const { return *m_editor; } GUI::Label& filename_label() { return *m_filename_label; } + const GUI::Label& filename_label() const { return *m_filename_label; } void set_editor_has_focus(Badge<Editor>, bool); private: - explicit EditorWrapper(); + explicit EditorWrapper(BreakpointChangeCallback); RefPtr<GUI::Label> m_filename_label; RefPtr<GUI::Label> m_cursor_label; diff --git a/Libraries/LibGUI/TextEditor.h b/Libraries/LibGUI/TextEditor.h index 760c4d4903..c18ec59845 100644 --- a/Libraries/LibGUI/TextEditor.h +++ b/Libraries/LibGUI/TextEditor.h @@ -151,8 +151,10 @@ protected: virtual void resize_event(ResizeEvent&) override; virtual void theme_change_event(ThemeChangeEvent&) override; virtual void cursor_did_change() {} + Gfx::Rect ruler_content_rect(size_t line) const; TextPosition text_position_at(const Gfx::Point&) const; + bool ruler_visible() const { return m_ruler_visible; } private: friend class TextDocumentLine; @@ -183,7 +185,6 @@ private: TextDocumentLine& current_line() { return line(m_cursor.line()); } const TextDocumentLine& current_line() const { return line(m_cursor.line()); } int ruler_width() const; - Gfx::Rect ruler_content_rect(size_t line) const; void toggle_selection_if_needed_for_event(const KeyEvent&); void delete_selection(); void did_update_selection(); |