mirror of
https://github.com/RGBCube/serenity
synced 2025-07-25 16:27:35 +00:00
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:
parent
1b897ec561
commit
4cecd79000
5 changed files with 51 additions and 46 deletions
|
@ -20,6 +20,7 @@ namespace PixelPaint {
|
||||||
|
|
||||||
ImageEditor::ImageEditor()
|
ImageEditor::ImageEditor()
|
||||||
: m_undo_stack(make<GUI::UndoStack>())
|
: m_undo_stack(make<GUI::UndoStack>())
|
||||||
|
, m_selection(*this)
|
||||||
{
|
{
|
||||||
set_focus_policy(GUI::FocusPolicy::StrongFocus);
|
set_focus_policy(GUI::FocusPolicy::StrongFocus);
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,26 +5,14 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "RectangleSelectTool.h"
|
#include "RectangleSelectTool.h"
|
||||||
#include "Image.h"
|
|
||||||
#include "ImageEditor.h"
|
#include "ImageEditor.h"
|
||||||
#include "Layer.h"
|
#include "Layer.h"
|
||||||
#include <LibCore/Timer.h>
|
|
||||||
#include <LibGUI/Painter.h>
|
#include <LibGUI/Painter.h>
|
||||||
|
|
||||||
namespace PixelPaint {
|
namespace PixelPaint {
|
||||||
|
|
||||||
constexpr int marching_ant_length = 4;
|
|
||||||
|
|
||||||
RectangleSelectTool::RectangleSelectTool()
|
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()
|
RectangleSelectTool::~RectangleSelectTool()
|
||||||
|
@ -63,33 +51,6 @@ void RectangleSelectTool::on_mouseup(Layer&, GUI::MouseEvent&, GUI::MouseEvent&
|
||||||
m_editor->selection().set(rect_in_image);
|
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)
|
void RectangleSelectTool::on_second_paint(Layer const&, GUI::PaintEvent& event)
|
||||||
{
|
{
|
||||||
if (!m_selecting)
|
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_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);
|
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>());
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -21,13 +21,9 @@ public:
|
||||||
virtual void on_second_paint(Layer const&, GUI::PaintEvent&) override;
|
virtual void on_second_paint(Layer const&, GUI::PaintEvent&) override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void draw_marching_ants(Gfx::Painter&, Gfx::IntRect const&) const;
|
|
||||||
|
|
||||||
bool m_selecting { false };
|
bool m_selecting { false };
|
||||||
Gfx::IntPoint m_selection_start;
|
Gfx::IntPoint m_selection_start;
|
||||||
Gfx::IntPoint m_selection_end;
|
Gfx::IntPoint m_selection_end;
|
||||||
RefPtr<Core::Timer> m_marching_ants_timer;
|
|
||||||
int m_marching_ants_offset { 0 };
|
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -10,9 +10,50 @@
|
||||||
|
|
||||||
namespace PixelPaint {
|
namespace PixelPaint {
|
||||||
|
|
||||||
|
constexpr int marching_ant_length = 4;
|
||||||
|
|
||||||
void Selection::paint(Gfx::Painter& painter, ImageEditor const& editor)
|
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);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,6 +6,7 @@
|
||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#include <LibCore/Timer.h>
|
||||||
#include <LibGfx/Rect.h>
|
#include <LibGfx/Rect.h>
|
||||||
|
|
||||||
namespace PixelPaint {
|
namespace PixelPaint {
|
||||||
|
@ -15,7 +16,7 @@ class ImageEditor;
|
||||||
// Coordinates are image-relative.
|
// Coordinates are image-relative.
|
||||||
class Selection {
|
class Selection {
|
||||||
public:
|
public:
|
||||||
Selection() { }
|
explicit Selection(ImageEditor&);
|
||||||
|
|
||||||
bool is_empty() const { return m_rect.is_empty(); }
|
bool is_empty() const { return m_rect.is_empty(); }
|
||||||
void clear() { m_rect = {}; }
|
void clear() { m_rect = {}; }
|
||||||
|
@ -23,8 +24,13 @@ public:
|
||||||
|
|
||||||
void paint(Gfx::Painter&, ImageEditor const&);
|
void paint(Gfx::Painter&, ImageEditor const&);
|
||||||
|
|
||||||
|
void draw_marching_ants(Gfx::Painter&, Gfx::IntRect const&) const;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
ImageEditor& m_editor;
|
||||||
Gfx::IntRect m_rect;
|
Gfx::IntRect m_rect;
|
||||||
|
RefPtr<Core::Timer> m_marching_ants_timer;
|
||||||
|
int m_marching_ants_offset { 0 };
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue