PixelPaint: Draw the current editor selection as marching ants

This patch moves the marching ants painting code to Selection and
unifies the timer mechanism so that all marching ants are synchronized
which looks neat. :^)
This commit is contained in:
Andreas Kling 2021-06-14 17:45:59 +02:00
parent 1b897ec561
commit 4cecd79000
Notes: sideshowbarker 2024-07-18 12:14:40 +09:00
5 changed files with 51 additions and 46 deletions

View File

@ -20,6 +20,7 @@ namespace PixelPaint {
ImageEditor::ImageEditor()
: m_undo_stack(make<GUI::UndoStack>())
, m_selection(*this)
{
set_focus_policy(GUI::FocusPolicy::StrongFocus);
}

View File

@ -5,26 +5,14 @@
*/
#include "RectangleSelectTool.h"
#include "Image.h"
#include "ImageEditor.h"
#include "Layer.h"
#include <LibCore/Timer.h>
#include <LibGUI/Painter.h>
namespace PixelPaint {
constexpr int marching_ant_length = 4;
RectangleSelectTool::RectangleSelectTool()
{
m_marching_ants_timer = Core::Timer::create_repeating(80, [this] {
if (!m_editor)
return;
++m_marching_ants_offset;
m_marching_ants_offset %= marching_ant_length;
m_editor->update();
});
m_marching_ants_timer->start();
}
RectangleSelectTool::~RectangleSelectTool()
@ -63,33 +51,6 @@ void RectangleSelectTool::on_mouseup(Layer&, GUI::MouseEvent&, GUI::MouseEvent&
m_editor->selection().set(rect_in_image);
}
void RectangleSelectTool::draw_marching_ants(Gfx::Painter& painter, Gfx::IntRect const& rect) const
{
int offset = m_marching_ants_offset;
auto draw_pixel = [&](int x, int y) {
if ((offset % marching_ant_length) != 0)
painter.set_pixel(x, y, Color::Black);
offset++;
};
// Top line
for (int x = rect.left(); x <= rect.right(); ++x)
draw_pixel(x, rect.top());
// Right line
for (int y = rect.top() + 1; y <= rect.bottom(); ++y)
draw_pixel(rect.right(), y);
// Bottom line
for (int x = rect.right() - 1; x >= rect.left(); --x)
draw_pixel(x, rect.bottom());
// Left line
for (int y = rect.bottom() - 1; y > rect.top(); --y)
draw_pixel(rect.left(), y);
}
void RectangleSelectTool::on_second_paint(Layer const&, GUI::PaintEvent& event)
{
if (!m_selecting)
@ -101,7 +62,7 @@ void RectangleSelectTool::on_second_paint(Layer const&, GUI::PaintEvent& event)
auto rect_in_image = Gfx::IntRect::from_two_points(m_selection_start, m_selection_end);
auto rect_in_editor = m_editor->image_rect_to_editor_rect(rect_in_image);
draw_marching_ants(painter, rect_in_editor.to_type<int>());
m_editor->selection().draw_marching_ants(painter, rect_in_editor.to_type<int>());
}
}

View File

@ -21,13 +21,9 @@ public:
virtual void on_second_paint(Layer const&, GUI::PaintEvent&) override;
private:
void draw_marching_ants(Gfx::Painter&, Gfx::IntRect const&) const;
bool m_selecting { false };
Gfx::IntPoint m_selection_start;
Gfx::IntPoint m_selection_end;
RefPtr<Core::Timer> m_marching_ants_timer;
int m_marching_ants_offset { 0 };
};
}

View File

@ -10,9 +10,50 @@
namespace PixelPaint {
constexpr int marching_ant_length = 4;
void Selection::paint(Gfx::Painter& painter, ImageEditor const& editor)
{
painter.draw_rect(editor.image_rect_to_editor_rect(m_rect).to_type<int>(), Color::Magenta);
draw_marching_ants(painter, editor.image_rect_to_editor_rect(m_rect).to_type<int>());
}
Selection::Selection(ImageEditor& editor)
: m_editor(editor)
{
m_marching_ants_timer = Core::Timer::create_repeating(80, [this] {
++m_marching_ants_offset;
m_marching_ants_offset %= marching_ant_length;
if (!is_empty())
m_editor.update();
});
m_marching_ants_timer->start();
}
void Selection::draw_marching_ants(Gfx::Painter& painter, Gfx::IntRect const& rect) const
{
int offset = m_marching_ants_offset;
auto draw_pixel = [&](int x, int y) {
if ((offset % marching_ant_length) != 0)
painter.set_pixel(x, y, Color::Black);
offset++;
};
// Top line
for (int x = rect.left(); x <= rect.right(); ++x)
draw_pixel(x, rect.top());
// Right line
for (int y = rect.top() + 1; y <= rect.bottom(); ++y)
draw_pixel(rect.right(), y);
// Bottom line
for (int x = rect.right() - 1; x >= rect.left(); --x)
draw_pixel(x, rect.bottom());
// Left line
for (int y = rect.bottom() - 1; y > rect.top(); --y)
draw_pixel(rect.left(), y);
}
}

View File

@ -6,6 +6,7 @@
#pragma once
#include <LibCore/Timer.h>
#include <LibGfx/Rect.h>
namespace PixelPaint {
@ -15,7 +16,7 @@ class ImageEditor;
// Coordinates are image-relative.
class Selection {
public:
Selection() { }
explicit Selection(ImageEditor&);
bool is_empty() const { return m_rect.is_empty(); }
void clear() { m_rect = {}; }
@ -23,8 +24,13 @@ public:
void paint(Gfx::Painter&, ImageEditor const&);
void draw_marching_ants(Gfx::Painter&, Gfx::IntRect const&) const;
private:
ImageEditor& m_editor;
Gfx::IntRect m_rect;
RefPtr<Core::Timer> m_marching_ants_timer;
int m_marching_ants_offset { 0 };
};
}