diff --git a/Userland/Applications/PixelPaint/Layer.cpp b/Userland/Applications/PixelPaint/Layer.cpp index 3c8bab3035..6a8c38cb90 100644 --- a/Userland/Applications/PixelPaint/Layer.cpp +++ b/Userland/Applications/PixelPaint/Layer.cpp @@ -1,6 +1,7 @@ /* * Copyright (c) 2020-2021, Andreas Kling * Copyright (c) 2022, Tobias Christiansen + * Copyright (c) 2022, Timothy Slater * * SPDX-License-Identifier: BSD-2-Clause */ @@ -65,6 +66,21 @@ Layer::Layer(Image& image, NonnullRefPtr bitmap, String name) void Layer::did_modify_bitmap(Gfx::IntRect const& rect) { + if (!m_scratch_edited_bitmap.is_null()) { + for (int y = 0; y < rect.height(); ++y) { + for (int x = 0; x < rect.width(); ++x) { + Gfx::IntPoint next_point = { rect.left() + x, rect.top() + y }; + if (!m_scratch_edited_bitmap->rect().contains(next_point)) + continue; + + if (this->image().selection().is_selected(next_point.translated(this->location()))) + currently_edited_bitmap().set_pixel(next_point, m_scratch_edited_bitmap->get_pixel(next_point)); + else + m_scratch_edited_bitmap->set_pixel(next_point, currently_edited_bitmap().get_pixel(next_point)); + } + } + } + m_image.layer_did_modify_bitmap({}, *this, rect); update_cached_bitmap(); } @@ -93,6 +109,21 @@ void Layer::set_name(String name) m_image.layer_did_modify_properties({}, *this); } +Gfx::Bitmap& Layer::get_scratch_edited_bitmap() +{ + if (this->image().selection().is_empty()) { + m_scratch_edited_bitmap = nullptr; + return currently_edited_bitmap(); + } + + if (!m_scratch_edited_bitmap.is_null()) + return *m_scratch_edited_bitmap; + + m_scratch_edited_bitmap = MUST(currently_edited_bitmap().clone()); + + return *m_scratch_edited_bitmap; +} + RefPtr Layer::try_copy_bitmap(Selection const& selection) const { if (selection.is_empty()) { @@ -158,6 +189,7 @@ ErrorOr Layer::try_set_bitmaps(NonnullRefPtr content, RefPtr< m_content_bitmap = move(content); m_mask_bitmap = move(mask); + m_scratch_edited_bitmap = nullptr; update_cached_bitmap(); return {}; } @@ -274,7 +306,7 @@ void Layer::set_edit_mode(Layer::EditMode mode) { if (m_edit_mode == mode) return; - + m_scratch_edited_bitmap = nullptr; m_edit_mode = mode; } diff --git a/Userland/Applications/PixelPaint/Layer.h b/Userland/Applications/PixelPaint/Layer.h index a2996e24c0..6e5121ecee 100644 --- a/Userland/Applications/PixelPaint/Layer.h +++ b/Userland/Applications/PixelPaint/Layer.h @@ -2,6 +2,7 @@ * Copyright (c) 2020-2021, Andreas Kling * Copyright (c) 2022, the SerenityOS developers. * Copyright (c) 2022, Tobias Christiansen + * Copyright (c) 2022, Timothy Slater * * SPDX-License-Identifier: BSD-2-Clause */ @@ -45,6 +46,7 @@ public: Gfx::Bitmap* mask_bitmap() { return m_mask_bitmap; } void create_mask(); + Gfx::Bitmap& get_scratch_edited_bitmap(); Gfx::IntSize size() const { return content_bitmap().size(); } @@ -102,6 +104,7 @@ private: String m_name; Gfx::IntPoint m_location; NonnullRefPtr m_content_bitmap; + RefPtr m_scratch_edited_bitmap { nullptr }; RefPtr m_mask_bitmap { nullptr }; NonnullRefPtr m_cached_display_bitmap; diff --git a/Userland/Applications/PixelPaint/Tools/BrushTool.cpp b/Userland/Applications/PixelPaint/Tools/BrushTool.cpp index 802ebbc0d2..88568da916 100644 --- a/Userland/Applications/PixelPaint/Tools/BrushTool.cpp +++ b/Userland/Applications/PixelPaint/Tools/BrushTool.cpp @@ -29,7 +29,7 @@ void BrushTool::on_mousedown(Layer* layer, MouseEvent& event) // Shift+Click draws a line from the last position to current one. if (layer_event.shift() && m_has_clicked) { - draw_line(layer->currently_edited_bitmap(), color_for(layer_event), m_last_position, layer_event.position()); + draw_line(layer->get_scratch_edited_bitmap(), color_for(layer_event), m_last_position, layer_event.position()); auto modified_rect = Gfx::IntRect::from_two_points(m_last_position, layer_event.position()).inflated(m_size * 2, m_size * 2); layer->did_modify_bitmap(modified_rect); m_last_position = layer_event.position(); @@ -39,7 +39,7 @@ void BrushTool::on_mousedown(Layer* layer, MouseEvent& event) int const first_draw_opacity = 10; for (int i = 0; i < first_draw_opacity; ++i) - draw_point(layer->currently_edited_bitmap(), color_for(layer_event), layer_event.position()); + draw_point(layer->get_scratch_edited_bitmap(), color_for(layer_event), layer_event.position()); layer->did_modify_bitmap(Gfx::IntRect::centered_on(layer_event.position(), Gfx::IntSize { m_size * 2, m_size * 2 })); m_last_position = layer_event.position(); @@ -55,7 +55,7 @@ void BrushTool::on_mousemove(Layer* layer, MouseEvent& event) if (!(layer_event.buttons() & GUI::MouseButton::Primary || layer_event.buttons() & GUI::MouseButton::Secondary)) return; - draw_line(layer->currently_edited_bitmap(), color_for(layer_event), m_last_position, layer_event.position()); + draw_line(layer->get_scratch_edited_bitmap(), color_for(layer_event), m_last_position, layer_event.position()); auto modified_rect = Gfx::IntRect::from_two_points(m_last_position, layer_event.position()).inflated(m_size * 2, m_size * 2); diff --git a/Userland/Applications/PixelPaint/Tools/BucketTool.cpp b/Userland/Applications/PixelPaint/Tools/BucketTool.cpp index 4cba2b9699..80228d5fc7 100644 --- a/Userland/Applications/PixelPaint/Tools/BucketTool.cpp +++ b/Userland/Applications/PixelPaint/Tools/BucketTool.cpp @@ -50,11 +50,11 @@ void BucketTool::on_mousedown(Layer* layer, MouseEvent& event) if (!layer->rect().contains(layer_event.position())) return; - GUI::Painter painter(layer->currently_edited_bitmap()); + GUI::Painter painter(layer->get_scratch_edited_bitmap()); - flood_fill(layer->currently_edited_bitmap(), layer_event.position(), m_editor->color_for(layer_event), m_threshold); + flood_fill(layer->get_scratch_edited_bitmap(), layer_event.position(), m_editor->color_for(layer_event), m_threshold); - layer->did_modify_bitmap(); + layer->did_modify_bitmap(layer->get_scratch_edited_bitmap().rect()); m_editor->did_complete_action(tool_name()); } diff --git a/Userland/Applications/PixelPaint/Tools/EllipseTool.cpp b/Userland/Applications/PixelPaint/Tools/EllipseTool.cpp index a9256cb100..aa3b676843 100644 --- a/Userland/Applications/PixelPaint/Tools/EllipseTool.cpp +++ b/Userland/Applications/PixelPaint/Tools/EllipseTool.cpp @@ -84,10 +84,10 @@ void EllipseTool::on_mouseup(Layer* layer, MouseEvent& event) return; if (event.layer_event().button() == m_drawing_button) { - GUI::Painter painter(layer->currently_edited_bitmap()); + GUI::Painter painter(layer->get_scratch_edited_bitmap()); draw_using(painter, m_ellipse_start_position, m_ellipse_end_position, m_thickness); m_drawing_button = GUI::MouseButton::None; - layer->did_modify_bitmap(); + layer->did_modify_bitmap(layer->get_scratch_edited_bitmap().rect()); m_editor->update(); m_editor->did_complete_action(tool_name()); } diff --git a/Userland/Applications/PixelPaint/Tools/LineTool.cpp b/Userland/Applications/PixelPaint/Tools/LineTool.cpp index dbb12f3f3b..5aebf8b885 100644 --- a/Userland/Applications/PixelPaint/Tools/LineTool.cpp +++ b/Userland/Applications/PixelPaint/Tools/LineTool.cpp @@ -76,10 +76,11 @@ void LineTool::on_mouseup(Layer* layer, MouseEvent& event) auto& layer_event = event.layer_event(); if (layer_event.button() == m_drawing_button) { - GUI::Painter painter(layer->currently_edited_bitmap()); + GUI::Painter painter(layer->get_scratch_edited_bitmap()); draw_using(painter, m_line_start_position, m_line_end_position, m_editor->color_for(m_drawing_button), m_thickness); m_drawing_button = GUI::MouseButton::None; - layer->did_modify_bitmap(); + auto modified_rect = Gfx::IntRect::from_two_points(m_line_start_position, m_line_end_position).inflated(m_thickness * 2, m_thickness * 2); + layer->did_modify_bitmap(modified_rect); m_editor->update(); m_editor->did_complete_action(tool_name()); } diff --git a/Userland/Applications/PixelPaint/Tools/RectangleTool.cpp b/Userland/Applications/PixelPaint/Tools/RectangleTool.cpp index 44fe26ec5c..fb88922eef 100644 --- a/Userland/Applications/PixelPaint/Tools/RectangleTool.cpp +++ b/Userland/Applications/PixelPaint/Tools/RectangleTool.cpp @@ -87,10 +87,11 @@ void RectangleTool::on_mouseup(Layer* layer, MouseEvent& event) return; if (event.layer_event().button() == m_drawing_button) { - GUI::Painter painter(layer->currently_edited_bitmap()); + GUI::Painter painter(layer->get_scratch_edited_bitmap()); draw_using(painter, m_rectangle_start_position, m_rectangle_end_position, m_thickness, m_corner_radius); m_drawing_button = GUI::MouseButton::None; - layer->did_modify_bitmap(); + auto modified_rect = Gfx::IntRect::from_two_points(m_rectangle_start_position, m_rectangle_end_position).inflated(m_thickness * 2, m_thickness * 2); + layer->did_modify_bitmap(modified_rect); m_editor->update(); m_editor->did_complete_action(tool_name()); } diff --git a/Userland/Applications/PixelPaint/Tools/SprayTool.cpp b/Userland/Applications/PixelPaint/Tools/SprayTool.cpp index 1118d6333f..a28bc03137 100644 --- a/Userland/Applications/PixelPaint/Tools/SprayTool.cpp +++ b/Userland/Applications/PixelPaint/Tools/SprayTool.cpp @@ -40,7 +40,7 @@ void SprayTool::paint_it() if (!layer) return; - auto& bitmap = layer->currently_edited_bitmap(); + auto& bitmap = layer->get_scratch_edited_bitmap(); GUI::Painter painter(bitmap); VERIFY(bitmap.bpp() == 32); double const minimal_radius = 2;