File indexing completed on 2024-05-12 16:02:07

0001 /* This file is part of the KDE project
0002  * SPDX-FileCopyrightText: 2007 C. Boemann <cbo@boemann.dk>
0003  * SPDX-FileCopyrightText: 2007 Fredy Yanardi <fyanardi@gmail.com>
0004  *
0005  * SPDX-License-Identifier: LGPL-2.0-or-later
0006  */
0007 
0008 #include "KoColorPopupAction.h"
0009 
0010 #include "KoColorSetWidget.h"
0011 #include "KoTriangleColorSelector.h"
0012 #include "KoColorSlider.h"
0013 #include "KoCheckerBoardPainter.h"
0014 #include "KoResourceServer.h"
0015 #include "KoResourceServerProvider.h"
0016 #include <KoColorSpaceRegistry.h>
0017 #include <KoColor.h>
0018 
0019 #include <WidgetsDebug.h>
0020 #include <klocalizedstring.h>
0021 
0022 #include <QPainter>
0023 #include <QWidgetAction>
0024 #include <QMenu>
0025 #include <QHBoxLayout>
0026 #include <QGridLayout>
0027 #include <QToolButton>
0028 
0029 class KoColorPopupAction::KoColorPopupActionPrivate
0030 {
0031 public:
0032     KoColorPopupActionPrivate()
0033         : colorSetWidget(0)
0034         , colorChooser(0)
0035         , opacitySlider(0)
0036         , menu(0)
0037         , checkerPainter(4)
0038         , showFilter(true)
0039         , applyMode(true)
0040         , firstTime(true)
0041     {}
0042 
0043     ~KoColorPopupActionPrivate()
0044     {
0045         delete menu;
0046     }
0047 
0048     KoColor currentColor;
0049     KoColor buddyColor;
0050 
0051     KoColorSetWidget *colorSetWidget;
0052     KoTriangleColorSelector * colorChooser;
0053     KoColorSlider * opacitySlider;
0054     QMenu *menu;
0055     KoCheckerBoardPainter checkerPainter;
0056     bool showFilter;
0057     bool applyMode;
0058 
0059     bool firstTime;
0060 };
0061 
0062 KoColorPopupAction::KoColorPopupAction(QObject *parent)
0063     : QAction(parent),
0064     d(new KoColorPopupActionPrivate())
0065 {
0066     d->menu = new QMenu();
0067     QWidget *widget = new QWidget(d->menu);
0068     QWidgetAction *wdgAction = new QWidgetAction(d->menu);
0069     d->colorSetWidget = new KoColorSetWidget(widget);
0070     KoResourceServer<KoColorSet>* rServer = KoResourceServerProvider::instance()->paletteServer();
0071 
0072     KoColorSetSP defaultColorSet = rServer->resource("", "", "Default");
0073     if (!defaultColorSet && rServer->resourceCount() > 0) {
0074         defaultColorSet = rServer->firstResource();
0075     }
0076     d->colorSetWidget->setColorSet(defaultColorSet);
0077 
0078     d->colorChooser = new KoTriangleColorSelector( widget );
0079     // prevent mouse release on color selector from closing popup
0080     d->colorChooser->setAttribute( Qt::WA_NoMousePropagation );
0081     d->opacitySlider = new KoColorSlider( Qt::Vertical, widget );
0082     d->opacitySlider->setFixedWidth(25);
0083     d->opacitySlider->setRange(0, 255);
0084     d->opacitySlider->setValue(255);
0085     d->opacitySlider->setToolTip( i18n( "Opacity" ) );
0086 
0087     QGridLayout * layout = new QGridLayout( widget );
0088     layout->addWidget( d->colorSetWidget, 0, 0, 1, -1 );
0089     layout->addWidget( d->colorChooser, 1, 0 );
0090     layout->addWidget( d->opacitySlider, 1, 1 );
0091     layout->setMargin(4);
0092 
0093     wdgAction->setDefaultWidget(widget);
0094     d->menu->addAction(wdgAction);
0095     setMenu(d->menu);
0096     new QHBoxLayout(d->menu);
0097     d->menu->layout()->addWidget(widget);
0098     d->menu->layout()->setMargin(0);
0099 
0100     connect(this, SIGNAL(triggered()), this, SLOT(emitColorChanged()));
0101 
0102     connect(d->colorSetWidget, SIGNAL(colorChanged(KoColor,bool)),
0103             this, SLOT(colorWasSelected(KoColor,bool)));
0104     connect(d->colorChooser, SIGNAL(colorChanged(QColor)),
0105             this, SLOT(colorWasEdited(QColor)));
0106     connect(d->opacitySlider, SIGNAL(valueChanged(int)),
0107             this, SLOT(opacityWasChanged(int)));
0108 }
0109 
0110 KoColorPopupAction::~KoColorPopupAction()
0111 {
0112     delete d;
0113 }
0114 
0115 void KoColorPopupAction::setCurrentColor( const KoColor &color )
0116 {
0117     KoColor minColor( color );
0118     d->currentColor = minColor;
0119 
0120     d->colorChooser->blockSignals(true);
0121     d->colorChooser->slotSetColor(color);
0122     d->colorChooser->blockSignals(false);
0123 
0124     KoColor maxColor( color );
0125     minColor.setOpacity( OPACITY_TRANSPARENT_U8 );
0126     maxColor.setOpacity( OPACITY_OPAQUE_U8 );
0127 
0128     d->opacitySlider->blockSignals( true );
0129     d->opacitySlider->setColors( minColor, maxColor );
0130     d->opacitySlider->setValue( color.opacityU8() );
0131     d->opacitySlider->blockSignals( false );
0132 
0133     updateIcon();
0134 }
0135 
0136 void KoColorPopupAction::setCurrentColor( const QColor &_color )
0137 {
0138 #ifndef NDEBUG
0139     if (!_color.isValid()) {
0140         warnWidgets << "Invalid color given, defaulting to black";
0141     }
0142 #endif
0143     const QColor color(_color.isValid() ? _color : QColor(0,0,0,255));
0144     setCurrentColor(KoColor(color, KoColorSpaceRegistry::instance()->rgb8() ));
0145 }
0146 
0147 QColor KoColorPopupAction::currentColor() const
0148 {
0149     return d->currentColor.toQColor();
0150 }
0151 
0152 KoColor KoColorPopupAction::currentKoColor() const
0153 {
0154     return d->currentColor;
0155 }
0156 
0157 void KoColorPopupAction::updateIcon()
0158 {
0159     QSize iconSize;
0160     QToolButton *toolButton = dynamic_cast<QToolButton*>(parentWidget());
0161     if (toolButton) {
0162         iconSize = QSize(toolButton->iconSize());
0163     } else {
0164         iconSize = QSize(16, 16);
0165     }
0166 
0167     // This must be a QImage, as drawing to a QPixmap outside the
0168     // UI thread will cause sporadic crashes.
0169     QImage pm;
0170 
0171     if (icon().isNull()) {
0172         d->applyMode = false;
0173     }
0174 
0175     if(d->applyMode) {
0176         pm = icon().pixmap(iconSize).toImage();
0177         if (pm.isNull()) {
0178             pm = QImage(iconSize, QImage::Format_ARGB32_Premultiplied);
0179             pm.fill(Qt::transparent);
0180         }
0181         QPainter p(&pm);
0182         p.fillRect(0, iconSize.height() - 4, iconSize.width(), 4, d->currentColor.toQColor());
0183         p.end();
0184     } else {
0185         pm = QImage(iconSize, QImage::Format_ARGB32_Premultiplied);
0186         pm.fill(Qt::transparent);
0187         QPainter p(&pm);
0188         d->checkerPainter.paint(p, QRect(QPoint(),iconSize));
0189         p.fillRect(0, 0, iconSize.width(), iconSize.height(), d->currentColor.toQColor());
0190         p.end();
0191     }
0192     setIcon(QIcon(QPixmap::fromImage(pm)));
0193 }
0194 
0195 void KoColorPopupAction::emitColorChanged()
0196 {
0197     emit colorChanged( d->currentColor );
0198 }
0199 
0200 void KoColorPopupAction::colorWasSelected(const KoColor &color, bool final)
0201 {
0202     d->currentColor = color;
0203     if (final) {
0204         menu()->hide();
0205         emitColorChanged();
0206     }
0207     updateIcon();
0208 }
0209 
0210 void KoColorPopupAction::colorWasEdited( const QColor &color )
0211 {
0212     d->currentColor = KoColor( color, KoColorSpaceRegistry::instance()->rgb8() );
0213     quint8 opacity = d->opacitySlider->value();
0214     d->currentColor.setOpacity( opacity );
0215 
0216     KoColor minColor = d->currentColor;
0217     minColor.setOpacity( OPACITY_TRANSPARENT_U8 );
0218     KoColor maxColor = minColor;
0219     maxColor.setOpacity( OPACITY_OPAQUE_U8 );
0220 
0221     d->opacitySlider->setColors( minColor, maxColor );
0222 
0223     emitColorChanged();
0224 
0225     updateIcon();
0226 }
0227 
0228 void KoColorPopupAction::opacityWasChanged( int opacity )
0229 {
0230     d->currentColor.setOpacity( quint8(opacity) );
0231 
0232     emitColorChanged();
0233 }