mirror of
https://github.com/RGBCube/serenity
synced 2025-07-25 07:27:45 +00:00
PixelPaint: Fix Line/Rectangle second paint alignment with pixels
The problem was a bit more complex than originally anticipated, and the root of the problem is that the "coordinates" of a pixel are actually the top left of the pixel, and when we're really zoomed in, the difference in editor coordinates of the top-left and the center of the pixel is significant. So, we need to offset the "start" point when we are painting on the editor to account for this, based on the current scale. This patch adds a `editor_stroke_position` in `Tool` which can be used to compute what point (in editor coords) we should use for a given pixel and it's corresponding stroke thickness. Note that this doesn't really work well with the ellipse, since that is drawn with a different mechanism. Using this new method with the `EllipseTool` seems to give the same (or slightly worse) results, so I have not changed anything there for now.
This commit is contained in:
parent
9097f86e51
commit
1d47d41c01
4 changed files with 14 additions and 4 deletions
|
@ -108,8 +108,8 @@ void LineTool::on_second_paint(Layer const* layer, GUI::PaintEvent& event)
|
||||||
|
|
||||||
GUI::Painter painter(*m_editor);
|
GUI::Painter painter(*m_editor);
|
||||||
painter.add_clip_rect(event.rect());
|
painter.add_clip_rect(event.rect());
|
||||||
auto preview_start = m_editor->layer_position_to_editor_position(*layer, m_line_start_position).to_type<int>();
|
auto preview_start = editor_stroke_position(m_line_start_position, m_thickness);
|
||||||
auto preview_end = m_editor->layer_position_to_editor_position(*layer, m_line_end_position).to_type<int>();
|
auto preview_end = editor_stroke_position(m_line_end_position, m_thickness);
|
||||||
painter.draw_line(preview_start, preview_end, m_editor->color_for(m_drawing_button), AK::max(m_thickness * m_editor->scale(), 1));
|
painter.draw_line(preview_start, preview_end, m_editor->color_for(m_drawing_button), AK::max(m_thickness * m_editor->scale(), 1));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -106,8 +106,8 @@ void RectangleTool::on_second_paint(Layer const* layer, GUI::PaintEvent& event)
|
||||||
|
|
||||||
GUI::Painter painter(*m_editor);
|
GUI::Painter painter(*m_editor);
|
||||||
painter.add_clip_rect(event.rect());
|
painter.add_clip_rect(event.rect());
|
||||||
auto start_position = m_editor->layer_position_to_editor_position(*layer, m_rectangle_start_position).to_type<int>();
|
auto start_position = editor_stroke_position(m_rectangle_start_position, m_thickness);
|
||||||
auto end_position = m_editor->layer_position_to_editor_position(*layer, m_rectangle_end_position).to_type<int>();
|
auto end_position = editor_stroke_position(m_rectangle_end_position, m_thickness);
|
||||||
draw_using(painter, start_position, end_position, AK::max(m_thickness * m_editor->scale(), 1));
|
draw_using(painter, start_position, end_position, AK::max(m_thickness * m_editor->scale(), 1));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -53,4 +53,12 @@ void Tool::on_keydown(GUI::KeyEvent& event)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Gfx::IntPoint Tool::editor_stroke_position(Gfx::IntPoint const& pixel_coords, int stroke_thickness) const
|
||||||
|
{
|
||||||
|
auto position = m_editor->image_position_to_editor_position(pixel_coords);
|
||||||
|
auto offset = (stroke_thickness % 2 == 0) ? m_editor->scale() : m_editor->scale() / 2;
|
||||||
|
position = position.translated(offset, offset);
|
||||||
|
return position.to_type<int>();
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -76,6 +76,8 @@ protected:
|
||||||
WeakPtr<ImageEditor> m_editor;
|
WeakPtr<ImageEditor> m_editor;
|
||||||
RefPtr<GUI::Action> m_action;
|
RefPtr<GUI::Action> m_action;
|
||||||
|
|
||||||
|
virtual Gfx::IntPoint editor_stroke_position(Gfx::IntPoint const& pixel_coords, int stroke_thickness) const;
|
||||||
|
|
||||||
void set_primary_slider(GUI::ValueSlider* primary) { m_primary_slider = primary; }
|
void set_primary_slider(GUI::ValueSlider* primary) { m_primary_slider = primary; }
|
||||||
void set_secondary_slider(GUI::ValueSlider* secondary) { m_secondary_slider = secondary; }
|
void set_secondary_slider(GUI::ValueSlider* secondary) { m_secondary_slider = secondary; }
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue