mirror of
https://github.com/LadybirdBrowser/ladybird.git
synced 2024-11-22 15:40:19 +00:00
PixelPaint: Add function to visualize editing-masks
This patch adds a function to make the editing-eask visible while beeing in mask-mode so that the user can see which parts are covered by the masks and can therefore be modified by other tools that support editing masks.
This commit is contained in:
parent
69650a5812
commit
660d6f171c
Notes:
sideshowbarker
2024-07-16 22:51:10 +09:00
Author: https://github.com/Torstennator Commit: https://github.com/SerenityOS/serenity/commit/660d6f171c Pull-request: https://github.com/SerenityOS/serenity/pull/19380 Reviewed-by: https://github.com/gmta ✅
6 changed files with 76 additions and 0 deletions
|
@ -290,6 +290,9 @@ Gfx::IntRect ImageEditor::mouse_indicator_rect_y() const
|
|||
|
||||
void ImageEditor::second_paint_event(GUI::PaintEvent& event)
|
||||
{
|
||||
if (m_active_layer && m_active_layer->mask_type() != Layer::MaskType::None)
|
||||
m_active_layer->on_second_paint(*this);
|
||||
|
||||
if (m_active_tool) {
|
||||
if (m_show_rulers) {
|
||||
auto clipped_event = GUI::PaintEvent(subtract_rulers_from_rect(event.rect()), event.window_size());
|
||||
|
@ -945,4 +948,15 @@ DeprecatedString ImageEditor::generate_unique_layer_name(DeprecatedString const&
|
|||
return new_layer_name.to_deprecated_string();
|
||||
}
|
||||
|
||||
Gfx::IntRect ImageEditor::active_layer_visible_rect()
|
||||
{
|
||||
if (!active_layer())
|
||||
return {};
|
||||
|
||||
auto scaled_layer_rect = active_layer()->relative_rect().to_type<float>().scaled(scale(), scale()).to_type<int>().translated(content_rect().location());
|
||||
auto visible_editor_rect = ruler_visibility() ? subtract_rulers_from_rect(rect()) : rect();
|
||||
scaled_layer_rect.intersect(visible_editor_rect);
|
||||
return scaled_layer_rect;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -37,6 +37,7 @@ public:
|
|||
|
||||
Layer* active_layer() { return m_active_layer; }
|
||||
void set_active_layer(Layer*);
|
||||
Gfx::IntRect active_layer_visible_rect();
|
||||
|
||||
ErrorOr<void> add_new_layer_from_selection();
|
||||
Tool* active_tool() { return m_active_tool; }
|
||||
|
|
|
@ -8,9 +8,11 @@
|
|||
|
||||
#include "Layer.h"
|
||||
#include "Image.h"
|
||||
#include "ImageEditor.h"
|
||||
#include "Selection.h"
|
||||
#include <AK/RefPtr.h>
|
||||
#include <AK/Try.h>
|
||||
#include <LibGUI/Painter.h>
|
||||
#include <LibGfx/Bitmap.h>
|
||||
#include <LibGfx/Painter.h>
|
||||
|
||||
|
@ -45,6 +47,7 @@ ErrorOr<NonnullRefPtr<Layer>> Layer::create_snapshot(Image& image, Layer const&
|
|||
snapshot->m_mask_bitmap = TRY(layer.mask_bitmap()->clone());
|
||||
snapshot->m_edit_mode = layer.m_edit_mode;
|
||||
snapshot->m_mask_type = layer.m_mask_type;
|
||||
snapshot->m_visible_mask = layer.m_visible_mask;
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -322,6 +325,7 @@ void Layer::delete_mask()
|
|||
{
|
||||
m_mask_bitmap = nullptr;
|
||||
m_mask_type = MaskType::None;
|
||||
m_visible_mask = false;
|
||||
set_edit_mode(EditMode::Content);
|
||||
update_cached_bitmap();
|
||||
}
|
||||
|
@ -464,4 +468,35 @@ Layer::MaskType Layer::mask_type()
|
|||
return m_mask_type;
|
||||
}
|
||||
|
||||
void Layer::on_second_paint(ImageEditor& editor)
|
||||
{
|
||||
if (!m_visible_mask || edit_mode() != EditMode::Mask)
|
||||
return;
|
||||
|
||||
auto visible_rect = editor.active_layer_visible_rect();
|
||||
if (visible_rect.width() == 0 || visible_rect.height() == 0)
|
||||
return;
|
||||
|
||||
GUI::Painter painter(editor);
|
||||
painter.translate(visible_rect.location());
|
||||
|
||||
auto content_offset = editor.content_to_frame_position(location());
|
||||
auto drawing_cursor_offset = visible_rect.location() - content_offset.to_type<int>();
|
||||
|
||||
Gfx::Color editing_mask_color = editor.primary_color();
|
||||
int mask_alpha;
|
||||
Gfx::IntPoint mask_coordinates;
|
||||
|
||||
for (int y = 0; y < visible_rect.height(); y++) {
|
||||
for (int x = 0; x < visible_rect.width(); x++) {
|
||||
mask_coordinates = (Gfx::FloatPoint(drawing_cursor_offset.x() + x, drawing_cursor_offset.y() + y) / editor.scale()).to_type<int>();
|
||||
mask_alpha = mask_bitmap()->get_pixel(mask_coordinates).alpha();
|
||||
if (!mask_alpha)
|
||||
continue;
|
||||
|
||||
painter.set_pixel(x, y, editing_mask_color.with_alpha(mask_alpha), true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -13,12 +13,14 @@
|
|||
#include <AK/Noncopyable.h>
|
||||
#include <AK/RefCounted.h>
|
||||
#include <AK/Weakable.h>
|
||||
#include <LibGUI/Event.h>
|
||||
#include <LibGfx/Bitmap.h>
|
||||
#include <LibGfx/Painter.h>
|
||||
|
||||
namespace PixelPaint {
|
||||
|
||||
class Image;
|
||||
class ImageEditor;
|
||||
class Selection;
|
||||
|
||||
class Layer
|
||||
|
@ -56,6 +58,8 @@ public:
|
|||
void apply_mask();
|
||||
void invert_mask();
|
||||
void clear_mask();
|
||||
void set_mask_visibility(bool visible) { m_visible_mask = visible; }
|
||||
bool mask_visibility() { return m_visible_mask; }
|
||||
|
||||
Gfx::Bitmap& get_scratch_edited_bitmap();
|
||||
|
||||
|
@ -126,6 +130,8 @@ public:
|
|||
return current_color.mixed_with(target_color, mask_intensity);
|
||||
}
|
||||
|
||||
void on_second_paint(ImageEditor&);
|
||||
|
||||
private:
|
||||
Layer(Image&, NonnullRefPtr<Gfx::Bitmap>, DeprecatedString name);
|
||||
|
||||
|
@ -140,6 +146,7 @@ private:
|
|||
|
||||
bool m_selected { false };
|
||||
bool m_visible { true };
|
||||
bool m_visible_mask { false };
|
||||
|
||||
int m_opacity_percent { 100 };
|
||||
|
||||
|
|
|
@ -853,6 +853,20 @@ ErrorOr<void> MainWidget::initialize_menubar(GUI::Window& window)
|
|||
}));
|
||||
TRY(m_layer_menu->try_add_action(*m_clear_mask_action));
|
||||
|
||||
m_toggle_mask_visibility_action = GUI::Action::create_checkable(
|
||||
"Show Mask", [&](auto&) {
|
||||
auto* editor = current_image_editor();
|
||||
VERIFY(editor);
|
||||
if (!editor->active_layer())
|
||||
return;
|
||||
|
||||
VERIFY(editor->active_layer()->is_masked());
|
||||
editor->active_layer()->set_mask_visibility(m_toggle_mask_visibility_action->is_checked());
|
||||
editor->update();
|
||||
});
|
||||
|
||||
TRY(m_layer_menu->try_add_action(*m_toggle_mask_visibility_action));
|
||||
|
||||
TRY(m_layer_menu->try_add_separator());
|
||||
|
||||
TRY(m_layer_menu->try_add_action(GUI::Action::create(
|
||||
|
@ -1232,6 +1246,8 @@ void MainWidget::set_mask_actions_for_layer(Layer* layer)
|
|||
m_clear_mask_action->set_visible(masked);
|
||||
m_delete_mask_action->set_visible(masked);
|
||||
m_apply_mask_action->set_visible(layer->mask_type() == Layer::MaskType::BasicMask);
|
||||
m_toggle_mask_visibility_action->set_visible(layer->mask_type() == Layer::MaskType::EditingMask);
|
||||
m_toggle_mask_visibility_action->set_checked(layer->mask_visibility());
|
||||
}
|
||||
|
||||
void MainWidget::open_image(FileSystemAccessClient::File file)
|
||||
|
@ -1373,6 +1389,8 @@ ImageEditor& MainWidget::create_new_editor(NonnullRefPtr<Image> image)
|
|||
m_palette_widget->set_primary_color(color);
|
||||
if (image_editor.active_tool())
|
||||
image_editor.active_tool()->on_primary_color_change(color);
|
||||
if (image_editor.active_layer()->mask_visibility())
|
||||
image_editor.update();
|
||||
};
|
||||
image_editor.on_secondary_color_change = [&](Color color) {
|
||||
m_palette_widget->set_secondary_color(color);
|
||||
|
|
|
@ -117,6 +117,7 @@ private:
|
|||
RefPtr<GUI::Action> m_add_editing_mask_action;
|
||||
RefPtr<GUI::Action> m_invert_mask_action;
|
||||
RefPtr<GUI::Action> m_clear_mask_action;
|
||||
RefPtr<GUI::Action> m_toggle_mask_visibility_action;
|
||||
|
||||
Gfx::IntPoint m_last_image_editor_mouse_position;
|
||||
};
|
||||
|
|
Loading…
Reference in a new issue