diff options
Diffstat (limited to 'Userland/Applications/PixelPaint/ImageEditor.cpp')
-rw-r--r-- | Userland/Applications/PixelPaint/ImageEditor.cpp | 104 |
1 files changed, 102 insertions, 2 deletions
diff --git a/Userland/Applications/PixelPaint/ImageEditor.cpp b/Userland/Applications/PixelPaint/ImageEditor.cpp index 3723034673..637d11a9c8 100644 --- a/Userland/Applications/PixelPaint/ImageEditor.cpp +++ b/Userland/Applications/PixelPaint/ImageEditor.cpp @@ -25,6 +25,8 @@ namespace PixelPaint { +constexpr int marching_ant_length = 4; + ImageEditor::ImageEditor(NonnullRefPtr<Image> image) : m_image(move(image)) , m_title("Untitled") @@ -41,6 +43,14 @@ ImageEditor::ImageEditor(NonnullRefPtr<Image> image) m_show_rulers = Config::read_bool("PixelPaint"sv, "Rulers"sv, "Show"sv, true); m_show_guides = Config::read_bool("PixelPaint"sv, "Guides"sv, "Show"sv, true); + + m_marching_ants_timer = Core::Timer::create_repeating(80, [this] { + ++m_marching_ants_offset; + m_marching_ants_offset %= (marching_ant_length * 2); + if (!m_selection.is_empty() || m_selection.in_interactive_selection()) + update(); + }); + m_marching_ants_timer->start(); } ImageEditor::~ImageEditor() @@ -158,8 +168,7 @@ void ImageEditor::paint_event(GUI::PaintEvent& event) } } - if (!m_selection.is_empty()) - m_selection.paint(painter); + paint_selection(painter); if (m_show_rulers) { auto const ruler_bg_color = palette().color(Gfx::ColorRole::InactiveSelection); @@ -651,4 +660,95 @@ void ImageEditor::set_loaded_from_image(bool loaded_from_image) m_loaded_from_image = loaded_from_image; } +void ImageEditor::paint_selection(Gfx::Painter& painter) +{ + if (m_selection.is_empty()) + return; + + draw_marching_ants(painter, m_selection.mask()); +} + +void ImageEditor::draw_marching_ants(Gfx::Painter& painter, Gfx::IntRect const& rect) const +{ + // Top line + for (int x = rect.left(); x <= rect.right(); ++x) + draw_marching_ants_pixel(painter, x, rect.top()); + + // Right line + for (int y = rect.top() + 1; y <= rect.bottom(); ++y) + draw_marching_ants_pixel(painter, rect.right(), y); + + // Bottom line + for (int x = rect.right() - 1; x >= rect.left(); --x) + draw_marching_ants_pixel(painter, x, rect.bottom()); + + // Left line + for (int y = rect.bottom() - 1; y > rect.top(); --y) + draw_marching_ants_pixel(painter, rect.left(), y); +} + +void ImageEditor::draw_marching_ants(Gfx::Painter& painter, Mask const& mask) const +{ + // If the zoom is < 100%, we can skip pixels to save a lot of time drawing the ants + int step = max(1, (int)floorf(1.0f / scale())); + + // Only check the visible selection area when drawing for performance + auto rect = this->rect(); + rect = Gfx::enclosing_int_rect(frame_to_content_rect(rect)); + rect.inflate(step * 2, step * 2); // prevent borders from having visible ants if the selection extends beyond it + + // Scan the image horizontally to find vertical borders + for (int y = rect.top(); y <= rect.bottom(); y += step) { + + bool previous_selected = false; + for (int x = rect.left(); x <= rect.right(); x += step) { + bool this_selected = mask.get(x, y) > 0; + + if (this_selected != previous_selected) { + Gfx::IntRect image_pixel { x, y, 1, 1 }; + auto pixel = content_to_frame_rect(image_pixel).to_type<int>(); + auto end = max(pixel.top(), pixel.bottom()); // for when the zoom is < 100% + + for (int pixel_y = pixel.top(); pixel_y <= end; pixel_y++) { + draw_marching_ants_pixel(painter, pixel.left(), pixel_y); + } + } + + previous_selected = this_selected; + } + } + + // Scan the image vertically to find horizontal borders + for (int x = rect.left(); x <= rect.right(); x += step) { + + bool previous_selected = false; + for (int y = rect.top(); y <= rect.bottom(); y += step) { + bool this_selected = mask.get(x, y) > 0; + + if (this_selected != previous_selected) { + Gfx::IntRect image_pixel { x, y, 1, 1 }; + auto pixel = content_to_frame_rect(image_pixel).to_type<int>(); + auto end = max(pixel.left(), pixel.right()); // for when the zoom is < 100% + + for (int pixel_x = pixel.left(); pixel_x <= end; pixel_x++) { + draw_marching_ants_pixel(painter, pixel_x, pixel.top()); + } + } + + previous_selected = this_selected; + } + } +} + +void ImageEditor::draw_marching_ants_pixel(Gfx::Painter& painter, int x, int y) const +{ + int pattern_index = x + y + m_marching_ants_offset; + + if (pattern_index % (marching_ant_length * 2) < marching_ant_length) { + painter.set_pixel(x, y, Color::Black); + } else { + painter.set_pixel(x, y, Color::White); + } +} + } |