Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Issue #1207 - Bucket features #1630

Merged
merged 35 commits into from
Jul 13, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
35 commits
Select commit Hold shift + click to select a range
10580d0
Implement expand algorithm
MrStevns Apr 17, 2021
23d5240
#1207 - Implement Fill expand UI interaction
MrStevns Apr 17, 2021
aab0d65
Move vector stroke thickness to BucketOptionsWidget
MrStevns Apr 17, 2021
15bf27a
Implement controls to fill to a layer and use layer below as reference
MrStevns Apr 18, 2021
0db1fe5
Add tooltips
MrStevns Apr 18, 2021
bcf366b
Adjust stretching
MrStevns Apr 18, 2021
8bbc010
Add documentation
MrStevns Apr 18, 2021
76db88a
Remove unused function
MrStevns Apr 18, 2021
77a18d2
Move destructor method below constructor
MrStevns Apr 18, 2021
9de9f8a
Fix BucketOptionsWidget cpp/h/ui placement
MrStevns Apr 20, 2021
5371677
Merge branch 'master' into iss-1207-bucket-features
MrStevns Apr 20, 2021
df5c710
Fix keyframe not added when filling using "layer below"
MrStevns Apr 20, 2021
8f0d841
Fix backup and undo relying on layer index to undo..
MrStevns Apr 21, 2021
32d5ea8
Merge branch 'master' into iss-1207-bucket-features
MrStevns Apr 24, 2021
90ebbe1
Fix features doesn't take layer visibility into account
MrStevns Apr 24, 2021
b6ff150
Fix filling with transparency not working
MrStevns Apr 24, 2021
ec94ef3
Refactor and simplify
MrStevns Apr 24, 2021
56110b5
Fix typo in documentation
MrStevns Apr 24, 2021
ffca137
Change transparency to blend mode
MrStevns Apr 25, 2021
8893310
Fix targetLayerIndex not being properly set with layer below
MrStevns Apr 25, 2021
6127949
Don't show floodfill options on camera layer
MrStevns Apr 25, 2021
21cfe61
Implement drag to fill ability
MrStevns Apr 25, 2021
a67f26d
Rework bucket logic and move into BitmapBucket class
MrStevns Apr 25, 2021
4aef4ad
Fix various dragging cases where the wrong pixel would be filled
MrStevns Apr 27, 2021
8321332
Implement BitmapBucket tests
MrStevns Apr 27, 2021
7bc955c
Remove redundant code based on test results
MrStevns Apr 27, 2021
42c3cd4
Fix crash on deinit because of strong reference to pointer
MrStevns Apr 28, 2021
f4f1987
Simplify and fix cases where filling would occur more than once
MrStevns Apr 29, 2021
fd1a18a
Fix test not working as expected
MrStevns Apr 30, 2021
f69be8f
Fix github actions failing
MrStevns Apr 30, 2021
e51a2a3
Fix cache update issue when painting on layer below
MrStevns May 1, 2021
9d3eb4d
Remove redundant code
MrStevns May 3, 2021
16f35c0
Check before creating keyframe on layer below
MrStevns May 3, 2021
e5e6705
Fix cache issue when drawing on layer below
MrStevns May 3, 2021
93db5e5
Remove old comment
MrStevns May 3, 2021
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions app/app.pro
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,7 @@ HEADERS += \
src/aboutdialog.h \
src/toolbox.h \
src/tooloptionwidget.h \
src/bucketoptionswidget.h \
src/importexportdialog.h \
src/exportimagedialog.h \
src/importimageseqdialog.h \
Expand Down Expand Up @@ -112,6 +113,7 @@ SOURCES += \
src/aboutdialog.cpp \
src/toolbox.cpp \
src/tooloptionwidget.cpp \
src/bucketoptionswidget.cpp \
src/importexportdialog.cpp \
src/exportimagedialog.cpp \
src/importimageseqdialog.cpp \
Expand Down Expand Up @@ -143,6 +145,7 @@ FORMS += \
ui/exportimageoptions.ui \
ui/importimageseqoptions.ui \
ui/tooloptions.ui \
ui/bucketoptionswidget.ui \
ui/aboutdialog.ui \
ui/doubleprogressdialog.ui \
ui/preferencesdialog.ui \
Expand Down
248 changes: 248 additions & 0 deletions app/src/bucketoptionswidget.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,248 @@
/*

Pencil2D - Traditional Animation Software
Copyright (C) 2005-2007 Patrick Corrieri & Pascal Naidon
Copyright (C) 2012-2020 Matthew Chiawen Chang

This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; version 2 of the License.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.

*/
#include "bucketoptionswidget.h"
#include "ui_bucketoptionswidget.h"

