13#include <QButtonGroup>
17#include <QSharedPointer>
20#include <klocalizedstring.h>
43#include "ui_KoFillConfigWidget.h"
50#include <QInputDialog>
162using namespace std::placeholders;
173 fillVariant(_fillVariant),
174 noSelectionTrackingMode(false)
181 QButtonGroup *group {
nullptr};
194 bool noSelectionTrackingMode {
false};
199 QScopedPointer<Ui_KoFillConfigWidget>
ui;
208 , d(new
Private(fillVariant, this))
212 if (trackShapeSelection) {
218 d->resourceManagerAcyclicConnector.connectBackwardResourcePair(
222 d->resourceManagerAcyclicConnector.connectForwardVoid(
233 d->ui.reset(
new Ui_KoFillConfigWidget());
234 d->ui->setupUi(
this);
236 d->group =
new QButtonGroup(
this);
237 d->group->setExclusive(
true);
239 d->ui->btnNoFill->setIcon(QPixmap((
const char **)
buttonnone));
240 d->group->addButton(
d->ui->btnNoFill,
None);
242 d->ui->btnSolidFill->setIcon(QPixmap((
const char **)
buttonsolid));
243 d->group->addButton(
d->ui->btnSolidFill,
Solid);
245 d->ui->btnGradientFill->setIcon(QPixmap((
const char **)
buttongradient));
246 d->group->addButton(
d->ui->btnGradientFill,
Gradient);
248 d->ui->btnPatternFill->setIcon(QPixmap((
const char **)
buttonpattern));
249 d->group->addButton(
d->ui->btnPatternFill,
Pattern);
250 d->ui->btnPatternFill->setVisible(
false);
254 d->ui->btnMeshFill->setIcon(QPixmap((
const char**)
buttonpattern));
257 d->ui->btnMeshFill->setVisible(
false);
261 d->colorAction->setToolTip(i18n(
"Change the filling color"));
262 d->colorAction->setCurrentColor(Qt::white);
264 d->ui->btnChooseSolidColor->setDefaultAction(
d->colorAction);
265 d->ui->btnChooseSolidColor->setPopupMode(QToolButton::InstantPopup);
269 d->ui->btnSolidColorSample->setEnabled(
false);
270 d->ui->btnSolidColorSample->setVisible(
false);
273 d->colorChangedCompressor.start({color.toQColor(), d->fillVariant});
276 connect(d->ui->btnChooseSolidColor, SIGNAL(iconSizeChanged()), d->colorAction, SLOT(updateIcon()));
278 connect(d->group, SIGNAL(idClicked(
int)), SLOT(styleButtonPressed(
int)));
280 connect(d->group, SIGNAL(idClicked(
int)), SLOT(slotUpdateFillTitle()));
282 slotUpdateFillTitle();
283 styleButtonPressed(d->group->checkedId());
287 d->ui->wdgGradientEditor->setCompactMode(
true);
288 d->ui->wdgGradientEditor->setCanvasResourcesInterface(canvas->resourceManager()->canvasResourcesInterface());
289 connect(d->ui->wdgGradientEditor, SIGNAL(sigGradientChanged()), &d->gradientChangedCompressor, SLOT(start()));
290 connect(&d->gradientChangedCompressor, SIGNAL(timeout()), SLOT(activeGradientChanged()));
294 d->gradientAction->setToolTip(i18n(
"Change filling gradient"));
295 d->ui->btnChoosePredefinedGradient->setDefaultAction(d->gradientAction);
296 d->ui->btnChoosePredefinedGradient->setPopupMode(QToolButton::InstantPopup);
299 SLOT(gradientResourceChanged()));
300 connect(d->ui->btnChoosePredefinedGradient, SIGNAL(iconSizeChanged()), d->gradientAction, SLOT(updateIcon()));
303 connect(d->ui->btnSaveGradient, SIGNAL(clicked()), SLOT(slotSavePredefinedGradientClicked()));
305 connect(d->ui->cmbGradientRepeat, SIGNAL(currentIndexChanged(
int)), SLOT(slotGradientRepeatChanged()));
306 connect(d->ui->cmbGradientType, SIGNAL(currentIndexChanged(
int)), SLOT(slotGradientTypeChanged()));
309 connect(d->ui->meshStopColorButton, SIGNAL(changed(
const KoColor&)),
this, SLOT(slotMeshHandleColorChanged(
const KoColor&)));
311 d->ui->spinbRows->setRange(1, 20);
312 d->ui->spinbColumns->setRange(1, 20);
313 connect(d->ui->spinbRows, SIGNAL(valueChanged(
int)), SLOT(slotMeshGradientChanged()));
314 connect(d->ui->spinbColumns, SIGNAL(valueChanged(
int)), SLOT(slotMeshGradientChanged()));
315 connect(d->ui->cmbSmoothingType, SIGNAL(currentIndexChanged(
int)), SLOT(slotMeshGradientShadingChanged(
int)));
340 d->deactivationLocks.clear();
342 if (!
d->noSelectionTrackingMode) {
343 d->shapeChangedCompressor.start();
361 d->shapeChangedCompressor.start();
366 d->meshposition = position;
372 d->noSelectionTrackingMode =
value;
373 if (!
d->noSelectionTrackingMode) {
374 d->shapeChangedCompressor.start();
380 QString text =
d->group->checkedButton() ?
d->group->checkedButton()->text() : QString();
381 text.replace(
'&', QString());
382 d->ui->lblFillTitle->setText(text);
392 const int checkedId =
d->group->checkedId();
394 if (checkedId < 0 || checkedId ==
None || checkedId ==
Solid) {
396 d->group->button(
Solid)->setChecked(
true);
397 d->selectedFillIndex =
Solid;
403 if (key ==
d->fillVariant) {
404 d->colorAction->setCurrentColor(color);
408 d->ui->wdgGradientEditor->notifyGlobalColorChanged(color);
412 const int checkedId =
d->group->checkedId();
414 if (gradient && (checkedId < 0 || checkedId ==
None || checkedId ==
Gradient)) {
415 d->group->button(
Gradient)->setChecked(
true);
416 d->gradientAction->setCurrentResource(gradient);
427 return d->selectedFillIndex;
442 if (
d->activeGradient) {
455 if (
d->activeMeshGradient) {
466 if (shapes.isEmpty() ==
false) {
467 KoShape *firstShape = shapes.first();
479 switch (
d->group->checkedId()) {
481 stroke->setColor(Qt::transparent);
484 stroke->setColor(
d->colorAction->currentColor());
487 QScopedPointer<QGradient> g(
d->activeGradient->toQGradient());
488 QBrush newBrush = *g;
489 stroke->setLineBrush(newBrush);
490 stroke->setColor(Qt::transparent);
503 if (selectedShapes.isEmpty()) {
520 QColor color = resource.first;
522 if (!color.isValid()) {
527 if (selectedShapes.isEmpty()) {
533 d->overriddenColorFromProvider[
fillVariant] = boost::none;
550 QColor solidColor =
d->colorAction->currentColor();
551 solidColor.setAlpha(255);
552 command = wrapper.
setColor(solidColor);
565 const int checkedId =
d->group->checkedId();
569 if (!
d->overriddenColorFromProvider[var]) {
570 d->overriddenColorFromProvider[var] =
586 if (!wrapper.
color().isValid()) {
591 uploadColorToResourceManager(res, fill, color);
594 if (checkedId ==
Solid) {
599 KoColor color =
d->colorAction->currentKoColor();
600 uploadColorToResourceManager(res,
d->fillVariant, color);
606 if (boost::optional<KoColor> gradientColor =
607 d->ui->wdgGradientEditor->currentActiveStopColor()) {
608 KoColor color = *gradientColor;
612 uploadColorToResourceManager(res,
d->fillVariant, color);
621 if (
d->overriddenColorFromProvider[var]) {
623 res, QVariant::fromValue(*
d->overriddenColorFromProvider[var]));
624 d->overriddenColorFromProvider[var] = boost::none;
637 const QString defaultGradientNamePrefix = i18nc(
"default prefix for the saved gradient",
"gradient");
638 const QString saveLocation = server->saveLocation();
640 QString name =
d->activeGradient->name().isEmpty() ? defaultGradientNamePrefix :
d->activeGradient->name();
641 QFileInfo fileInfo(saveLocation + name.split(
" ").join(
"_") +
d->activeGradient->defaultFileExtension());
642 bool fileOverWriteAccepted =
false;
644 while(!fileOverWriteAccepted) {
645 name = QInputDialog::getText(
this,
646 i18nc(
"@title:window",
"Save Gradient"),
647 i18n(
"Enter gradient name:"),
648 QLineEdit::Normal, name);
649 if (name.isNull() || name.isEmpty()) {
652 fileInfo = QFileInfo(saveLocation + name.split(
" ").join(
"_") +
d->activeGradient->defaultFileExtension());
653 if (fileInfo.exists()) {
654 int res = QMessageBox::warning(
this, i18nc(
"@title:window",
"Name Already Exists")
655 , i18n(
"The name '%1' already exists, do you wish to overwrite it?", name)
656 , QMessageBox::Yes | QMessageBox::No);
657 if (res == QMessageBox::Yes) fileOverWriteAccepted =
true;
659 fileOverWriteAccepted =
true;
664 d->activeGradient->setName(name);
665 d->activeGradient->setFilename(name.split(
" ").join(
"_") +
d->activeGradient->defaultFileExtension());
671 d->gradientAction->setCurrentResource(newGradient);
685 qSharedPointerDynamicCast<KoGradientBackground>(
686 d->gradientAction->currentBackground());
696 QGradient::Type type =
697 d->ui->cmbGradientType->currentIndex() == 0 ?
698 QGradient::LinearGradient : QGradient::RadialGradient;
700 d->activeGradient->setType(type);
706 QGradient::Spread spread =
707 QGradient::Spread(
d->ui->cmbGradientRepeat->currentIndex());
709 d->activeGradient->setSpread(spread);
716 d->ui->cmbGradientType,
717 d->ui->cmbGradientRepeat);
719 d->ui->wdgGradientEditor->setGradient(0);
723 d->ui->wdgGradientEditor->setGradient(
d->activeGradient);
724 d->ui->cmbGradientType->setCurrentIndex(
d->activeGradient->type() != QGradient::LinearGradient);
725 d->ui->cmbGradientRepeat->setCurrentIndex(
int(
d->activeGradient->spread()));
731 if (selectedShapes.isEmpty()) {
737 QScopedPointer<QGradient> srcQGradient(
d->activeGradient->toQGradient());
749 bool savingEnabled =
false;
751 QScopedPointer<QGradient> currentGradient(
d->activeGradient->toQGradient());
755 qSharedPointerDynamicCast<KoGradientBackground>(bg);
757 savingEnabled = resourceBackground->gradient()->stops() != currentGradient->stops();
758 savingEnabled |= resourceBackground->gradient()->type() != currentGradient->type();
759 savingEnabled |= resourceBackground->gradient()->spread() != currentGradient->spread();
762 d->ui->btnSaveGradient->setEnabled(savingEnabled);
767 Q_UNUSED(background);
771 if (! patternBackground) {
776 if (selectedShapes.isEmpty()) {
781 fill->setPattern(patternBackground->pattern());
812 if (
d->meshposition.isValid()) {
818 d->activeMeshGradient->getMeshArray()->modifyColor(
d->meshposition, c.
toQColor());
828 if (
d->group->checkedId() == -1 ||
d->group->checkedId() ==
None) {
829 d->group->button(
Solid)->setChecked(
true);
831 d->selectedFillIndex =
Solid;
832 d->colorAction->setCurrentColor(color);
835 Q_FOREACH (QAbstractButton *
button,
d->group->buttons()) {
845 if (selectedShapes.isEmpty()) {
863 if (selectedShapes.isEmpty()) {
869 for (
const auto& shape: selectedShapes) {
870 QSizeF size = shape->boundingRect().size();
871 if (size.height() > maxSize.height()) {
872 maxSize.rheight() = size.height();
874 if (size.width() > maxSize.width()) {
875 maxSize.rwidth() = size.width();
883 int nrows =
d->ui->spinbRows->value();
884 int ncols =
d->ui->spinbColumns->value();
886 if (
d->ui->cmbSmoothingType->currentIndex()) {
892 gradient->
getMeshArray()->createDefaultMesh(nrows, ncols, color, maxSize);
894 d->activeMeshGradient.reset(gradient);
901 if (selectedShapes.isEmpty()) {
918 if (!
d->activeMeshGradient)
return;
922 d->ui->cmbSmoothingType,
923 d->ui->meshStopColorButton);
925 SvgMeshArray *mesharray =
d->activeMeshGradient->getMeshArray().data();
926 d->ui->spinbRows->setValue(mesharray->
numRows());
927 d->ui->spinbColumns->setValue(mesharray->
numColumns());
928 d->ui->cmbSmoothingType->setCurrentIndex(
d->activeMeshGradient->type());
929 if (
d->meshposition.isValid()) {
930 QColor qc =
d->activeMeshGradient->getMeshArray()->getStop(
d->meshposition).color;
932 KoColor c =
d->ui->meshStopColorButton->color();
935 d->ui->meshStopColorButton->setColor(c);
936 d->ui->meshStopColorButton->setDisabled(
false);
938 d->ui->meshStopColorButton->setDisabled(
true);
944 if (
d->noSelectionTrackingMode)
return;
948 bool shouldUploadColorToResourceManager =
false;
952 if (shapes.isEmpty() ||
955 Q_FOREACH (QAbstractButton *
button,
d->group->buttons()) {
956 button->setEnabled(!shapes.isEmpty());
960 Q_FOREACH (QAbstractButton *
button,
d->group->buttons()) {
965 KoShape *shape = shapes.first();
968 shouldUploadColorToResourceManager =
true;
972 d->group->button(
d->selectedFillIndex)->setChecked(
true);
977 if (shouldUploadColorToResourceManager) {
989 switch (wrapper.
type()) {
995 QColor color = wrapper.
color();
996 if (color.alpha() > 0) {
997 d->colorAction->setCurrentColor(wrapper.
color());
1023 d->ui->wdgGradientEditor->setVisible(
false);
1024 d->ui->btnChoosePredefinedGradient->setVisible(
false);
1025 d->ui->btnChooseSolidColor->setVisible(
false);
1026 d->ui->typeLabel->setVisible(
false);
1027 d->ui->repeatLabel->setVisible(
false);
1028 d->ui->cmbGradientRepeat->setVisible(
false);
1029 d->ui->cmbGradientType->setVisible(
false);
1030 d->ui->btnSolidColorSample->setVisible(
false);
1031 d->ui->btnSaveGradient->setVisible(
false);
1032 d->ui->gradientTypeLine->setVisible(
false);
1033 d->ui->soldStrokeColorLabel->setVisible(
false);
1034 d->ui->presetLabel->setVisible(
false);
1035 d->ui->stopColorLabel->setVisible(
false);
1036 d->ui->meshStopColorButton->setVisible(
false);
1037 d->ui->rowsLabel->setVisible(
false);
1038 d->ui->spinbRows->setVisible(
false);
1039 d->ui->columnsLabel->setVisible(
false);
1040 d->ui->spinbColumns->setVisible(
false);
1041 d->ui->smoothingTypeLabel->setVisible(
false);
1042 d->ui->cmbSmoothingType->setVisible(
false);
1050 switch (
d->selectedFillIndex) {
1054 d->ui->btnChooseSolidColor->setVisible(
true);
1055 d->ui->btnSolidColorSample->setVisible(
false);
1056 d->ui->soldStrokeColorLabel->setVisible(
true);
1059 d->ui->wdgGradientEditor->setVisible(
true);
1060 d->ui->btnChoosePredefinedGradient->setVisible(
true);
1061 d->ui->typeLabel->setVisible(
true);
1062 d->ui->repeatLabel->setVisible(
true);
1063 d->ui->cmbGradientRepeat->setVisible(
true);
1064 d->ui->cmbGradientType->setVisible(
true);
1065 d->ui->btnSaveGradient->setVisible(
true);
1066 d->ui->gradientTypeLine->setVisible(
true);
1067 d->ui->presetLabel->setVisible(
true);
1072 d->ui->stopColorLabel->setVisible(
true);
1073 d->ui->meshStopColorButton->setVisible(
true);
1074 d->ui->rowsLabel->setVisible(
true);
1075 d->ui->spinbRows->setVisible(
true);
1076 d->ui->columnsLabel->setVisible(
true);
1077 d->ui->spinbColumns->setVisible(
true);
1078 d->ui->smoothingTypeLabel->setVisible(
true);
1079 d->ui->cmbSmoothingType->setVisible(
true);
1080 d->ui->meshStopColorButton->setAlphaChannelEnabled(
true);
float value(const T *src, size_t ch)
const quint8 OPACITY_OPAQUE_U8
connect(this, SIGNAL(optionsChanged()), this, SLOT(saveOptions()))
std::unique_lock< KisAcyclicSignalConnector > Blocker
void connectForwardVoid(QObject *sender, const char *signal, QObject *receiver, const char *method)
KisSelectedShapesProxy selectedShapesProxy
void addCommand(KUndo2Command *command) override
static bool addResourceWithUserInput(QWidget *widgetParent, KoResourceSP resource, QString storageLocation="")
KoSelection * selection() override
QPointer< KoCanvasResourceProvider > resourceManager
void setOpacity(quint8 alpha)
void fromQColor(const QColor &c)
Convenient function for converting from a QColor.
void toQColor(QColor *c) const
a convenience method for the above.
A pattern shape background.
const QList< KoShape * > selectedEditableShapes() const
The undo / redo command for setting the shape background.
KoFlake::FillType type() const
KUndo2Command * applyGradientStopsOnly(const QGradient *gradient)
const SvgMeshGradient * meshgradient() const
KUndo2Command * setMeshGradient(const SvgMeshGradient *gradient, const QTransform &transform)
const QGradient * gradient() const
bool hasZeroLineWidth() const
KUndo2Command * setLineWidth(const float &lineWidth)
KUndo2Command * setColor(const QColor &color)
static QSharedPointer< KoStopGradient > fromQGradient(const QGradient *gradient)
Creates KoStopGradient from a QGradient.
void setType(Shading type)
const QScopedPointer< SvgMeshArray > & getMeshArray() const
void setGradientUnits(KoFlake::CoordinateSystem units=KoFlake::UserSpaceOnUse)
#define KIS_ASSERT_RECOVER_RETURN_VALUE(cond, val)
#define KIS_SAFE_ASSERT_RECOVER_RETURN(cond)
#define KIS_SAFE_ASSERT_RECOVER_NOOP(cond)
QString button(const QWheelEvent &ev)
QIcon loadIcon(const QString &name)
@ BackgroundColor
The active background color selected for this canvas.
@ ForegroundColor
The active foreground color selected for this canvas.
@ Background
the background / fill style is active
static KoResourceServerProvider * instance()
KoResourceServer< KoAbstractGradient > * gradientServer