Warning, file /office/calligra/libs/widgets/KoFillConfigWidget.cpp was not indexed or was modified since last indexation (in which case cross-reference links may be missing, inaccurate or erroneous).

0001 /* This file is part of the KDE project
0002  * Made by Tomislav Lukman (tomislav.lukman@ck.tel.hr)
0003  * Copyright (C) 2012 Jean-Nicolas Artaud <jeannicolasartaud@gmail.com>
0004  *
0005  * This library is free software; you can redistribute it and/or
0006  * modify it under the terms of the GNU Library General Public
0007  * License as published by the Free Software Foundation; either
0008  * version 2 of the License, or (at your option) any later version.
0009  *
0010  * This library is distributed in the hope that it will be useful,
0011  * but WITHOUT ANY WARRANTY; without even the implied warranty of
0012  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
0013  * Library General Public License for more details.
0014  *
0015  * You should have received a copy of the GNU Library General Public License
0016  * along with this library; see the file COPYING.LIB.  If not, write to
0017  * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
0018  * Boston, MA 02110-1301, USA.
0019  */
0020 
0021 #include "KoFillConfigWidget.h"
0022 
0023 #include <QToolButton>
0024 #include <QHBoxLayout>
0025 #include <QButtonGroup>
0026 #include <QLabel>
0027 #include <QSizePolicy>
0028 #include <QBitmap>
0029 #include <QAction>
0030 #include <QSharedPointer>
0031 
0032 #include <klocalizedstring.h>
0033 
0034 #include <KoGroupButton.h>
0035 #include <KoIcon.h>
0036 #include <KoColor.h>
0037 #include <KoColorPopupAction.h>
0038 #include "KoResourceServerProvider.h"
0039 #include "KoResourceServerAdapter.h"
0040 #include "KoResourceSelector.h"
0041 #include <KoSelection.h>
0042 #include <KoToolManager.h>
0043 #include <KoCanvasBase.h>
0044 #include <KoCanvasController.h>
0045 #include <KoCanvasResourceManager.h>
0046 #include <KoDocumentResourceManager.h>
0047 #include <KoShape.h>
0048 #include <KoShapeManager.h>
0049 #include <KoShapeController.h>
0050 #include <KoShapeBackground.h>
0051 #include <KoShapeBackgroundCommand.h>
0052 #include <KoColorBackground.h>
0053 #include <KoGradientBackground.h>
0054 #include <KoPatternBackground.h>
0055 #include <KoImageCollection.h>
0056 #include <KoResourcePopupAction.h>
0057 #include "KoZoomHandler.h"
0058 #include "KoColorPopupButton.h"
0059 
0060 static const char* const buttonnone[]={
0061     "16 16 3 1",
0062     "# c #000000",
0063     "e c #ff0000",
0064     "- c #ffffff",
0065     "################",
0066     "#--------------#",
0067     "#--------------#",
0068     "#--------------#",
0069     "#--------------#",
0070     "#--------------#",
0071     "#--------------#",
0072     "#--------------#",
0073     "#--------------#",
0074     "#--------------#",
0075     "#--------------#",
0076     "#--------------#",
0077     "#--------------#",
0078     "#--------------#",
0079     "#--------------#",
0080     "################"};
0081 
0082 static const char* const buttonsolid[]={
0083     "16 16 2 1",
0084     "# c #000000",
0085     ". c #969696",
0086     "################",
0087     "#..............#",
0088     "#..............#",
0089     "#..............#",
0090     "#..............#",
0091     "#..............#",
0092     "#..............#",
0093     "#..............#",
0094     "#..............#",
0095     "#..............#",
0096     "#..............#",
0097     "#..............#",
0098     "#..............#",
0099     "#..............#",
0100     "#..............#",
0101     "################"};
0102 
0103 
0104 // FIXME: Smoother gradient button.
0105 
0106 static const char* const buttongradient[]={
0107     "16 16 15 1",
0108     "# c #000000",
0109     "n c #101010",
0110     "m c #202020",
0111     "l c #303030",
0112     "k c #404040",
0113     "j c #505050",
0114     "i c #606060",
0115     "h c #707070",
0116     "g c #808080",
0117     "f c #909090",
0118     "e c #a0a0a0",
0119     "d c #b0b0b0",
0120     "c c #c0c0c0",
0121     "b c #d0d0d0",
0122     "a c #e0e0e0",
0123     "################",
0124     "#abcdefghijklmn#",
0125     "#abcdefghijklmn#",
0126     "#abcdefghijklmn#",
0127     "#abcdefghijklmn#",
0128     "#abcdefghijklmn#",
0129     "#abcdefghijklmn#",
0130     "#abcdefghijklmn#",
0131     "#abcdefghijklmn#",
0132     "#abcdefghijklmn#",
0133     "#abcdefghijklmn#",
0134     "#abcdefghijklmn#",
0135     "#abcdefghijklmn#",
0136     "#abcdefghijklmn#",
0137     "#abcdefghijklmn#",
0138     "################"};
0139 
0140 static const char* const buttonpattern[]={
0141     "16 16 4 1",
0142     ". c #0a0a0a",
0143     "# c #333333",
0144     "a c #a0a0a0",
0145     "b c #ffffffff",
0146     "################",
0147     "#aaaaabbbbaaaaa#",
0148     "#aaaaabbbbaaaaa#",
0149     "#aaaaabbbbaaaaa#",
0150     "#aaaaabbbbaaaaa#",
0151     "#aaaaabbbbaaaaa#",
0152     "#bbbbbaaaabbbbb#",
0153     "#bbbbbaaaabbbbb#",
0154     "#bbbbbaaaabbbbb#",
0155     "#bbbbbaaaabbbbb#",
0156     "#aaaaabbbbaaaaa#",
0157     "#aaaaabbbbaaaaa#",
0158     "#aaaaabbbbaaaaa#",
0159     "#aaaaabbbbaaaaa#",
0160     "#aaaaabbbbaaaaa#",
0161     "################"};
0162 
0163 class Q_DECL_HIDDEN KoFillConfigWidget::Private
0164 {
0165 public:
0166     Private()
0167     : canvas(nullptr)
0168     {
0169     }
0170     /// Apply the gradient stops using the shape background
0171     QSharedPointer<KoShapeBackground> applyFillGradientStops(KoShape *shape, const QGradientStops &stops)
0172     {
0173         if (! shape || ! stops.count()) {
0174             return QSharedPointer<KoShapeBackground>();
0175         }
0176 
0177         KoGradientBackground *newGradient = nullptr;
0178         QSharedPointer<KoGradientBackground> oldGradient = qSharedPointerDynamicCast<KoGradientBackground>(shape->background());
0179         if (oldGradient) {
0180             // just copy the gradient and set the new stops
0181             QGradient *g = KoFlake::cloneGradient(oldGradient->gradient());
0182             g->setStops(stops);
0183             newGradient = new KoGradientBackground(g);
0184             newGradient->setTransform(oldGradient->transform());
0185         }
0186         else {
0187             // No gradient yet, so create a new one.
0188             QLinearGradient *g = new QLinearGradient(QPointF(0, 0), QPointF(1, 1));
0189             g->setCoordinateMode(QGradient::ObjectBoundingMode);
0190             g->setStops(stops);
0191             newGradient = new KoGradientBackground(g);
0192         }
0193         return QSharedPointer<KoGradientBackground>(newGradient);
0194     }
0195 
0196     KoColorPopupButton *colorButton;
0197     QAction *noFillAction;
0198     KoColorPopupAction *colorAction;
0199     KoResourcePopupAction *gradientAction;
0200     KoResourcePopupAction *patternAction;
0201     QButtonGroup *group;
0202 
0203     QWidget *spacer;
0204     KoCanvasBase *canvas;
0205 };
0206 
0207 KoFillConfigWidget::KoFillConfigWidget(QWidget *parent)
0208 :  QWidget(parent)
0209 , d(new Private())
0210 {
0211     setObjectName("Fill widget");
0212     QHBoxLayout *layout = new QHBoxLayout(this);
0213     layout->setMargin(0);
0214     layout->setSpacing(0);
0215 
0216     d->group = new QButtonGroup(this);
0217     d->group->setExclusive(true);
0218 
0219     // The button for no fill
0220     KoGroupButton *button = new KoGroupButton(KoGroupButton::GroupLeft, this);
0221     QPixmap noFillButtonIcon((const char **) buttonnone);
0222     noFillButtonIcon.setMask(QBitmap(noFillButtonIcon));
0223     button->setIcon(noFillButtonIcon);
0224     button->setToolTip(i18nc("No stroke or fill", "None"));
0225     button->setCheckable(true);
0226     d->group->addButton(button, None);
0227     layout->addWidget(button);
0228 
0229     // The button for solid fill
0230     button = new KoGroupButton(KoGroupButton::GroupCenter, this);
0231     button->setIcon(QPixmap((const char **) buttonsolid));
0232     button->setToolTip(i18nc("Solid color stroke or fill", "Solid"));
0233     button->setCheckable(true);
0234     d->group->addButton(button, Solid);
0235     layout->addWidget(button);
0236 
0237     // The button for gradient fill
0238     button = new KoGroupButton(KoGroupButton::GroupCenter, this);
0239     button->setIcon(QPixmap((const char **) buttongradient));
0240     button->setToolTip(i18n("Gradient"));
0241     button->setCheckable(true);
0242     d->group->addButton(button, Gradient);
0243     layout->addWidget(button);
0244 
0245     // The button for pattern fill
0246     button = new KoGroupButton(KoGroupButton::GroupRight, this);
0247     button->setIcon(QPixmap((const char **) buttonpattern));
0248     button->setToolTip(i18n("Pattern"));
0249     button->setCheckable(true);
0250     d->group->addButton(button, Pattern);
0251     layout->addWidget(button);
0252 
0253     connect(d->group, SIGNAL(buttonClicked(int)), this, SLOT(styleButtonPressed(int)));
0254 
0255     d->colorButton = new KoColorPopupButton(this);
0256     d->colorButton->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Fixed);
0257     layout->addWidget(d->colorButton);
0258 
0259     d->noFillAction = new QAction(nullptr);
0260 
0261     d->colorAction = new KoColorPopupAction(d->colorButton);
0262     d->colorAction->setToolTip(i18n("Change the filling color"));
0263     d->colorAction->setCurrentColor(Qt::white);
0264     d->colorButton->setDefaultAction(d->colorAction);
0265     d->colorButton->setPopupMode(QToolButton::InstantPopup);
0266     connect(d->colorAction, SIGNAL(colorChanged(KoColor)), this, SLOT(colorChanged()));
0267     connect(d->colorButton, SIGNAL(iconSizeChanged()), d->colorAction, SLOT(updateIcon()));
0268 
0269     // Gradient selector
0270     KoResourceServerProvider *serverProvider = KoResourceServerProvider::instance();
0271     QSharedPointer<KoAbstractResourceServerAdapter> gradientResourceAdapter(new KoResourceServerAdapter<KoAbstractGradient>(serverProvider->gradientServer()));
0272     d->gradientAction = new KoResourcePopupAction(gradientResourceAdapter, d->colorButton);
0273     d->gradientAction->setToolTip(i18n("Change the filling gradient"));
0274     connect(d->gradientAction, SIGNAL(resourceSelected(QSharedPointer<KoShapeBackground>)), this, SLOT(gradientChanged(QSharedPointer<KoShapeBackground>)));
0275     connect(d->colorButton, SIGNAL(iconSizeChanged()), d->gradientAction, SLOT(updateIcon()));
0276 
0277     // Pattern selector
0278     QSharedPointer<KoAbstractResourceServerAdapter>patternResourceAdapter(new KoResourceServerAdapter<KoPattern>(serverProvider->patternServer()));
0279     d->patternAction = new KoResourcePopupAction(patternResourceAdapter, d->colorButton);
0280     d->patternAction->setToolTip(i18n("Change the filling pattern"));
0281     connect(d->patternAction, SIGNAL(resourceSelected(QSharedPointer<KoShapeBackground>)), this, SLOT(patternChanged(QSharedPointer<KoShapeBackground>)));
0282     connect(d->colorButton, SIGNAL(iconSizeChanged()), d->patternAction, SLOT(updateIcon()));
0283 
0284     // Spacer
0285     d->spacer = new QWidget();
0286     d->spacer->setObjectName("SpecialSpacer");
0287     layout->addWidget(d->spacer);
0288 
0289     KoCanvasController *canvasController = KoToolManager::instance()->activeCanvasController();
0290     KoSelection *selection = canvasController->canvas()->shapeManager()->selection();
0291     if (selection) {
0292         d->canvas = canvasController->canvas();
0293         connect(selection, SIGNAL(selectionChanged()), this, SLOT(shapeChanged()));
0294     }
0295 }
0296 
0297 KoFillConfigWidget::~KoFillConfigWidget()
0298 {
0299     delete d->noFillAction;
0300     delete d;
0301 }
0302 
0303 void KoFillConfigWidget::setCanvas( KoCanvasBase *canvas )
0304 {
0305     KoCanvasController *canvasController = KoToolManager::instance()->activeCanvasController();
0306     KoSelection *selection = canvasController->canvas()->shapeManager()->selection();
0307 
0308     connect(selection, SIGNAL(selectionChanged()), this, SLOT(shapeChanged()));
0309 
0310     d->canvas = canvas;
0311 }
0312 
0313 KoCanvasBase* KoFillConfigWidget::canvas()
0314 {
0315     return d->canvas;
0316 }
0317 
0318 QList<KoShape*> KoFillConfigWidget::currentShapes()
0319 {
0320     KoCanvasController *canvasController = KoToolManager::instance()->activeCanvasController();
0321     KoSelection *selection = canvasController->canvas()->shapeManager()->selection();
0322     return selection->selectedShapes();
0323 }
0324 
0325 KoShape *KoFillConfigWidget::currentShape()
0326 {
0327     KoCanvasController *canvasController = KoToolManager::instance()->activeCanvasController();
0328     KoSelection *selection = canvasController->canvas()->shapeManager()->selection();
0329     return selection->firstSelectedShape();
0330 }
0331 
0332 
0333 void KoFillConfigWidget::styleButtonPressed(int buttonId)
0334 {
0335     d->colorButton->setEnabled(true);
0336     switch (buttonId) {
0337         case KoFillConfigWidget::None:
0338             // Direct manipulation
0339             d->colorButton->setDefaultAction(d->noFillAction);
0340              d->colorButton->setDisabled(true);
0341             noColorSelected();
0342             break;
0343         case KoFillConfigWidget::Solid:
0344             d->colorButton->setDefaultAction(d->colorAction);
0345             colorChanged();
0346             break;
0347         case KoFillConfigWidget::Gradient:
0348             // Only select mode in the widget, don't set actual gradient :/
0349             d->colorButton->setDefaultAction(d->gradientAction);
0350             gradientChanged(d->gradientAction->currentBackground());
0351             break;
0352         case KoFillConfigWidget::Pattern:
0353             // Only select mode in the widget, don't set actual pattern :/
0354             d->colorButton->setDefaultAction(d->patternAction);
0355             patternChanged(d->patternAction->currentBackground());
0356             break;
0357     }
0358     d->colorButton->setPopupMode(QToolButton::InstantPopup);
0359 }
0360 
0361 void KoFillConfigWidget::noColorSelected()
0362 {
0363     QList<KoShape*> selectedShapes = currentShapes();
0364     if (selectedShapes.isEmpty()) {
0365         return;
0366     }
0367     KoCanvasController *canvasController = KoToolManager::instance()->activeCanvasController();
0368     canvasController->canvas()->addCommand(new KoShapeBackgroundCommand(selectedShapes, QSharedPointer<KoShapeBackground>(0)));
0369 }
0370 
0371 void KoFillConfigWidget::colorChanged()
0372 {
0373     QList<KoShape*> selectedShapes = currentShapes();
0374     if (selectedShapes.isEmpty()) {
0375         return;
0376     }
0377 
0378     QSharedPointer<KoShapeBackground> fill(new KoColorBackground(d->colorAction->currentColor()));
0379     KUndo2Command *firstCommand = nullptr;
0380     foreach (KoShape *shape, selectedShapes) {
0381         if (! firstCommand) {
0382             firstCommand = new KoShapeBackgroundCommand(shape, fill);
0383         } else {
0384             new KoShapeBackgroundCommand(shape, fill, firstCommand);
0385         }
0386     }
0387 
0388     KoCanvasController *canvasController = KoToolManager::instance()->activeCanvasController();
0389     canvasController->canvas()->addCommand(firstCommand);
0390 }
0391 
0392 void KoFillConfigWidget::gradientChanged(QSharedPointer<KoShapeBackground>  background)
0393 {
0394     QList<KoShape*> selectedShapes = currentShapes();
0395     if (selectedShapes.isEmpty()) {
0396         return;
0397     }
0398 
0399     QSharedPointer<KoGradientBackground> gradientBackground = qSharedPointerDynamicCast<KoGradientBackground>(background);
0400     if (!gradientBackground) {
0401         return;
0402     }
0403 
0404     QGradientStops newStops = gradientBackground->gradient()->stops();
0405     gradientBackground.clear();
0406 
0407     KUndo2Command *firstCommand = nullptr;
0408     foreach (KoShape *shape, selectedShapes) {
0409         QSharedPointer<KoShapeBackground> fill = d->applyFillGradientStops(shape, newStops);
0410         if (! fill) {
0411             continue;
0412         }
0413         if (! firstCommand) {
0414             firstCommand = new KoShapeBackgroundCommand(shape, fill);
0415         } else {
0416             new KoShapeBackgroundCommand(shape, fill, firstCommand);
0417         }
0418     }
0419     KoCanvasController *canvasController = KoToolManager::instance()->activeCanvasController();
0420     canvasController->canvas()->addCommand(firstCommand);
0421 }
0422 
0423 void KoFillConfigWidget::patternChanged(QSharedPointer<KoShapeBackground>  background)
0424 {
0425     QSharedPointer<KoPatternBackground> patternBackground = qSharedPointerDynamicCast<KoPatternBackground>(background);
0426     if (! patternBackground) {
0427         return;
0428     }
0429 
0430     QList<KoShape*> selectedShapes = currentShapes();
0431     if (selectedShapes.isEmpty()) {
0432         return;
0433     }
0434 
0435     KoCanvasController *canvasController = KoToolManager::instance()->activeCanvasController();
0436     KoImageCollection *imageCollection = canvasController->canvas()->shapeController()->resourceManager()->imageCollection();
0437     if (imageCollection) {
0438         QSharedPointer<KoPatternBackground> fill(new KoPatternBackground(imageCollection));
0439         fill->setPattern(patternBackground->pattern());
0440         canvasController->canvas()->addCommand(new KoShapeBackgroundCommand(selectedShapes, fill));
0441     }
0442 }
0443 
0444 void KoFillConfigWidget::shapeChanged()
0445 {
0446     KoShape *shape = currentShape();
0447     if (! shape) {
0448         d->group->button(KoFillConfigWidget::None)->setChecked(false);
0449         d->group->button(KoFillConfigWidget::Solid)->setChecked(false);
0450         d->group->button(KoFillConfigWidget::Gradient)->setChecked(false);
0451         d->group->button(KoFillConfigWidget::Pattern)->setChecked(false);
0452         d->colorButton->setDisabled(true);
0453         return;
0454     }
0455 
0456     d->colorAction->blockSignals(true);
0457     updateWidget(shape);
0458     d->colorAction->blockSignals(false);
0459 }
0460 
0461 
0462 void KoFillConfigWidget::updateWidget(KoShape *shape)
0463 {
0464     if (! shape) {
0465         return;
0466     }
0467 
0468     KoZoomHandler zoomHandler;
0469     const qreal realWidth = zoomHandler.resolutionX() * width();
0470     const qreal realHeight = zoomHandler.resolutionX() * height();
0471 
0472     const qreal zoom = (realWidth > realHeight) ? realHeight : realWidth;
0473     zoomHandler.setZoom(zoom);
0474 
0475     shape->waitUntilReady(zoomHandler, false);
0476 
0477     d->colorButton->setEnabled(true);
0478     QSharedPointer<KoShapeBackground> background = shape->background();
0479     if (! background) {
0480         // No Fill
0481         d->group->button(KoFillConfigWidget::None)->setChecked(true);
0482         d->colorButton->setDefaultAction(d->noFillAction);
0483         d->colorButton->setDisabled(true);
0484         d->colorButton->setPopupMode(QToolButton::InstantPopup);
0485         return;
0486     }
0487 
0488     QSharedPointer<KoColorBackground> colorBackground = qSharedPointerDynamicCast<KoColorBackground>(background);
0489     QSharedPointer<KoGradientBackground> gradientBackground = qSharedPointerDynamicCast<KoGradientBackground>(background);
0490     QSharedPointer<KoPatternBackground> patternBackground = qSharedPointerDynamicCast<KoPatternBackground>(background);
0491 
0492     if (colorBackground) {
0493         d->colorAction->setCurrentColor(colorBackground->color());
0494         d->group->button(KoFillConfigWidget::Solid)->setChecked(true);
0495         d->colorButton->setDefaultAction(d->colorAction);
0496     } else if (gradientBackground) {
0497         d->gradientAction->setCurrentBackground(background);
0498         d->group->button(KoFillConfigWidget::Gradient)->setChecked(true);
0499         d->colorButton->setDefaultAction(d->gradientAction);
0500     } else if (patternBackground) {
0501         d->patternAction->setCurrentBackground(background);
0502         d->group->button(KoFillConfigWidget::Pattern)->setChecked(true);
0503         d->colorButton->setDefaultAction(d->patternAction);
0504     } else {
0505         // No Fill
0506         d->group->button(KoFillConfigWidget::None)->setChecked(true);
0507         d->colorButton->setDefaultAction(d->noFillAction);
0508         d->colorButton->setDisabled(true);
0509     }
0510     d->colorButton->setPopupMode(QToolButton::InstantPopup);
0511 }