#include <QDebug>

#include "spinslider.h"
#include "pencilsettings.h"

#include "layer.h"
#include "editor.h"
#include "layermanager.h"
#include "toolmanager.h"
#include "util.h"

BucketOptionsWidget::BucketOptionsWidget(Editor* editor, QWidget *parent) :
QWidget(parent),
ui(new Ui::BucketOptionsWidget),
mEditor(editor)
{
ui->setupUi(this);

ui->colorToleranceSlider->init(tr("Color tolerance"), SpinSlider::GROWTH_TYPE::LINEAR, SpinSlider::VALUE_TYPE::INTEGER, 0, MAX_COLOR_TOLERANCE);
ui->expandSlider->init(tr("Expand fill"), SpinSlider::GROWTH_TYPE::LINEAR, SpinSlider::VALUE_TYPE::INTEGER, 0, MAX_EXPAND);
ui->strokeThicknessSlider->init(tr("Stroke thickness"), SpinSlider::GROWTH_TYPE::LOG, SpinSlider::VALUE_TYPE::FLOAT, 1, MAX_STROKE_THICKNESS);

QSettings settings(PENCIL2D, PENCIL2D);

ui->colorToleranceCheckbox->setChecked(settings.value(SETTING_BUCKET_TOLERANCE_ON, true).toBool());
ui->expandCheckbox->setChecked(settings.value(SETTING_BUCKET_FILL_EXPAND_ON, true).toBool());

ui->expandSpinBox->setMaximum(MAX_EXPAND);
ui->strokeThicknessSpinBox->setMaximum(MAX_STROKE_THICKNESS);
ui->colorToleranceSpinbox->setMaximum(MAX_COLOR_TOLERANCE);
ui->strokeThicknessSpinBox->setMinimum(1);

ui->fillToLayerComboBox->addItem(tr("Current layer"), 0);
ui->fillToLayerComboBox->addItem(tr("Layer below"), 1);
ui->fillToLayerComboBox->setToolTip(tr("Fill to the current layer or the layer below"));

ui->referenceLayerComboBox->addItem(tr("Current layer"), 0);
ui->referenceLayerComboBox->addItem(tr("All layers"), 1);
ui->referenceLayerComboBox->setToolTip(tr("Refers to the layer that used to flood fill from"));

ui->blendModeComboBox->addItem(tr("Overlay"), 0);
ui->blendModeComboBox->addItem(tr("Replace"), 1);
ui->blendModeComboBox->addItem(tr("Behind"), 2);
ui->blendModeComboBox->setToolTip(tr("Defines how the fill will behave when the new color is not opaque"));

connect(ui->colorToleranceSlider, &SpinSlider::valueChanged, mEditor->tools(), &ToolManager::setTolerance);
connect(ui->colorToleranceSpinbox, static_cast<void (QSpinBox::*)(int)>(&QSpinBox::valueChanged), mEditor->tools(), &ToolManager::setTolerance);
connect(ui->colorToleranceCheckbox, &QCheckBox::toggled, mEditor->tools(), &ToolManager::setBucketColorToleranceEnabled);

connect(ui->expandSlider, &SpinSlider::valueChanged, mEditor->tools(), &ToolManager::setBucketFillExpand);
connect(ui->expandSpinBox, static_cast<void (QSpinBox::*)(int)>(&QSpinBox::valueChanged), mEditor->tools(), &ToolManager::setBucketFillExpand);
connect(ui->expandCheckbox, &QCheckBox::toggled, mEditor->tools(), &ToolManager::setBucketFillExpandEnabled);

connect(ui->strokeThicknessSlider, &SpinSlider::valueChanged, mEditor->tools(), &ToolManager::setWidth);
connect(ui->strokeThicknessSpinBox, static_cast<void (QDoubleSpinBox::*)(qreal)>(&QDoubleSpinBox::valueChanged), mEditor->tools(), &ToolManager::setWidth);

connect(mEditor->tools(), &ToolManager::toolPropertyChanged, this, &BucketOptionsWidget::onPropertyChanged);
connect(mEditor->layers(), &LayerManager::currentLayerChanged, this, &BucketOptionsWidget::onLayerChanged);

connect(ui->fillToLayerComboBox, static_cast<void (QComboBox::*)(int)>(&QComboBox::currentIndexChanged), mEditor->tools(), &ToolManager::setBucketFillToLayer);
connect(ui->referenceLayerComboBox, static_cast<void (QComboBox::*)(int)>(&QComboBox::currentIndexChanged), mEditor->tools(), &ToolManager::setBucketFillReferenceMode);
connect(ui->blendModeComboBox, static_cast<void (QComboBox::*)(int)>(&QComboBox::currentIndexChanged), mEditor->tools(), &ToolManager::setFillMode);

ui->expandSlider->setValue(settings.value(SETTING_BUCKET_FILL_EXPAND, 2).toInt());
ui->expandSpinBox->setValue(settings.value(SETTING_BUCKET_FILL_EXPAND, 2).toInt());
ui->colorToleranceSlider->setValue(settings.value(SETTING_BUCKET_TOLERANCE, 50).toInt());
ui->colorToleranceSpinbox->setValue(settings.value(SETTING_BUCKET_TOLERANCE, 50).toInt());
ui->fillToLayerComboBox->setCurrentIndex(settings.value(SETTING_BUCKET_FILL_TO_LAYER_MODE, 0).toInt());
ui->referenceLayerComboBox->setCurrentIndex(settings.value(SETTING_BUCKET_FILL_REFERENCE_MODE, 0).toInt());
ui->blendModeComboBox->setCurrentIndex(settings.value(SETTING_FILL_MODE, 0).toInt());

clearFocusOnFinished(ui->colorToleranceSpinbox);
clearFocusOnFinished(ui->expandSpinBox);

updatePropertyVisibility();
}

