summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Userland/Applications/PixelPaint/ImageEditor.cpp104
-rw-r--r--Userland/Applications/PixelPaint/ImageEditor.h10
-rw-r--r--Userland/Applications/PixelPaint/Selection.cpp97
-rw-r--r--Userland/Applications/PixelPaint/Selection.h11
-rw-r--r--Userland/Applications/PixelPaint/Tools/RectangleSelectTool.cpp2
5 files changed, 116 insertions, 108 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);
+ }
+}
+
}
diff --git a/Userland/Applications/PixelPaint/ImageEditor.h b/Userland/Applications/PixelPaint/ImageEditor.h
index 04f83c9b1e..5e9fb8e616 100644
--- a/Userland/Applications/PixelPaint/ImageEditor.h
+++ b/Userland/Applications/PixelPaint/ImageEditor.h
@@ -113,6 +113,9 @@ public:
bool is_modified();
+ void draw_marching_ants(Gfx::Painter&, Gfx::IntRect const&) const;
+ void draw_marching_ants(Gfx::Painter&, Mask const&) const;
+
private:
explicit ImageEditor(NonnullRefPtr<Image>);
@@ -140,6 +143,8 @@ private:
Gfx::IntRect mouse_indicator_rect_x() const;
Gfx::IntRect mouse_indicator_rect_y() const;
+ void paint_selection(Gfx::Painter&);
+
NonnullRefPtr<Image> m_image;
RefPtr<Layer> m_active_layer;
GUI::UndoStack m_undo_stack;
@@ -171,6 +176,11 @@ private:
Selection m_selection;
bool m_loaded_from_image { true };
+
+ RefPtr<Core::Timer> m_marching_ants_timer;
+ int m_marching_ants_offset { 0 };
+
+ void draw_marching_ants_pixel(Gfx::Painter&, int x, int y) const;
};
}
diff --git a/Userland/Applications/PixelPaint/Selection.cpp b/Userland/Applications/PixelPaint/Selection.cpp
index a55975fe7f..57d81ea5fc 100644
--- a/Userland/Applications/PixelPaint/Selection.cpp
+++ b/Userland/Applications/PixelPaint/Selection.cpp
@@ -10,95 +10,9 @@
namespace PixelPaint {
-constexpr int marching_ant_length = 4;
-
-void Selection::paint(Gfx::Painter& painter)
-{
- draw_marching_ants(painter, m_mask);
-}
-
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 * 2);
- if (!is_empty() || m_in_interactive_selection)
- m_editor.update();
- });
- m_marching_ants_timer->start();
-}
-
-void Selection::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 Selection::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 / m_editor.scale()));
-
- // Only check the visible selection area when drawing for performance
- auto rect = m_editor.rect();
- rect = Gfx::enclosing_int_rect(m_editor.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 = m_editor.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 = m_editor.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 Selection::clear()
@@ -127,15 +41,4 @@ void Selection::merge(Mask const& mask, MergeMode mode)
}
}
-void Selection::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);
- }
-}
-
}
diff --git a/Userland/Applications/PixelPaint/Selection.h b/Userland/Applications/PixelPaint/Selection.h
index 4080b9c09e..7f269cc1e0 100644
--- a/Userland/Applications/PixelPaint/Selection.h
+++ b/Userland/Applications/PixelPaint/Selection.h
@@ -40,22 +40,17 @@ public:
[[nodiscard]] u8 get_selection_alpha(int x, int y) const { return m_mask.get(x, y); }
[[nodiscard]] u8 get_selection_alpha(Gfx::IntPoint const& point) const { return get_selection_alpha(point.x(), point.y()); }
- void paint(Gfx::Painter&);
-
- void draw_marching_ants(Gfx::Painter&, Gfx::IntRect const&) const;
- void draw_marching_ants(Gfx::Painter&, Mask const&) const;
+ Mask const& mask() const { return m_mask; }
void begin_interactive_selection() { m_in_interactive_selection = true; }
void end_interactive_selection() { m_in_interactive_selection = false; }
+ bool in_interactive_selection() { return m_in_interactive_selection; }
+
private:
ImageEditor& m_editor;
Mask m_mask;
- RefPtr<Core::Timer> m_marching_ants_timer;
- int m_marching_ants_offset { 0 };
bool m_in_interactive_selection { false };
-
- void draw_marching_ants_pixel(Gfx::Painter&, int x, int y) const;
};
}
diff --git a/Userland/Applications/PixelPaint/Tools/RectangleSelectTool.cpp b/Userland/Applications/PixelPaint/Tools/RectangleSelectTool.cpp
index 0d2d7daea1..890aa9bc4f 100644
--- a/Userland/Applications/PixelPaint/Tools/RectangleSelectTool.cpp
+++ b/Userland/Applications/PixelPaint/Tools/RectangleSelectTool.cpp
@@ -136,7 +136,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->content_to_frame_rect(rect_in_image);
- m_editor->selection().draw_marching_ants(painter, rect_in_editor.to_type<int>());
+ m_editor->draw_marching_ants(painter, rect_in_editor.to_rounded<int>());
}
GUI::Widget* RectangleSelectTool::get_properties_widget()