From e9d3f3793c26c343001ab5eb87dc92dec46d6a9e Mon Sep 17 00:00:00 2001 From: snooze Date: Wed, 9 Feb 2022 11:00:36 +0530 Subject: [PATCH] PixelPaint: Add a preview in FilterGallery Now FilterGallery shows the preview of the currently selected filter applied on the currently active layer --- .../Applications/PixelPaint/CMakeLists.txt | 1 + .../Applications/PixelPaint/FilterGallery.cpp | 16 ++++- .../Applications/PixelPaint/FilterGallery.gml | 24 ++++++- .../Applications/PixelPaint/FilterGallery.h | 2 + .../PixelPaint/FilterPreviewWidget.cpp | 67 +++++++++++++++++++ .../PixelPaint/FilterPreviewWidget.h | 35 ++++++++++ .../Applications/PixelPaint/Filters/Bloom.cpp | 2 + .../PixelPaint/Filters/FastBoxBlur.cpp | 2 + .../PixelPaint/Filters/Filter.cpp | 6 ++ .../Applications/PixelPaint/Filters/Filter.h | 3 + .../Applications/PixelPaint/Filters/Sepia.cpp | 1 + 11 files changed, 155 insertions(+), 4 deletions(-) create mode 100644 Userland/Applications/PixelPaint/FilterPreviewWidget.cpp create mode 100644 Userland/Applications/PixelPaint/FilterPreviewWidget.h diff --git a/Userland/Applications/PixelPaint/CMakeLists.txt b/Userland/Applications/PixelPaint/CMakeLists.txt index d3ca024630..65aeef7394 100644 --- a/Userland/Applications/PixelPaint/CMakeLists.txt +++ b/Userland/Applications/PixelPaint/CMakeLists.txt @@ -17,6 +17,7 @@ set(SOURCES FilterGallery.cpp FilterGalleryGML.h FilterModel.cpp + FilterPreviewWidget.cpp Filters/Bloom.cpp Filters/BoxBlur3.cpp Filters/BoxBlur5.cpp diff --git a/Userland/Applications/PixelPaint/FilterGallery.cpp b/Userland/Applications/PixelPaint/FilterGallery.cpp index 325e40b940..48844ffa9d 100644 --- a/Userland/Applications/PixelPaint/FilterGallery.cpp +++ b/Userland/Applications/PixelPaint/FilterGallery.cpp @@ -29,11 +29,13 @@ FilterGallery::FilterGallery(GUI::Window* parent_window, ImageEditor* editor) auto apply_button = main_widget.find_descendant_of_type_named("apply_button"); auto cancel_button = main_widget.find_descendant_of_type_named("cancel_button"); m_config_widget = main_widget.find_descendant_of_type_named("config_widget"); + m_preview_widget = main_widget.find_descendant_of_type_named("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(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); diff --git a/Userland/Applications/PixelPaint/FilterGallery.gml b/Userland/Applications/PixelPaint/FilterGallery.gml index 833b95aa31..082e9012d8 100644 --- a/Userland/Applications/PixelPaint/FilterGallery.gml +++ b/Userland/Applications/PixelPaint/FilterGallery.gml @@ -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" diff --git a/Userland/Applications/PixelPaint/FilterGallery.h b/Userland/Applications/PixelPaint/FilterGallery.h index 39ddcea584..fcf67ee761 100644 --- a/Userland/Applications/PixelPaint/FilterGallery.h +++ b/Userland/Applications/PixelPaint/FilterGallery.h @@ -6,6 +6,7 @@ #pragma once +#include "FilterPreviewWidget.h" #include "Filters/Filter.h" #include "ImageEditor.h" #include @@ -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 m_selected_filter_config_widget { nullptr }; Filter* m_selected_filter { nullptr }; }; diff --git a/Userland/Applications/PixelPaint/FilterPreviewWidget.cpp b/Userland/Applications/PixelPaint/FilterPreviewWidget.cpp new file mode 100644 index 0000000000..f86fe42769 --- /dev/null +++ b/Userland/Applications/PixelPaint/FilterPreviewWidget.cpp @@ -0,0 +1,67 @@ +/* + * Copyright (c) 2022, the SerenityOS developers. + * + * SPDX-License-Identifier: BSD-2-Clause + */ + +#include "FilterPreviewWidget.h" +#include +#include +#include + +REGISTER_WIDGET(PixelPaint, FilterPreviewWidget); + +namespace PixelPaint { + +FilterPreviewWidget::FilterPreviewWidget() +{ +} + +FilterPreviewWidget::~FilterPreviewWidget() +{ +} + +void FilterPreviewWidget::set_bitmap(const RefPtr& 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()); +} + +} diff --git a/Userland/Applications/PixelPaint/FilterPreviewWidget.h b/Userland/Applications/PixelPaint/FilterPreviewWidget.h new file mode 100644 index 0000000000..451ff90569 --- /dev/null +++ b/Userland/Applications/PixelPaint/FilterPreviewWidget.h @@ -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 +#include + +namespace PixelPaint { + +class FilterPreviewWidget final : public GUI::Frame { + C_OBJECT(FilterPreviewWidget); + +public: + virtual ~FilterPreviewWidget() override; + void set_bitmap(const RefPtr& bitmap); + void set_filter(Filter* filter); + void clear_filter(); + +private: + explicit FilterPreviewWidget(); + + RefPtr m_bitmap; + RefPtr m_filtered_bitmap; + + virtual void paint_event(GUI::PaintEvent&) override; +}; + +} diff --git a/Userland/Applications/PixelPaint/Filters/Bloom.cpp b/Userland/Applications/PixelPaint/Filters/Bloom.cpp index 3c1ec93674..614388a606 100644 --- a/Userland/Applications/PixelPaint/Filters/Bloom.cpp +++ b/Userland/Applications/PixelPaint/Filters/Bloom.cpp @@ -59,6 +59,7 @@ RefPtr 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(); @@ -75,6 +76,7 @@ RefPtr Bloom::get_settings_widget() radius_slider.set_value(m_blur_radius); radius_slider.on_change = [&](int value) { m_blur_radius = value; + update_preview(); }; } diff --git a/Userland/Applications/PixelPaint/Filters/FastBoxBlur.cpp b/Userland/Applications/PixelPaint/Filters/FastBoxBlur.cpp index 9375b487fa..4b9f62ccc7 100644 --- a/Userland/Applications/PixelPaint/Filters/FastBoxBlur.cpp +++ b/Userland/Applications/PixelPaint/Filters/FastBoxBlur.cpp @@ -54,6 +54,7 @@ RefPtr 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(); @@ -66,6 +67,7 @@ RefPtr 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(); }; } diff --git a/Userland/Applications/PixelPaint/Filters/Filter.cpp b/Userland/Applications/PixelPaint/Filters/Filter.cpp index a7dcfa5058..27f0f2d65d 100644 --- a/Userland/Applications/PixelPaint/Filters/Filter.cpp +++ b/Userland/Applications/PixelPaint/Filters/Filter.cpp @@ -37,4 +37,10 @@ void Filter::apply() const } } +void Filter::update_preview() +{ + if (on_settings_change) + on_settings_change(); +} + } diff --git a/Userland/Applications/PixelPaint/Filters/Filter.h b/Userland/Applications/PixelPaint/Filters/Filter.h index 7752c931ad..3d201a0282 100644 --- a/Userland/Applications/PixelPaint/Filters/Filter.h +++ b/Userland/Applications/PixelPaint/Filters/Filter.h @@ -27,9 +27,12 @@ public: Filter(ImageEditor* editor) : m_editor(editor) {}; + Function on_settings_change; + protected: ImageEditor* m_editor { nullptr }; RefPtr m_settings_widget { nullptr }; + void update_preview(); }; } diff --git a/Userland/Applications/PixelPaint/Filters/Sepia.cpp b/Userland/Applications/PixelPaint/Filters/Sepia.cpp index 4a3b87099b..e3e0851502 100644 --- a/Userland/Applications/PixelPaint/Filters/Sepia.cpp +++ b/Userland/Applications/PixelPaint/Filters/Sepia.cpp @@ -42,6 +42,7 @@ RefPtr Sepia::get_settings_widget() amount_slider.set_value(m_amount * 100); amount_slider.on_change = [&](int value) { m_amount = value * 0.01f; + update_preview(); }; }