BucketOptionsWidget::~BucketOptionsWidget()
{
delete ui;
}

void BucketOptionsWidget::updatePropertyVisibility()
{
Layer* layer = mEditor->layers()->currentLayer();

Q_ASSERT(layer != nullptr);

switch (layer->type()) {
case Layer::VECTOR:
ui->strokeThicknessSlider->show();
ui->strokeThicknessSpinBox->show();

ui->fillToLayerComboBox->hide();
ui->fillToDescLabel->hide();
ui->colorToleranceCheckbox->hide();
ui->colorToleranceSlider->hide();
ui->colorToleranceSpinbox->hide();
ui->expandCheckbox->hide();
ui->expandSlider->hide();
ui->expandSpinBox->hide();
ui->referenceLayerComboBox->hide();
ui->referenceLayerDescLabel->hide();
ui->blendModeComboBox->hide();
ui->blendModeLabel->hide();
break;
case Layer::BITMAP:
ui->strokeThicknessSlider->hide();
ui->strokeThicknessSpinBox->hide();

ui->fillToLayerComboBox->show();
ui->fillToDescLabel->show();
ui->colorToleranceCheckbox->show();
ui->colorToleranceSlider->show();
ui->colorToleranceSpinbox->show();
ui->expandCheckbox->show();
ui->expandSlider->show();
ui->expandSpinBox->show();
ui->referenceLayerComboBox->show();
ui->referenceLayerDescLabel->show();
ui->blendModeComboBox->show();
ui->blendModeLabel->show();
break;
default:
ui->strokeThicknessSlider->hide();
ui->strokeThicknessSpinBox->hide();
ui->fillToLayerComboBox->hide();
ui->fillToDescLabel->hide();
ui->colorToleranceCheckbox->hide();
ui->colorToleranceSlider->hide();
ui->colorToleranceSpinbox->hide();
ui->expandCheckbox->hide();
ui->expandSlider->hide();
ui->expandSpinBox->hide();
ui->referenceLayerComboBox->hide();
ui->referenceLayerDescLabel->hide();
ui->blendModeComboBox->hide();
ui->blendModeLabel->hide();
}
}

