From 567769eb2feedd4b2ec7eb90b65b76b8f0d30bda Mon Sep 17 00:00:00 2001 From: Andreas Kling Date: Sun, 10 Nov 2019 22:31:10 +0100 Subject: [PATCH] HackStudio: Allow moving widgets around using the CursorTool You can now move the widgets around, either by themselves or in group selections, by dragging them with the cursor tool. :^) --- DevTools/HackStudio/CursorTool.cpp | 66 +++++++++++++++++++++++--- DevTools/HackStudio/CursorTool.h | 8 ++++ DevTools/HackStudio/FormEditorWidget.h | 9 ++++ DevTools/HackStudio/FormWidget.h | 4 +- 4 files changed, 79 insertions(+), 8 deletions(-) diff --git a/DevTools/HackStudio/CursorTool.cpp b/DevTools/HackStudio/CursorTool.cpp index 77f0476703..e95f632282 100644 --- a/DevTools/HackStudio/CursorTool.cpp +++ b/DevTools/HackStudio/CursorTool.cpp @@ -8,11 +8,27 @@ void CursorTool::on_mousedown(GMouseEvent& event) dbg() << "CursorTool::on_mousedown"; 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 (event.modifiers() & Mod_Ctrl) - m_editor.selection().toggle(*result.widget); - else - m_editor.selection().set(*result.widget); + + if (event.button() == GMouseButton::Left) { + if (result.widget && result.widget != &form_widget) { + if (event.modifiers() & Mod_Ctrl) { + m_editor.selection().toggle(*result.widget); + } else if (!event.modifiers()) { + if (!m_editor.selection().contains(*result.widget)) { + dbg() << "Selection didn't contain " << *result.widget << ", making it the only selected one"; + m_editor.selection().set(*result.widget); + } + + m_drag_origin = event.position(); + m_positions_before_drag.clear(); + m_editor.selection().for_each([&](auto& widget) { + m_positions_before_drag.set(&widget, widget.relative_position()); + return IterationDecision::Continue; + }); + } + } else { + m_editor.selection().clear(); + } // FIXME: Do we need to update any part of the FormEditorWidget outside the FormWidget? form_widget.update(); } @@ -20,12 +36,48 @@ void CursorTool::on_mousedown(GMouseEvent& event) void CursorTool::on_mouseup(GMouseEvent& event) { - (void)event; dbg() << "CursorTool::on_mouseup"; + if (event.button() == GMouseButton::Left) { + auto& form_widget = m_editor.form_widget(); + auto result = form_widget.hit_test(event.position(), GWidget::ShouldRespectGreediness::No); + if (!m_dragging && !(event.modifiers() & Mod_Ctrl)) { + if (result.widget && result.widget != &form_widget) { + m_editor.selection().set(*result.widget); + // FIXME: Do we need to update any part of the FormEditorWidget outside the FormWidget? + form_widget.update(); + } + } + m_dragging = false; + } } void CursorTool::on_mousemove(GMouseEvent& event) { - (void)event; dbg() << "CursorTool::on_mousemove"; + + 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)) { + m_editor.selection().set(*result.widget); + // FIXME: Do we need to update any part of the FormEditorWidget outside the FormWidget? + form_widget.update(); + } + } + m_dragging = true; + } + + if (m_dragging) { + auto movement_delta = event.position() - m_drag_origin; + m_editor.selection().for_each([&](auto& widget) { + auto new_rect = widget.relative_rect(); + new_rect.set_location(m_positions_before_drag.get(&widget).value_or({}).translated(movement_delta)); + new_rect.set_x(new_rect.x() - (new_rect.x() % m_editor.form_widget().grid_size())); + new_rect.set_y(new_rect.y() - (new_rect.y() % m_editor.form_widget().grid_size())); + widget.set_relative_rect(new_rect); + return IterationDecision::Continue; + }); + return; + } } diff --git a/DevTools/HackStudio/CursorTool.h b/DevTools/HackStudio/CursorTool.h index 2b9cbcc3bc..68fcbb534f 100644 --- a/DevTools/HackStudio/CursorTool.h +++ b/DevTools/HackStudio/CursorTool.h @@ -1,6 +1,10 @@ #pragma once #include "Tool.h" +#include +#include + +class GWidget; class CursorTool final : public Tool { public: @@ -15,4 +19,8 @@ private: virtual void on_mousedown(GMouseEvent&) override; virtual void on_mouseup(GMouseEvent&) override; virtual void on_mousemove(GMouseEvent&) override; + + Point m_drag_origin; + HashMap m_positions_before_drag; + bool m_dragging { false }; }; diff --git a/DevTools/HackStudio/FormEditorWidget.h b/DevTools/HackStudio/FormEditorWidget.h index ef0bbed234..cc2d9e66cd 100644 --- a/DevTools/HackStudio/FormEditorWidget.h +++ b/DevTools/HackStudio/FormEditorWidget.h @@ -60,6 +60,15 @@ public: m_widgets.clear(); } + template + void for_each(Callback callback) + { + for (auto& it : m_widgets) { + if (callback(*it) == IterationDecision::Break) + break; + } + } + WidgetSelection() {} private: HashTable m_widgets; diff --git a/DevTools/HackStudio/FormWidget.h b/DevTools/HackStudio/FormWidget.h index 6ac2eb3df9..3258cede35 100644 --- a/DevTools/HackStudio/FormWidget.h +++ b/DevTools/HackStudio/FormWidget.h @@ -12,6 +12,9 @@ public: FormEditorWidget& editor(); const FormEditorWidget& editor() const; + // FIXME: This should be an app-wide preference instead. + int grid_size() const { return m_grid_size; } + private: virtual void paint_event(GPaintEvent&) override; virtual void second_paint_event(GPaintEvent&) override; @@ -21,6 +24,5 @@ private: explicit FormWidget(FormEditorWidget& parent); - // FIXME: This should be an app-wide preference instead. int m_grid_size { 5 }; };