PixelPaint: Rebuild FilterGallery tree using TreeViewModel

This commit is contained in:
Linus Groh 2022-05-12 21:37:43 +02:00
parent 5bb38296b1
commit ffc5fed79f
7 changed files with 105 additions and 208 deletions

View file

@ -16,7 +16,7 @@ set(SOURCES
EditGuideDialogGML.h
FilterGallery.cpp
FilterGalleryGML.h
FilterModel.cpp
FilterTreeModel.cpp
FilterPreviewWidget.cpp
Filters/Bloom.cpp
Filters/BoxBlur3.cpp

View file

@ -5,7 +5,7 @@
*/
#include "FilterGallery.h"
#include "FilterModel.h"
#include "FilterTreeModel.h"
#include <Applications/PixelPaint/FilterGalleryGML.h>
#include <LibGUI/Button.h>
#include <LibGUI/TreeView.h>
@ -37,8 +37,8 @@ FilterGallery::FilterGallery(GUI::Window* parent_window, ImageEditor* editor)
VERIFY(m_config_widget);
VERIFY(m_preview_widget);
auto filter_model = FilterModel::create(editor);
m_filter_tree->set_model(filter_model);
auto filter_tree_model = MUST(create_filter_tree_model(editor));
m_filter_tree->set_model(filter_tree_model);
m_filter_tree->expand_tree();
m_filter_tree->on_selection_change = [this]() {
@ -48,13 +48,13 @@ FilterGallery::FilterGallery(GUI::Window* parent_window, ImageEditor* editor)
return;
}
auto selected_filter = static_cast<const FilterModel::FilterInfo*>(selected_index.internal_data());
if (selected_filter->type != FilterModel::FilterInfo::Type::Filter) {
auto& node = *static_cast<GUI::TreeViewModel::Node*>(selected_index.internal_data());
if (!is<FilterNode>(node)) {
m_preview_widget->clear_filter();
return;
}
m_selected_filter = selected_filter->filter;
m_selected_filter = &static_cast<FilterNode&>(node).filter();
m_selected_filter->on_settings_change = [&]() {
m_preview_widget->set_filter(m_selected_filter);
};

View file

@ -1,120 +0,0 @@
/*
* Copyright (c) 2021-2022, Tobias Christiansen <tobyase@serenityos.org>
* Copyright (c) 2021, Mustafa Quraish <mustafa@serenityos.org>
*
* SPDX-License-Identifier: BSD-2-Clause
*/
#include "FilterModel.h"
#include "FilterParams.h"
#include "Filters/Bloom.h"
#include "Filters/BoxBlur3.h"
#include "Filters/BoxBlur5.h"
#include "Filters/FastBoxBlur.h"
#include "Filters/GaussBlur3.h"
#include "Filters/GaussBlur5.h"
#include "Filters/Grayscale.h"
#include "Filters/Invert.h"
#include "Filters/LaplaceCardinal.h"
#include "Filters/LaplaceDiagonal.h"
#include "Filters/Sepia.h"
#include "Filters/Sharpen.h"
#include "Layer.h"
#include <LibGUI/FileIconProvider.h>
namespace PixelPaint {
FilterModel::FilterModel(ImageEditor* editor)
{
auto artistic_category = FilterInfo::create_category("Artistic");
auto bloom_filter = FilterInfo::create_filter<Filters::Bloom>(editor, artistic_category);
m_filters.append(artistic_category);
auto spatial_category = FilterInfo::create_category("Spatial");
auto edge_detect_category = FilterInfo::create_category("Edge Detection", spatial_category);
auto laplace_cardinal_filter = FilterInfo::create_filter<Filters::LaplaceCardinal>(editor, edge_detect_category);
auto laplace_diagonal_filter = FilterInfo::create_filter<Filters::LaplaceDiagonal>(editor, edge_detect_category);
auto blur_category = FilterInfo::create_category("Blur & Sharpen", spatial_category);
auto fast_box_filter = FilterInfo::create_filter<Filters::FastBoxBlur>(editor, blur_category);
auto gaussian_blur_filter_3 = FilterInfo::create_filter<Filters::GaussBlur3>(editor, blur_category);
auto gaussian_blur_filter_5 = FilterInfo::create_filter<Filters::GaussBlur5>(editor, blur_category);
auto box_blur_filter_3 = FilterInfo::create_filter<Filters::BoxBlur3>(editor, blur_category);
auto box_blur_filter_5 = FilterInfo::create_filter<Filters::BoxBlur5>(editor, blur_category);
auto sharpen_filter = FilterInfo::create_filter<Filters::Sharpen>(editor, blur_category);
m_filters.append(spatial_category);
auto color_category = FilterInfo::create_category("Color");
auto grayscale_filter = FilterInfo::create_filter<Filters::Grayscale>(editor, color_category);
auto invert_filter = FilterInfo::create_filter<Filters::Invert>(editor, color_category);
auto sepia_filter = FilterInfo::create_filter<Filters::Sepia>(editor, color_category);
m_filters.append(color_category);
auto filter_bitmap = Gfx::Bitmap::try_load_from_file("/res/icons/pixelpaint/filter.png").release_value_but_fixme_should_propagate_errors();
m_filter_icon = GUI::Icon(filter_bitmap);
}
GUI::ModelIndex FilterModel::index(int row, int column, const GUI::ModelIndex& parent_index) const
{
if (!parent_index.is_valid()) {
if (static_cast<size_t>(row) >= m_filters.size())
return {};
return create_index(row, column, &m_filters[row]);
}
auto* parent = static_cast<FilterInfo const*>(parent_index.internal_data());
if (static_cast<size_t>(row) >= parent->children.size())
return {};
auto* child = &parent->children[row];
return create_index(row, column, child);
}
GUI::ModelIndex FilterModel::parent_index(const GUI::ModelIndex& index) const
{
if (!index.is_valid())
return {};
auto* child = static_cast<FilterInfo const*>(index.internal_data());
auto* parent = child->parent;
if (parent == nullptr)
return {};
if (parent->parent == nullptr) {
for (size_t row = 0; row < m_filters.size(); row++)
if (m_filters.ptr_at(row).ptr() == parent)
return create_index(row, 0, parent);
VERIFY_NOT_REACHED();
}
for (size_t row = 0; row < parent->parent->children.size(); row++) {
FilterInfo* child_at_row = parent->parent->children.ptr_at(row).ptr();
if (child_at_row == parent)
return create_index(row, 0, parent);
}
VERIFY_NOT_REACHED();
}
int FilterModel::row_count(const GUI::ModelIndex& index) const
{
if (!index.is_valid())
return m_filters.size();
auto* node = static_cast<FilterInfo const*>(index.internal_data());
return node->children.size();
}
GUI::Variant FilterModel::data(const GUI::ModelIndex& index, GUI::ModelRole role) const
{
auto* filter = static_cast<FilterInfo const*>(index.internal_data());
switch (role) {
case GUI::ModelRole::Display:
return filter->text;
case GUI::ModelRole::Icon:
if (filter->type == FilterInfo::Type::Category)
return GUI::FileIconProvider::directory_icon();
return m_filter_icon;
default:
return {};
}
}
}

View file

@ -1,81 +0,0 @@
/*
* Copyright (c) 2021, Tobias Christiansen <tobyase@serenityos.org>
*
* SPDX-License-Identifier: BSD-2-Clause
*/
#pragma once
#include "Filters/Filter.h"
#include "ImageEditor.h"
#include <AK/NonnullRefPtr.h>
#include <LibGUI/Model.h>
namespace PixelPaint {
class FilterModel final : public GUI::Model {
public:
class FilterInfo : public RefCounted<FilterInfo> {
public:
enum class Type {
Category,
Filter,
} type;
String text;
Filter* filter { nullptr };
NonnullRefPtrVector<FilterInfo> children;
FilterInfo* parent;
template<typename FilterType>
static NonnullRefPtr<FilterInfo> create_filter(ImageEditor* editor, FilterInfo* parent = nullptr)
{
auto filter = static_cast<Filter*>(new FilterType(editor));
auto filter_info = adopt_ref(*new FilterInfo(Type::Filter, filter->filter_name(), parent));
filter_info->filter = filter;
filter_info->ref();
if (parent)
parent->children.append(filter_info);
return filter_info;
}
static NonnullRefPtr<FilterInfo> create_category(String const& text, FilterInfo* parent = nullptr)
{
auto category = adopt_ref(*new FilterInfo(Type::Category, text, parent));
category->ref();
if (parent)
parent->children.append(category);
return category;
}
FilterInfo(Type type, String text, FilterInfo* parent)
: type(type)
, text(move(text))
, parent(parent)
{
}
};
static NonnullRefPtr<FilterModel> create(ImageEditor* editor)
{
return adopt_ref(*new FilterModel(editor));
}
virtual ~FilterModel() override {};
virtual int row_count(const GUI::ModelIndex& = GUI::ModelIndex()) const override;
virtual int column_count(const GUI::ModelIndex& = GUI::ModelIndex()) const override { return 1; }
virtual GUI::Variant data(const GUI::ModelIndex& index, GUI::ModelRole role) const override;
virtual GUI::ModelIndex parent_index(const GUI::ModelIndex&) const override;
virtual GUI::ModelIndex index(int row, int column = 0, const GUI::ModelIndex& = GUI::ModelIndex()) const override;
private:
FilterModel(ImageEditor* editor);
NonnullRefPtrVector<FilterInfo> m_filters;
GUI::Icon m_filter_icon;
};
}

View file

@ -0,0 +1,63 @@
/*
* Copyright (c) 2021-2022, Tobias Christiansen <tobyase@serenityos.org>
* Copyright (c) 2021, Mustafa Quraish <mustafa@serenityos.org>
* Copyright (c) 2022, Linus Groh <linusg@serenityos.org>
*
* SPDX-License-Identifier: BSD-2-Clause
*/
#include "FilterTreeModel.h"
#include "Filters/Bloom.h"
#include "Filters/BoxBlur3.h"
#include "Filters/BoxBlur5.h"
#include "Filters/FastBoxBlur.h"
#include "Filters/GaussBlur3.h"
#include "Filters/GaussBlur5.h"
#include "Filters/Grayscale.h"
#include "Filters/Invert.h"
#include "Filters/LaplaceCardinal.h"
#include "Filters/LaplaceDiagonal.h"
#include "Filters/Sepia.h"
#include "Filters/Sharpen.h"
#include <LibGUI/FileIconProvider.h>
namespace PixelPaint {
ErrorOr<NonnullRefPtr<GUI::TreeViewModel>> create_filter_tree_model(ImageEditor* editor)
{
auto directory_icon = GUI::FileIconProvider::directory_icon();
auto filter_icon = GUI::Icon(TRY(Gfx::Bitmap::try_load_from_file("/res/icons/pixelpaint/filter.png")));
auto filter_tree_model = GUI::TreeViewModel::create();
auto add_filter_node = [&]<typename FilterType>(GUI::TreeViewModel::Node& node) {
auto filter = adopt_own(*new FilterType(editor));
(void)node.add_node<FilterNode>(filter->filter_name(), filter_icon, move(filter));
};
auto artistic_category = filter_tree_model->add_node("Artistic", directory_icon);
add_filter_node.template operator()<Filters::Bloom>(artistic_category);
auto spatial_category = filter_tree_model->add_node("Spatial", directory_icon);
auto edge_detect_category = spatial_category->add_node("Edge Detection", directory_icon);
add_filter_node.template operator()<Filters::LaplaceCardinal>(edge_detect_category);
add_filter_node.template operator()<Filters::LaplaceDiagonal>(edge_detect_category);
auto blur_category = spatial_category->add_node("Blur & Sharpen", directory_icon);
add_filter_node.template operator()<Filters::FastBoxBlur>(blur_category);
add_filter_node.template operator()<Filters::GaussBlur3>(blur_category);
add_filter_node.template operator()<Filters::GaussBlur5>(blur_category);
add_filter_node.template operator()<Filters::BoxBlur3>(blur_category);
add_filter_node.template operator()<Filters::BoxBlur5>(blur_category);
add_filter_node.template operator()<Filters::Sharpen>(blur_category);
auto color_category = filter_tree_model->add_node("Color", directory_icon);
add_filter_node.template operator()<Filters::Grayscale>(color_category);
add_filter_node.template operator()<Filters::Invert>(color_category);
add_filter_node.template operator()<Filters::Sepia>(color_category);
return filter_tree_model;
}
}

View file

@ -0,0 +1,34 @@
/*
* Copyright (c) 2021, Tobias Christiansen <tobyase@serenityos.org>
* Copyright (c) 2022, Linus Groh <linusg@serenityos.org>
*
* SPDX-License-Identifier: BSD-2-Clause
*/
#pragma once
#include "Filters/Filter.h"
#include "ImageEditor.h"
#include <AK/NonnullOwnPtr.h>
#include <LibGUI/TreeViewModel.h>
namespace PixelPaint {
class FilterNode final : public GUI::TreeViewModel::Node {
public:
FilterNode(String text, Optional<GUI::Icon> icon, Node* parent_node, NonnullOwnPtr<Filter> filter)
: Node(move(text), move(icon), parent_node)
, m_filter(move(filter))
{
}
Filter const& filter() const { return *m_filter; }
Filter& filter() { return *m_filter; }
private:
NonnullOwnPtr<Filter> m_filter;
};
ErrorOr<NonnullRefPtr<GUI::TreeViewModel>> create_filter_tree_model(ImageEditor*);
}

View file

@ -7,6 +7,7 @@
#pragma once
#include "Filter.h"
#include <LibGUI/CheckBox.h>
#include <LibGUI/ValueSlider.h>
namespace PixelPaint::Filters {