diff options
author | Davipb <daviparca@gmail.com> | 2021-06-20 10:57:30 -0300 |
---|---|---|
committer | Andreas Kling <kling@serenityos.org> | 2021-06-22 11:00:00 +0200 |
commit | e58f78e667796871c13e2de2ccac81caca99bf37 (patch) | |
tree | 942d085808f38ba81bc10036040912b5e3fdc4bd /Userland/Applications | |
parent | 22585e2845c0b9a3ea7799f576239a5478a18050 (diff) | |
download | serenity-e58f78e667796871c13e2de2ccac81caca99bf37.zip |
PixelPaint: Add more options to RectangleSelectTool
A "feather" value sets by how much the borders of the selection will be
smoothed, and a "mode" value sets how the newly selected region will
interact with an existing image selection (if any).
Diffstat (limited to 'Userland/Applications')
-rw-r--r-- | Userland/Applications/PixelPaint/RectangleSelectTool.cpp | 113 | ||||
-rw-r--r-- | Userland/Applications/PixelPaint/RectangleSelectTool.h | 9 |
2 files changed, 121 insertions, 1 deletions
diff --git a/Userland/Applications/PixelPaint/RectangleSelectTool.cpp b/Userland/Applications/PixelPaint/RectangleSelectTool.cpp index 70d0c366a7..25038e9ed0 100644 --- a/Userland/Applications/PixelPaint/RectangleSelectTool.cpp +++ b/Userland/Applications/PixelPaint/RectangleSelectTool.cpp @@ -7,7 +7,14 @@ #include "RectangleSelectTool.h" #include "ImageEditor.h" #include "Layer.h" +#include <LibGUI/BoxLayout.h> +#include <LibGUI/Button.h> +#include <LibGUI/ComboBox.h> +#include <LibGUI/ItemListModel.h> +#include <LibGUI/Label.h> +#include <LibGUI/Model.h> #include <LibGUI/Painter.h> +#include <LibGUI/Slider.h> namespace PixelPaint { @@ -60,7 +67,42 @@ void RectangleSelectTool::on_mouseup(Layer&, GUI::MouseEvent&, GUI::MouseEvent& m_editor->update(); auto rect_in_image = Gfx::IntRect::from_two_points(m_selection_start, m_selection_end); - m_editor->selection().merge(rect_in_image, Selection::MergeMode::Set); + auto mask = Mask::full(rect_in_image); + + auto feathering = ((mask.bounding_rect().size().to_type<float>() * .5f) * m_edge_feathering).to_type<int>(); + + // Multiply the alpha instead of setting it to ensure corners are feathered correctly + auto multiply_alpha = [&mask](int x, int y, float alpha) { + Gfx::IntPoint point { x, y }; + point += mask.bounding_rect().top_left(); + + float old_alpha = mask.getf(point); + mask.setf(point, old_alpha * alpha); + }; + + // Horizontal feathering + for (int offset = 0; offset < feathering.width(); offset++) { + // Add 1 to offset before dividing to ensure the first pixel won't always be transparent + float alpha = (float)(offset + 1) / (float)feathering.width(); + + for (int y = 0; y < mask.bounding_rect().height(); y++) { + multiply_alpha(offset, y, alpha); + multiply_alpha(mask.bounding_rect().width() - offset - 1, y, alpha); + } + } + + // Vertical feathering + for (int offset = 0; offset < feathering.height(); offset++) { + // Add 1 to offset before dividing to ensure the first pixel won't always be transparent + float alpha = (float)(offset + 1) / (float)feathering.height(); + + for (int x = 0; x < mask.bounding_rect().width(); x++) { + multiply_alpha(x, offset, alpha); + multiply_alpha(x, mask.bounding_rect().height() - offset - 1, alpha); + } + } + + m_editor->selection().merge(mask, m_merge_mode); } void RectangleSelectTool::on_keydown(GUI::KeyEvent& key_event) @@ -93,4 +135,73 @@ void RectangleSelectTool::on_second_paint(Layer const&, GUI::PaintEvent& event) m_editor->selection().draw_marching_ants(painter, rect_in_editor.to_type<int>()); } +GUI::Widget* RectangleSelectTool::get_properties_widget() +{ + if (m_properties_widget) { + return m_properties_widget.ptr(); + } + + m_properties_widget = GUI::Widget::construct(); + m_properties_widget->set_layout<GUI::VerticalBoxLayout>(); + + auto& feather_container = m_properties_widget->add<GUI::Widget>(); + feather_container.set_fixed_height(20); + feather_container.set_layout<GUI::HorizontalBoxLayout>(); + + auto& feather_label = feather_container.add<GUI::Label>(); + feather_label.set_text("Feather:"); + feather_label.set_text_alignment(Gfx::TextAlignment::CenterLeft); + feather_label.set_fixed_size(80, 20); + + int feather_slider_max = 10000; + auto& feather_slider = feather_container.add<GUI::HorizontalSlider>(); + feather_slider.set_fixed_height(20); + feather_slider.set_range(0, feather_slider_max); + feather_slider.set_value((int)floorf(m_edge_feathering * (float)feather_slider_max)); + feather_slider.on_change = [this, feather_slider_max](int value) { + m_edge_feathering = (float)value / (float)feather_slider_max; + }; + + auto& mode_container = m_properties_widget->add<GUI::Widget>(); + mode_container.set_fixed_height(20); + mode_container.set_layout<GUI::HorizontalBoxLayout>(); + + auto& mode_label = mode_container.add<GUI::Label>(); + mode_label.set_text("Mode:"); + mode_label.set_text_alignment(Gfx::TextAlignment::CenterLeft); + mode_label.set_fixed_size(80, 20); + + for (int i = 0; i < (int)Selection::MergeMode::__Count; i++) { + switch ((Selection::MergeMode)i) { + case Selection::MergeMode::Set: + m_merge_mode_names.append("Set"); + break; + case Selection::MergeMode::Add: + m_merge_mode_names.append("Add"); + break; + case Selection::MergeMode::Subtract: + m_merge_mode_names.append("Subtract"); + break; + case Selection::MergeMode::Intersect: + m_merge_mode_names.append("Intersect"); + break; + default: + VERIFY_NOT_REACHED(); + } + } + + auto& mode_combo = mode_container.add<GUI::ComboBox>(); + mode_combo.set_only_allow_values_from_model(true); + mode_combo.set_model(*GUI::ItemListModel<String>::create(m_merge_mode_names)); + mode_combo.set_selected_index((int)m_merge_mode); + mode_combo.on_change = [this](auto&&, GUI::ModelIndex const& index) { + VERIFY(index.row() >= 0); + VERIFY(index.row() < (int)Selection::MergeMode::__Count); + + m_merge_mode = (Selection::MergeMode)index.row(); + }; + + return m_properties_widget.ptr(); +} + } diff --git a/Userland/Applications/PixelPaint/RectangleSelectTool.h b/Userland/Applications/PixelPaint/RectangleSelectTool.h index a47fd35ee8..866dc417fa 100644 --- a/Userland/Applications/PixelPaint/RectangleSelectTool.h +++ b/Userland/Applications/PixelPaint/RectangleSelectTool.h @@ -6,8 +6,12 @@ #pragma once +#include "Selection.h" #include "Tool.h" +#include <AK/Vector.h> +#include <LibGUI/Widget.h> + namespace PixelPaint { class RectangleSelectTool final : public Tool { @@ -21,6 +25,7 @@ public: virtual void on_keydown(GUI::KeyEvent&) override; virtual void on_keyup(GUI::KeyEvent&) override; virtual void on_second_paint(Layer const&, GUI::PaintEvent&) override; + virtual GUI::Widget* get_properties_widget() override; private: enum class MovingMode { @@ -29,6 +34,10 @@ private: None, }; + RefPtr<GUI::Widget> m_properties_widget; + Vector<String> m_merge_mode_names {}; + Selection::MergeMode m_merge_mode { Selection::MergeMode::Set }; + float m_edge_feathering { 0.0f }; bool m_selecting { false }; MovingMode m_moving_mode { MovingMode::None }; Gfx::IntPoint m_selection_start; |