void BucketOptionsWidget::onPropertyChanged(ToolType, ToolPropertyType propertyType)
{
const Properties& p = mEditor->tools()->currentTool()->properties;
switch (propertyType)
{
case ToolPropertyType::TOLERANCE:
setColorTolerance(static_cast<int>(p.tolerance)); break;
case ToolPropertyType::USETOLERANCE:
setColorToleranceEnabled(p.toleranceEnabled); break;
case ToolPropertyType::WIDTH:
setStrokeWidth(static_cast<int>(p.width)); break;
case ToolPropertyType::BUCKETFILLEXPAND:
setFillExpand(static_cast<int>(p.bucketFillExpand)); break;
case ToolPropertyType::USEBUCKETFILLEXPAND:
setFillExpandEnabled(p.bucketFillExpandEnabled); break;
case ToolPropertyType::BUCKETFILLLAYERMODE:
setFillToLayerMode(p.bucketFillToLayerMode); break;
case ToolPropertyType::BUCKETFILLLAYERREFERENCEMODE:
setFillReferenceMode(p.bucketFillReferenceMode); break;
case ToolPropertyType::FILL_MODE:
setFillMode(p.fillMode); break;
default:
Q_ASSERT(true);
break;
}
}

void BucketOptionsWidget::onLayerChanged(int)
{
updatePropertyVisibility();
}

void BucketOptionsWidget::setColorTolerance(int tolerance)
{
QSignalBlocker b(ui->colorToleranceSlider);
ui->colorToleranceSlider->setValue(tolerance);

QSignalBlocker b2(ui->colorToleranceSpinbox);
ui->colorToleranceSpinbox->setValue(tolerance);
}

void BucketOptionsWidget::setColorToleranceEnabled(bool enabled)
{
QSignalBlocker b(ui->colorToleranceCheckbox);
ui->colorToleranceCheckbox->setChecked(enabled);
}

void BucketOptionsWidget::setFillMode(int mode)
{
QSignalBlocker b(ui->blendModeComboBox);
ui->blendModeComboBox->setCurrentIndex(mode);
}

void BucketOptionsWidget::setFillExpandEnabled(bool enabled)
{
QSignalBlocker b(ui->expandCheckbox);
ui->expandCheckbox->setChecked(enabled);
}

void BucketOptionsWidget::setFillExpand(int value)
{
QSignalBlocker b(ui->expandSlider);
ui->expandSlider->setValue(value);

QSignalBlocker b2(ui->expandSpinBox);
ui->expandSpinBox->setValue(value);
}

void BucketOptionsWidget::setFillToLayerMode(int layerMode)
{
QSignalBlocker b(ui->fillToLayerComboBox);
ui->fillToLayerComboBox->setCurrentIndex(layerMode);
}

void BucketOptionsWidget::setFillReferenceMode(int referenceMode)
{
QSignalBlocker b(ui->referenceLayerComboBox);
ui->referenceLayerComboBox->setCurrentIndex(referenceMode);
}

void BucketOptionsWidget::setStrokeWidth(qreal value)
{
QSignalBlocker b(ui->strokeThicknessSlider);
ui->strokeThicknessSlider->setValue(value);

QSignalBlocker b2(ui->strokeThicknessSpinBox);
ui->strokeThicknessSpinBox->setValue(value);
}
61 changes: 61 additions & 0 deletions app/src/bucketoptionswidget.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
/*

Pencil2D - Traditional Animation Software
Copyright (C) 2005-2007 Patrick Corrieri & Pascal Naidon
Copyright (C) 2012-2020 Matthew Chiawen Chang

This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; version 2 of the License.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.

*/
#ifndef BUCKETOPTIONSWIDGET_H
#define BUCKETOPTIONSWIDGET_H

#include <QWidget>
#include "pencildef.h"

class Editor;
class Layer;

namespace Ui {
class BucketOptionsWidget;
}

class BucketOptionsWidget : public QWidget
{
Q_OBJECT

public:
explicit BucketOptionsWidget(Editor* editor, QWidget *parent = nullptr);
~BucketOptionsWidget();

void setStrokeWidth(qreal value);
void setColorToleranceEnabled(bool enabled);
void setFillExpandEnabled(bool enabled);
void setFillExpand(int value);
void setColorTolerance(int tolerance);
void setFillReferenceMode(int referenceMode);
void setFillToLayerMode(int layerMode);
void setFillMode(int mode);

void onPropertyChanged(ToolType, const ToolPropertyType propertyType);
void onLayerChanged(int);

private:
void updatePropertyVisibility();

Ui::BucketOptionsWidget *ui;
Editor* mEditor = nullptr;

const static int MAX_EXPAND = 25;
const static int MAX_COLOR_TOLERANCE = 100;
const static int MAX_STROKE_THICKNESS = 200;
};

#endif // BUCKETOPTIONSWIDGET_H
Loading