mirror of
https://github.com/RGBCube/serenity
synced 2025-07-28 01:07:44 +00:00
PixelPaint: Add a preview in FilterGallery
Now FilterGallery shows the preview of the currently selected filter applied on the currently active layer
This commit is contained in:
parent
44cf3ac60f
commit
e9d3f3793c
11 changed files with 155 additions and 4 deletions
|
@ -17,6 +17,7 @@ set(SOURCES
|
|||
FilterGallery.cpp
|
||||
FilterGalleryGML.h
|
||||
FilterModel.cpp
|
||||
FilterPreviewWidget.cpp
|
||||
Filters/Bloom.cpp
|
||||
Filters/BoxBlur3.cpp
|
||||
Filters/BoxBlur5.cpp
|
||||
|
|
|
@ -29,11 +29,13 @@ FilterGallery::FilterGallery(GUI::Window* parent_window, ImageEditor* editor)
|
|||
auto apply_button = main_widget.find_descendant_of_type_named<GUI::Button>("apply_button");
|
||||
auto cancel_button = main_widget.find_descendant_of_type_named<GUI::Button>("cancel_button");
|
||||
m_config_widget = main_widget.find_descendant_of_type_named<GUI::Widget>("config_widget");
|
||||
m_preview_widget = main_widget.find_descendant_of_type_named<FilterPreviewWidget>("preview_widget");
|
||||
|
||||
VERIFY(m_filter_tree);
|
||||
VERIFY(apply_button);
|
||||
VERIFY(cancel_button);
|
||||
VERIFY(m_config_widget);
|
||||
VERIFY(m_preview_widget);
|
||||
|
||||
auto filter_model = FilterModel::create(editor);
|
||||
m_filter_tree->set_model(filter_model);
|
||||
|
@ -41,20 +43,30 @@ FilterGallery::FilterGallery(GUI::Window* parent_window, ImageEditor* editor)
|
|||
|
||||
m_filter_tree->on_selection_change = [this]() {
|
||||
auto selected_index = m_filter_tree->selection().first();
|
||||
if (!selected_index.is_valid())
|
||||
if (!selected_index.is_valid()) {
|
||||
m_preview_widget->clear_filter();
|
||||
return;
|
||||
}
|
||||
|
||||
auto selected_filter = static_cast<const FilterModel::FilterInfo*>(selected_index.internal_data());
|
||||
if (selected_filter->type != FilterModel::FilterInfo::Type::Filter)
|
||||
if (selected_filter->type != FilterModel::FilterInfo::Type::Filter) {
|
||||
m_preview_widget->clear_filter();
|
||||
return;
|
||||
}
|
||||
|
||||
m_selected_filter = selected_filter->filter;
|
||||
m_selected_filter->on_settings_change = [&]() {
|
||||
m_preview_widget->set_filter(m_selected_filter);
|
||||
};
|
||||
m_preview_widget->set_filter(m_selected_filter);
|
||||
|
||||
m_selected_filter_config_widget = m_selected_filter->get_settings_widget();
|
||||
m_config_widget->remove_all_children();
|
||||
m_config_widget->add_child(*m_selected_filter_config_widget);
|
||||
};
|
||||
|
||||
m_preview_widget->set_bitmap(editor->active_layer()->bitmap().clone().release_value());
|
||||
|
||||
apply_button->on_click = [this](auto) {
|
||||
if (!m_selected_filter) {
|
||||
done(ExecResult::ExecAborted);
|
||||
|
|
|
@ -13,11 +13,29 @@
|
|||
}
|
||||
|
||||
@GUI::Widget {
|
||||
name: "config_widget"
|
||||
layout: @GUI::VerticalBoxLayout {
|
||||
layout:@GUI::VerticalBoxLayout {
|
||||
margins: [4]
|
||||
}
|
||||
|
||||
@GUI::Widget {
|
||||
name: "config_widget"
|
||||
|
||||
layout:@GUI::VerticalBoxLayout {
|
||||
margins: [4]
|
||||
}
|
||||
}
|
||||
|
||||
@GUI::GroupBox {
|
||||
title: "Preview"
|
||||
layout: @GUI::VerticalBoxLayout {
|
||||
margins: [4]
|
||||
}
|
||||
|
||||
@PixelPaint::FilterPreviewWidget {
|
||||
name: "preview_widget"
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -29,6 +47,8 @@
|
|||
|
||||
@GUI::Widget
|
||||
|
||||
|
||||
|
||||
@GUI::Button {
|
||||
name: "apply_button"
|
||||
text: "Apply"
|
||||
|
|
|
@ -6,6 +6,7 @@
|
|||
|
||||
#pragma once
|
||||
|
||||
#include "FilterPreviewWidget.h"
|
||||
#include "Filters/Filter.h"
|
||||
#include "ImageEditor.h"
|
||||
#include <LibGUI/Dialog.h>
|
||||
|
@ -19,6 +20,7 @@ private:
|
|||
FilterGallery(GUI::Window* parent_window, ImageEditor*);
|
||||
GUI::TreeView* m_filter_tree { nullptr };
|
||||
GUI::Widget* m_config_widget { nullptr };
|
||||
FilterPreviewWidget* m_preview_widget { nullptr };
|
||||
RefPtr<GUI::Widget> m_selected_filter_config_widget { nullptr };
|
||||
Filter* m_selected_filter { nullptr };
|
||||
};
|
||||
|
|
67
Userland/Applications/PixelPaint/FilterPreviewWidget.cpp
Normal file
67
Userland/Applications/PixelPaint/FilterPreviewWidget.cpp
Normal file
|
@ -0,0 +1,67 @@
|
|||
/*
|
||||
* Copyright (c) 2022, the SerenityOS developers.
|
||||
*
|
||||
* SPDX-License-Identifier: BSD-2-Clause
|
||||
*/
|
||||
|
||||
#include "FilterPreviewWidget.h"
|
||||
#include <LibGUI/Painter.h>
|
||||
#include <LibGfx/Palette.h>
|
||||
#include <LibGfx/Rect.h>
|
||||
|
||||
REGISTER_WIDGET(PixelPaint, FilterPreviewWidget);
|
||||
|
||||
namespace PixelPaint {
|
||||
|
||||
FilterPreviewWidget::FilterPreviewWidget()
|
||||
{
|
||||
}
|
||||
|
||||
FilterPreviewWidget::~FilterPreviewWidget()
|
||||
{
|
||||
}
|
||||
|
||||
void FilterPreviewWidget::set_bitmap(const RefPtr<Gfx::Bitmap>& bitmap)
|
||||
{
|
||||
m_bitmap = bitmap;
|
||||
clear_filter();
|
||||
}
|
||||
|
||||
void FilterPreviewWidget::set_filter(Filter* filter)
|
||||
{
|
||||
if (filter)
|
||||
filter->apply(*m_filtered_bitmap, *m_bitmap);
|
||||
else
|
||||
m_filtered_bitmap = m_bitmap->clone().release_value();
|
||||
repaint();
|
||||
}
|
||||
|
||||
void FilterPreviewWidget::clear_filter()
|
||||
{
|
||||
set_filter(nullptr);
|
||||
}
|
||||
|
||||
void FilterPreviewWidget::paint_event(GUI::PaintEvent& event)
|
||||
{
|
||||
GUI::Painter painter(*this);
|
||||
painter.add_clip_rect(event.rect());
|
||||
auto preview_rect = event.rect();
|
||||
auto bitmap_rect = m_filtered_bitmap->rect();
|
||||
|
||||
int scaled_width, scaled_height, dx = 0, dy = 0;
|
||||
if (preview_rect.height() > preview_rect.width()) {
|
||||
scaled_width = preview_rect.width();
|
||||
scaled_height = ((float)bitmap_rect.height() / bitmap_rect.width()) * scaled_width;
|
||||
dy = (preview_rect.height() - scaled_height) / 2;
|
||||
} else {
|
||||
scaled_height = preview_rect.height();
|
||||
scaled_width = ((float)bitmap_rect.width() / bitmap_rect.height()) * scaled_height;
|
||||
dx = (preview_rect.width() - scaled_width) / 2;
|
||||
}
|
||||
|
||||
Gfx::IntRect scaled_rect(preview_rect.x() + dx, preview_rect.y() + dy, scaled_width, scaled_height);
|
||||
|
||||
painter.draw_scaled_bitmap(scaled_rect, *m_filtered_bitmap, m_filtered_bitmap->rect());
|
||||
}
|
||||
|
||||
}
|
35
Userland/Applications/PixelPaint/FilterPreviewWidget.h
Normal file
35
Userland/Applications/PixelPaint/FilterPreviewWidget.h
Normal file
|
@ -0,0 +1,35 @@
|
|||
/*
|
||||
* Copyright (c) 2022, the SerenityOS developers.
|
||||
*
|
||||
* SPDX-License-Identifier: BSD-2-Clause
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "Filters/Filter.h"
|
||||
#include "ImageEditor.h"
|
||||
#include "Layer.h"
|
||||
#include <LibGUI/Frame.h>
|
||||
#include <LibGfx/Bitmap.h>
|
||||
|
||||
namespace PixelPaint {
|
||||
|
||||
class FilterPreviewWidget final : public GUI::Frame {
|
||||
C_OBJECT(FilterPreviewWidget);
|
||||
|
||||
public:
|
||||
virtual ~FilterPreviewWidget() override;
|
||||
void set_bitmap(const RefPtr<Gfx::Bitmap>& bitmap);
|
||||
void set_filter(Filter* filter);
|
||||
void clear_filter();
|
||||
|
||||
private:
|
||||
explicit FilterPreviewWidget();
|
||||
|
||||
RefPtr<Gfx::Bitmap> m_bitmap;
|
||||
RefPtr<Gfx::Bitmap> m_filtered_bitmap;
|
||||
|
||||
virtual void paint_event(GUI::PaintEvent&) override;
|
||||
};
|
||||
|
||||
}
|
|
@ -59,6 +59,7 @@ RefPtr<GUI::Widget> Bloom::get_settings_widget()
|
|||
luma_lower_slider.set_value(m_luma_lower);
|
||||
luma_lower_slider.on_change = [&](int value) {
|
||||
m_luma_lower = value;
|
||||
update_preview();
|
||||
};
|
||||
|
||||
auto& radius_container = m_settings_widget->add<GUI::Widget>();
|
||||
|
@ -75,6 +76,7 @@ RefPtr<GUI::Widget> Bloom::get_settings_widget()
|
|||
radius_slider.set_value(m_blur_radius);
|
||||
radius_slider.on_change = [&](int value) {
|
||||
m_blur_radius = value;
|
||||
update_preview();
|
||||
};
|
||||
}
|
||||
|
||||
|
|
|
@ -54,6 +54,7 @@ RefPtr<GUI::Widget> FastBoxBlur::get_settings_widget()
|
|||
radius_slider.set_value(m_radius);
|
||||
radius_slider.on_change = [&](int value) {
|
||||
m_radius = value;
|
||||
update_preview();
|
||||
};
|
||||
|
||||
auto& gaussian_container = m_settings_widget->add<GUI::Widget>();
|
||||
|
@ -66,6 +67,7 @@ RefPtr<GUI::Widget> FastBoxBlur::get_settings_widget()
|
|||
gaussian_checkbox.set_tooltip("A real gaussian blur can be approximated by running the box blur multiple times with different weights.");
|
||||
gaussian_checkbox.on_checked = [this](bool checked) {
|
||||
m_approximate_gauss = checked;
|
||||
update_preview();
|
||||
};
|
||||
}
|
||||
|
||||
|
|
|
@ -37,4 +37,10 @@ void Filter::apply() const
|
|||
}
|
||||
}
|
||||
|
||||
void Filter::update_preview()
|
||||
{
|
||||
if (on_settings_change)
|
||||
on_settings_change();
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -27,9 +27,12 @@ public:
|
|||
Filter(ImageEditor* editor)
|
||||
: m_editor(editor) {};
|
||||
|
||||
Function<void(void)> on_settings_change;
|
||||
|
||||
protected:
|
||||
ImageEditor* m_editor { nullptr };
|
||||
RefPtr<GUI::Widget> m_settings_widget { nullptr };
|
||||
void update_preview();
|
||||
};
|
||||
|
||||
}
|
||||
|
|
|
@ -42,6 +42,7 @@ RefPtr<GUI::Widget> Sepia::get_settings_widget()
|
|||
amount_slider.set_value(m_amount * 100);
|
||||
amount_slider.on_change = [&](int value) {
|
||||
m_amount = value * 0.01f;
|
||||
update_preview();
|
||||
};
|
||||
}
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue