diff options
author | Andreas Kling <awesomekling@gmail.com> | 2019-11-16 19:17:27 +0100 |
---|---|---|
committer | Andreas Kling <awesomekling@gmail.com> | 2019-11-16 19:17:27 +0100 |
commit | 69dee2076124aeac2bcd3caae78bc08a51d2db35 (patch) | |
tree | 606d8cf6b8f0684efff3790b6975230363ee0773 /DevTools | |
parent | 196b64c0ae61b4f2c548073fa84b29a19b87a3ed (diff) | |
download | serenity-69dee2076124aeac2bcd3caae78bc08a51d2db35.zip |
HackStudio: Allow rubber-band selection of widgets
This patch implements basic rubber-banding. Perhaps this mechanism can
be generalized somehow, but it's not clear to me how that would work
at the moment.
Diffstat (limited to 'DevTools')
-rw-r--r-- | DevTools/HackStudio/CursorTool.cpp | 11 | ||||
-rw-r--r-- | DevTools/HackStudio/FormWidget.cpp | 77 | ||||
-rw-r--r-- | DevTools/HackStudio/FormWidget.h | 13 |
3 files changed, 91 insertions, 10 deletions
diff --git a/DevTools/HackStudio/CursorTool.cpp b/DevTools/HackStudio/CursorTool.cpp index 98742d448b..33e8b802ee 100644 --- a/DevTools/HackStudio/CursorTool.cpp +++ b/DevTools/HackStudio/CursorTool.cpp @@ -29,6 +29,8 @@ void CursorTool::on_mousedown(GMouseEvent& event) } } else { m_editor.selection().clear(); + form_widget.set_rubber_banding({}, true); + form_widget.set_rubber_band_origin({}, event.position()); } // FIXME: Do we need to update any part of the FormEditorWidget outside the FormWidget? form_widget.update(); @@ -49,15 +51,21 @@ void CursorTool::on_mouseup(GMouseEvent& event) } } m_dragging = false; + form_widget.set_rubber_banding({}, false); } } void CursorTool::on_mousemove(GMouseEvent& event) { dbg() << "CursorTool::on_mousemove"; + auto& form_widget = m_editor.form_widget(); + + if (form_widget.is_rubber_banding({})) { + form_widget.set_rubber_band_position({}, event.position()); + return; + } if (!m_dragging && event.buttons() & GMouseButton::Left && event.position() != m_drag_origin) { - auto& form_widget = m_editor.form_widget(); auto result = form_widget.hit_test(event.position(), GWidget::ShouldRespectGreediness::No); if (result.widget && result.widget != &form_widget) { if (!m_editor.selection().contains(*result.widget)) { @@ -82,6 +90,7 @@ void CursorTool::on_mousemove(GMouseEvent& event) m_editor.model().update(); return; } + } void CursorTool::on_keydown(GKeyEvent& event) diff --git a/DevTools/HackStudio/FormWidget.cpp b/DevTools/HackStudio/FormWidget.cpp index 4168f7e965..1d92c5735f 100644 --- a/DevTools/HackStudio/FormWidget.cpp +++ b/DevTools/HackStudio/FormWidget.cpp @@ -41,17 +41,20 @@ void FormWidget::paint_event(GPaintEvent& event) void FormWidget::second_paint_event(GPaintEvent& event) { - if (editor().selection().is_empty()) - return; - GPainter painter(*this); painter.add_clip_rect(event.rect()); - for_each_child_widget([&](auto& child) { - if (editor().selection().contains(child)) { - painter.draw_rect(child.relative_rect(), Color::Blue); - } - return IterationDecision::Continue; - }); + + if (!editor().selection().is_empty()) { + for_each_child_widget([&](auto& child) { + if (editor().selection().contains(child)) { + painter.draw_rect(child.relative_rect(), Color::Blue); + } + return IterationDecision::Continue; + }); + } + + if (m_rubber_banding) + painter.draw_rect(rubber_band_rect(), Color::MidMagenta); } void FormWidget::mousedown_event(GMouseEvent& event) @@ -73,3 +76,59 @@ void FormWidget::keydown_event(GKeyEvent& event) { editor().tool().on_keydown(event); } + +void FormWidget::set_rubber_banding(Badge<CursorTool>, bool value) +{ + if (m_rubber_banding == value) + return; + m_rubber_banding = value; + update(); +} + +void FormWidget::set_rubber_band_origin(Badge<CursorTool>, const Point& origin) +{ + if (m_rubber_band_origin == origin) + return; + m_rubber_band_origin = origin; + m_rubber_band_position = origin; + update(); +} + +void FormWidget::set_rubber_band_position(Badge<CursorTool>, const Point& position) +{ + if (m_rubber_band_position == position) + return; + m_rubber_band_position = position; + + auto rubber_band_rect = this->rubber_band_rect(); + + editor().selection().clear(); + for_each_child_widget([&](auto& child) { + if (child.relative_rect().intersects(rubber_band_rect)) + editor().selection().add(child); + return IterationDecision::Continue; + }); + + update(); +} + +static Rect rect_from_two_points(const Point& a, const Point& b) +{ + if (a.x() <= b.x()) { + if (a.y() <= b.y()) + return { a, { b.x() - a.x(), b.y() - a.y() } }; + int height = a.y() - b.y(); + return { a.x(), a.y() - height, b.x() - a.x(), height }; + } + if (a.y() >= b.y()) + return { b, { a.x() - b.x(), a.y() - b.y() } }; + int height = b.y() - a.y(); + return { b.x(), b.y() - height, a.x() - b.x(), height }; +} + +Rect FormWidget::rubber_band_rect() const +{ + if (!m_rubber_banding) + return {}; + return rect_from_two_points(m_rubber_band_origin, m_rubber_band_position); +} diff --git a/DevTools/HackStudio/FormWidget.h b/DevTools/HackStudio/FormWidget.h index 02a568e513..f9b41bccee 100644 --- a/DevTools/HackStudio/FormWidget.h +++ b/DevTools/HackStudio/FormWidget.h @@ -1,7 +1,9 @@ #pragma once +#include <AK/Badge.h> #include <LibGUI/GWidget.h> +class CursorTool; class FormEditorWidget; class FormWidget final : public GWidget { @@ -15,6 +17,11 @@ public: // FIXME: This should be an app-wide preference instead. int grid_size() const { return m_grid_size; } + bool is_rubber_banding(Badge<CursorTool>) const { return m_rubber_banding; } + void set_rubber_banding(Badge<CursorTool>, bool); + void set_rubber_band_position(Badge<CursorTool>, const Point&); + void set_rubber_band_origin(Badge<CursorTool>, const Point&); + private: virtual bool accepts_focus() const override { return true; } @@ -27,5 +34,11 @@ private: explicit FormWidget(FormEditorWidget& parent); + Rect rubber_band_rect() const; + int m_grid_size { 5 }; + + bool m_rubber_banding { false }; + Point m_rubber_band_origin; + Point m_rubber_band_position; }; |