1
Fork 0
mirror of https://github.com/RGBCube/serenity synced 2025-07-27 06:47:35 +00:00

PixelPaint: Add Filter Gallery Dialog to the Filter Menu

This patch adds the bare bones of the new Filter Gallery.
For now, only the gml and the basic layout got added, a fairly boringw
indow pops up when "Filter Gallery" is called.

The code for the Model used by the TreeView is taken in large parts from
HackStudio's VariableModel.
This commit is contained in:
Tobias Christiansen 2021-12-31 22:17:24 +01:00 committed by Andreas Kling
parent b46ea5158d
commit f47026b1d6
7 changed files with 277 additions and 0 deletions

View file

@ -7,12 +7,16 @@ serenity_component(
compile_gml(PixelPaintWindow.gml PixelPaintWindowGML.h pixel_paint_window_gml)
compile_gml(EditGuideDialog.gml EditGuideDialogGML.h edit_guide_dialog_gml)
compile_gml(FilterGallery.gml FilterGalleryGML.h filter_gallery_gml)
set(SOURCES
CreateNewImageDialog.cpp
CreateNewLayerDialog.cpp
EditGuideDialog.cpp
EditGuideDialogGML.h
FilterGallery.cpp
FilterGalleryGML.h
FilterModel.cpp
Image.cpp
ImageEditor.cpp
Layer.cpp

View file

@ -0,0 +1,51 @@
/*
* Copyright (c) 2021, Tobias Christiansen <tobyase@serenityos.org>
*
* SPDX-License-Identifier: BSD-2-Clause
*/
#include "FilterGallery.h"
#include "FilterModel.h"
#include <Applications/PixelPaint/FilterGalleryGML.h>
#include <LibGUI/Button.h>
#include <LibGUI/TreeView.h>
#include <LibGUI/Widget.h>
namespace PixelPaint {
FilterGallery::FilterGallery(GUI::Window* parent_window)
: GUI::Dialog(parent_window)
{
set_title("Filter Gallery");
set_icon(parent_window->icon());
resize(200, 250);
set_resizable(true);
auto& main_widget = set_main_widget<GUI::Widget>();
if (!main_widget.load_from_gml(filter_gallery_gml))
VERIFY_NOT_REACHED();
auto filter_tree = main_widget.find_descendant_of_type_named<GUI::TreeView>("tree_view");
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");
VERIFY(filter_tree);
VERIFY(apply_button);
VERIFY(cancel_button);
auto filter_model = FilterModel::create();
filter_tree->set_model(filter_model);
filter_tree->expand_tree();
apply_button->on_click = [this](auto) {
dbgln("Click!");
done(ExecResult::ExecOK);
};
cancel_button->on_click = [this](auto) {
done(ExecResult::ExecCancel);
};
}
}

View file

@ -0,0 +1,40 @@
@GUI::Frame {
layout: @GUI::VerticalBoxLayout {
}
fill_with_background_color: true
@GUI::Widget {
layout:@GUI::HorizontalBoxLayout {
margins: [4]
}
@GUI::TreeView {
name: "tree_view"
}
}
@GUI::Widget {
max_height: 24
layout:@GUI::HorizontalBoxLayout {
margins: [4]
}
@GUI::Widget {}
@GUI::Button {
name: "apply_button"
text: "Apply"
max_width: 75
}
@GUI::Button {
name: "cancel_button"
text: "Cancel"
max_width: 75
}
}
}

View file

@ -0,0 +1,20 @@
/*
* Copyright (c) 2021, Tobias Christiansen <tobyase@serenityos.org>
*
* SPDX-License-Identifier: BSD-2-Clause
*/
#pragma once
#include <LibGUI/Dialog.h>
namespace PixelPaint {
class FilterGallery final : public GUI::Dialog {
C_OBJECT(FilterGallery);
private:
FilterGallery(GUI::Window* parent_window);
};
}

View file

@ -0,0 +1,79 @@
/*
* 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 <LibGUI/FileIconProvider.h>
namespace PixelPaint {
FilterModel::FilterModel()
{
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<const FilterInfo*>(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<const FilterInfo*>(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<const FilterInfo*>(index.internal_data());
return node->children.size();
}
GUI::Variant FilterModel::data(const GUI::ModelIndex& index, GUI::ModelRole role) const
{
auto* filter = static_cast<const FilterInfo*>(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

@ -0,0 +1,75 @@
/*
* Copyright (c) 2021, Tobias Christiansen <tobyase@serenityos.org>
*
* SPDX-License-Identifier: BSD-2-Clause
*/
#pragma once
#include <AK/NonnullRefPtr.h>
#include <LibGUI/Model.h>
namespace PixelPaint {
class FilterModel final : public GUI::Model {
public:
class FilterInfo : public RefCounted {
public:
enum class Type {
Category,
Filter,
} type;
String text;
NonnullRefPtrVector<FilterInfo> children;
FilterInfo* parent;
static NonnullRefPtr<FilterInfo> create_filter(String const& text, FilterInfo* parent = nullptr)
{
auto filter = adopt_ref(*new FilterInfo(Type::Filter, text, parent));
filter->ref();
if (parent)
parent->children.append(filter);
return filter;
}
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()
{
return adopt_ref(*new FilterModel());
}
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();
NonnullRefPtrVector<FilterInfo> m_filters;
GUI::Icon m_filter_icon;
};
}

View file

@ -10,6 +10,7 @@
#include "CreateNewImageDialog.h"
#include "CreateNewLayerDialog.h"
#include "EditGuideDialog.h"
#include "FilterGallery.h"
#include "FilterParams.h"
#include <Applications/PixelPaint/PixelPaintWindowGML.h>
#include <LibConfig/Client.h>
@ -587,6 +588,13 @@ void MainWidget::initialize_menubar(GUI::Window& window)
}));
auto& filter_menu = window.add_menu("&Filter");
filter_menu.add_action(GUI::Action::create("Filter &Gallery", [&](auto&) {
auto dialog = PixelPaint::FilterGallery::construct(&window);
if (dialog->exec() != GUI::Dialog::ExecOK)
return;
}));
auto& spatial_filters_menu = filter_menu.add_submenu("&Spatial");
auto& edge_detect_submenu = spatial_filters_menu.add_submenu("&Edge Detect");