Browse Source

PixelPaint: Display a preview image when scaling with the move tool

A preview of the scaled image and an outline of the updated layer
boundary are now shown when scaling with the move tool.
Tim Ledbetter 2 years ago
parent
commit
5ba0b551f4

+ 44 - 8
Userland/Applications/PixelPaint/Tools/MoveTool.cpp

@@ -13,6 +13,7 @@
 #include <LibGUI/Menu.h>
 #include <LibGUI/Painter.h>
 #include <LibGUI/Window.h>
+#include <LibGfx/Filters/ContrastFilter.h>
 
 namespace PixelPaint {
 
@@ -57,6 +58,9 @@ void MoveTool::on_mousemove(Layer* layer, MouseEvent& event)
         m_editor->update_tool_cursor();
     }
 
+    if (!m_layer_being_moved)
+        return;
+
     if (m_scaling) {
         auto cursor_location = event.image_event().position();
         auto width = abs(m_layer_being_moved->location().x() - cursor_location.x());
@@ -70,15 +74,13 @@ void MoveTool::on_mousemove(Layer* layer, MouseEvent& event)
         }
         m_new_layer_size = Gfx::IntSize(width, height);
         // TODO: Change this according to which direction the user is scaling
-        m_new_scaled_layer_location = Gfx::IntPoint(m_layer_being_moved->location().x(), m_layer_being_moved->location().y());
+        m_new_scaled_layer_location = m_layer_being_moved->location();
+    } else {
+        auto& image_event = event.image_event();
+        auto delta = image_event.position() - m_event_origin;
+        m_layer_being_moved->set_location(m_layer_origin.translated(delta));
     }
-
-    auto& image_event = event.image_event();
-    if (!m_layer_being_moved || m_scaling)
-        return;
-    auto delta = image_event.position() - m_event_origin;
-    m_layer_being_moved->set_location(m_layer_origin.translated(delta));
-    m_editor->layers_did_change();
+    m_editor->update();
 }
 
 void MoveTool::on_mouseup(Layer* layer, MouseEvent& event)
@@ -98,10 +100,12 @@ void MoveTool::on_mouseup(Layer* layer, MouseEvent& event)
 
     if (m_scaling) {
         m_editor->active_layer()->resize(m_new_layer_size, m_new_scaled_layer_location, Gfx::Painter::ScalingMode::BilinearBlend);
+        m_editor->layers_did_change();
     }
 
     m_scaling = false;
     m_layer_being_moved = nullptr;
+    m_cached_preview_bitmap = nullptr;
     m_editor->update_tool_cursor();
     m_editor->did_complete_action(tool_name());
 }
@@ -151,6 +155,38 @@ void MoveTool::on_keyup(GUI::KeyEvent& event)
         m_keep_ascept_ratio = false;
 }
 
+void MoveTool::on_second_paint(Layer const* layer, GUI::PaintEvent& event)
+{
+    if (layer != m_layer_being_moved.ptr() || !m_scaling)
+        return;
+
+    GUI::Painter painter(*m_editor);
+    painter.add_clip_rect(event.rect());
+    painter.translate(editor_layer_location(*layer));
+
+    auto dst_rect = Gfx::IntRect(Gfx::IntPoint(0, 0), m_scaling ? m_new_layer_size : layer->size());
+    auto rect_in_editor = m_editor->content_to_frame_rect(dst_rect).to_rounded<int>();
+    painter.draw_rect(rect_in_editor, Color::Black);
+    if (!m_cached_preview_bitmap.is_null() || !update_cached_preview_bitmap(layer).is_error()) {
+        painter.add_clip_rect(m_editor->content_rect());
+        painter.draw_scaled_bitmap(rect_in_editor, *m_cached_preview_bitmap, m_cached_preview_bitmap->rect(), 1.0f, Gfx::Painter::ScalingMode::BilinearBlend);
+    }
+}
+
+ErrorOr<void> MoveTool::update_cached_preview_bitmap(Layer const* layer)
+{
+    auto editor_rect_size = m_editor->frame_inner_rect().size();
+    auto const& source_bitmap = layer->content_bitmap();
+    auto preview_bitmap_size = editor_rect_size.contains(source_bitmap.size()) ? source_bitmap.size() : editor_rect_size;
+
+    m_cached_preview_bitmap = TRY(Gfx::Bitmap::try_create(source_bitmap.format(), preview_bitmap_size));
+    GUI::Painter preview_painter(*m_cached_preview_bitmap);
+    preview_painter.draw_scaled_bitmap(m_cached_preview_bitmap->rect(), source_bitmap, source_bitmap.rect(), 0.8f, Gfx::Painter::ScalingMode::BilinearBlend);
+    Gfx::ContrastFilter preview_filter(0.5f);
+    preview_filter.apply(*m_cached_preview_bitmap, m_cached_preview_bitmap->rect(), *m_cached_preview_bitmap, m_cached_preview_bitmap->rect());
+    return {};
+}
+
 Variant<Gfx::StandardCursor, NonnullRefPtr<Gfx::Bitmap>> MoveTool::cursor()
 {
     if (m_mouse_in_resize_corner || m_scaling)

+ 4 - 0
Userland/Applications/PixelPaint/Tools/MoveTool.h

@@ -22,10 +22,12 @@ public:
     virtual void on_mouseup(Layer*, MouseEvent&) override;
     virtual bool on_keydown(GUI::KeyEvent&) override;
     virtual void on_keyup(GUI::KeyEvent&) override;
+    virtual void on_second_paint(Layer const*, GUI::PaintEvent&) override;
     virtual Variant<Gfx::StandardCursor, NonnullRefPtr<Gfx::Bitmap>> cursor() override;
 
 private:
     virtual StringView tool_name() const override { return "Move Tool"sv; }
+    ErrorOr<void> update_cached_preview_bitmap(Layer const* layer);
 
     RefPtr<Layer> m_layer_being_moved;
     Gfx::IntPoint m_event_origin;
@@ -35,6 +37,8 @@ private:
     bool m_scaling { false };
     bool m_mouse_in_resize_corner { false };
     bool m_keep_ascept_ratio { false };
+
+    RefPtr<Gfx::Bitmap> m_cached_preview_bitmap { nullptr };
 };
 
 }