diff --git a/plugins/paintops/libpaintop/kis_brush_chooser.cpp b/plugins/paintops/libpaintop/kis_brush_chooser.cpp index a391a0441f..1382e84c86 100644 --- a/plugins/paintops/libpaintop/kis_brush_chooser.cpp +++ b/plugins/paintops/libpaintop/kis_brush_chooser.cpp @@ -1,417 +1,419 @@ /* * Copyright (c) 2004 Adrian Page * Copyright (c) 2009 Sven Langkamp * Copyright (c) 2010 Cyrille Berger * Copyright (c) 2010 Lukáš Tvrdý * Copyright (C) 2011 Srikanth Tiyyagura * * 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; either version 2 of the License, or * (at your option) any later version. * * 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. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include "kis_brush_chooser.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "kis_brush_server.h" #include "widgets/kis_slider_spin_box.h" #include "widgets/kis_multipliers_double_slider_spinbox.h" #include "kis_spacing_selection_widget.h" #include "kis_signals_blocker.h" #include "kis_imagepipe_brush.h" #include "kis_custom_brush_widget.h" #include "kis_clipboard_brush_widget.h" #include #include "kis_global.h" #include "kis_gbr_brush.h" #include "kis_debug.h" #include "kis_image.h" /// The resource item delegate for rendering the resource preview class KisBrushDelegate : public QAbstractItemDelegate { public: KisBrushDelegate(QObject * parent = 0) : QAbstractItemDelegate(parent) {} ~KisBrushDelegate() override {} /// reimplemented void paint(QPainter *, const QStyleOptionViewItem &, const QModelIndex &) const override; /// reimplemented QSize sizeHint(const QStyleOptionViewItem & option, const QModelIndex &) const override { return option.decorationSize; } }; void KisBrushDelegate::paint(QPainter * painter, const QStyleOptionViewItem & option, const QModelIndex & index) const { if (! index.isValid()) return; KisBrush *brush = static_cast(index.internalPointer()); QRect itemRect = option.rect; QImage thumbnail = brush->image(); if (thumbnail.height() > itemRect.height() || thumbnail.width() > itemRect.width()) { thumbnail = thumbnail.scaled(itemRect.size() , Qt::KeepAspectRatio, Qt::SmoothTransformation); } painter->save(); int dx = (itemRect.width() - thumbnail.width()) / 2; int dy = (itemRect.height() - thumbnail.height()) / 2; painter->drawImage(itemRect.x() + dx, itemRect.y() + dy, thumbnail); if (option.state & QStyle::State_Selected) { painter->setPen(QPen(option.palette.highlight(), 2.0)); painter->drawRect(option.rect); painter->setCompositionMode(QPainter::CompositionMode_HardLight); painter->setOpacity(0.65); painter->fillRect(option.rect, option.palette.highlight()); } painter->restore(); } KisPredefinedBrushChooser::KisPredefinedBrushChooser(QWidget *parent, const char *name) : QWidget(parent), m_stampBrushWidget(0), m_clipboardBrushWidget(0) { setObjectName(name); setupUi(this); brushSizeSpinBox->setRange(0, KSharedConfig::openConfig()->group("").readEntry("maximumBrushSize", 1000), 2); brushSizeSpinBox->setValue(5); brushSizeSpinBox->setExponentRatio(3.0); brushSizeSpinBox->setSuffix(i18n(" px")); brushSizeSpinBox->setExponentRatio(3.0); QObject::connect(brushSizeSpinBox, SIGNAL(valueChanged(qreal)), this, SLOT(slotSetItemSize(qreal))); brushRotationSpinBox->setRange(0, 360, 0); brushRotationSpinBox->setValue(0); brushRotationSpinBox->setSuffix(QChar(Qt::Key_degree)); QObject::connect(brushRotationSpinBox, SIGNAL(valueChanged(qreal)), this, SLOT(slotSetItemRotation(qreal))); brushSpacingSelectionWidget->setSpacing(true, 1.0); connect(brushSpacingSelectionWidget, SIGNAL(sigSpacingChanged()), SLOT(slotSpacingChanged())); QObject::connect(useColorAsMaskCheckbox, SIGNAL(toggled(bool)), this, SLOT(slotSetItemUseColorAsMask(bool))); KisBrushResourceServer* rServer = KisBrushServer::instance()->brushServer(); QSharedPointer adapter(new KisBrushResourceServerAdapter(rServer)); m_itemChooser = new KoResourceItemChooser(adapter, this); m_itemChooser->setObjectName("brush_selector"); m_itemChooser->showTaggingBar(true); m_itemChooser->setColumnCount(10); m_itemChooser->setRowHeight(30); m_itemChooser->setItemDelegate(new KisBrushDelegate(this)); m_itemChooser->setCurrentItem(0, 0); m_itemChooser->setSynced(true); m_itemChooser->setMinimumWidth(100); m_itemChooser->setMinimumHeight(150); m_itemChooser->showButtons(false); // turn the import and delete buttons since we want control over them addPresetButton->setIcon(KisIconUtils::loadIcon("list-add")); deleteBrushTipButton->setIcon(KisIconUtils::loadIcon("trash-empty")); connect(addPresetButton, SIGNAL(clicked(bool)), this, SLOT(slotImportNewBrushResource())); connect(deleteBrushTipButton, SIGNAL(clicked(bool)), this, SLOT(slotDeleteBrushResource())); presetsLayout->addWidget(m_itemChooser); connect(m_itemChooser, SIGNAL(resourceSelected(KoResource*)), this, SLOT(updateBrushTip(KoResource*))); stampButton->setIcon(KisIconUtils::loadIcon("list-add")); stampButton->setToolTip(i18n("Creates a brush tip from the current image selection." "\n If no selection is present the whole image will be used.")); clipboardButton->setIcon(KisIconUtils::loadIcon("list-add")); clipboardButton->setToolTip(i18n("Creates a brush tip from the image in the clipboard.")); connect(stampButton, SIGNAL(clicked()), this, SLOT(slotOpenStampBrush())); connect(clipboardButton, SIGNAL(clicked()), SLOT(slotOpenClipboardBrush())); QGridLayout *spacingLayout = new QGridLayout(); spacingLayout->setObjectName("spacing grid layout"); resetBrushButton->setToolTip(i18n("Reloads Spacing from file\nSets Scale to 1.0\nSets Rotation to 0.0")); connect(resetBrushButton, SIGNAL(clicked()), SLOT(slotResetBrush())); updateBrushTip(m_itemChooser->currentResource()); } KisPredefinedBrushChooser::~KisPredefinedBrushChooser() { } void KisPredefinedBrushChooser::setBrush(KisBrushSP brush) { /** * Warning: since the brushes are always cloned after loading from XML or * fetching from the server, we cannot just ask for that brush explicitly. * Instead, we should search for the brush with the same filename and/or name * and load it. Please take it into account that after selecting the brush * explicitly in the chooser, m_itemChooser->currentResource() might be * **not** the same as the value in m_brush. * * Ideally, if the resource is not found on the server, we should add it, but * it might lead to a set of weird consequences. So for now we just * select nothing. */ KisBrushResourceServer* server = KisBrushServer::instance()->brushServer(); KoResource *resource = server->resourceByFilename(brush->shortFilename()).data(); if (!resource) { resource = server->resourceByName(brush->name()).data(); } if (!resource) { resource = brush.data(); } m_itemChooser->setCurrentResource(resource); updateBrushTip(brush.data(), true); } void KisPredefinedBrushChooser::slotResetBrush() { /** * The slot also resets the brush on the server * * TODO: technically, after we refactored all the brushes to be forked, * we can just re-update the brush from the server without reloading. * But it needs testing. */ KisBrush *brush = dynamic_cast(m_itemChooser->currentResource()); if (brush) { brush->load(); brush->setScale(1.0); brush->setAngle(0.0); updateBrushTip(brush); emit sigBrushChanged(); } } void KisPredefinedBrushChooser::slotSetItemSize(qreal sizeValue) { KIS_SAFE_ASSERT_RECOVER_RETURN(m_brush); if (m_brush) { int brushWidth = m_brush->width(); m_brush->setScale(sizeValue / qreal(brushWidth)); emit sigBrushChanged(); } } void KisPredefinedBrushChooser::slotSetItemRotation(qreal rotationValue) { KIS_SAFE_ASSERT_RECOVER_RETURN(m_brush); if (m_brush) { m_brush->setAngle(rotationValue / 180.0 * M_PI); emit sigBrushChanged(); } } void KisPredefinedBrushChooser::slotSpacingChanged() { KIS_SAFE_ASSERT_RECOVER_RETURN(m_brush); if (m_brush) { m_brush->setSpacing(brushSpacingSelectionWidget->spacing()); m_brush->setAutoSpacing(brushSpacingSelectionWidget->autoSpacingActive(), brushSpacingSelectionWidget->autoSpacingCoeff()); emit sigBrushChanged(); } } void KisPredefinedBrushChooser::slotSetItemUseColorAsMask(bool useColorAsMask) { KIS_SAFE_ASSERT_RECOVER_RETURN(m_brush); KisGbrBrush *brush = dynamic_cast(m_brush.data()); if (brush) { brush->setUseColorAsMask(useColorAsMask); emit sigBrushChanged(); } } void KisPredefinedBrushChooser::slotOpenStampBrush() { if(!m_stampBrushWidget) { m_stampBrushWidget = new KisCustomBrushWidget(this, i18n("Stamp"), m_image); m_stampBrushWidget->setModal(false); connect(m_stampBrushWidget, SIGNAL(sigNewPredefinedBrush(KoResource*)), SLOT(slotNewPredefinedBrush(KoResource*))); + } else { + m_stampBrushWidget->setImage(m_image); } QDialog::DialogCode result = (QDialog::DialogCode)m_stampBrushWidget->exec(); if(result) { updateBrushTip(m_itemChooser->currentResource()); } } void KisPredefinedBrushChooser::slotOpenClipboardBrush() { if(!m_clipboardBrushWidget) { m_clipboardBrushWidget = new KisClipboardBrushWidget(this, i18n("Clipboard"), m_image); m_clipboardBrushWidget->setModal(true); connect(m_clipboardBrushWidget, SIGNAL(sigNewPredefinedBrush(KoResource*)), SLOT(slotNewPredefinedBrush(KoResource*))); } QDialog::DialogCode result = (QDialog::DialogCode)m_clipboardBrushWidget->exec(); if(result) { updateBrushTip(m_itemChooser->currentResource()); } } void KisPredefinedBrushChooser::updateBrushTip(KoResource * resource, bool isChangingBrushPresets) { QString animatedBrushTipSelectionMode; // incremental, random, etc { KisBrush* brush = dynamic_cast(resource); m_brush = brush ? brush->clone() : 0; } if (m_brush) { brushTipNameLabel->setText(i18n(m_brush->name().toUtf8().data())); QString brushTypeString = ""; if (m_brush->brushType() == INVALID) { brushTypeString = i18n("Invalid"); } else if (m_brush->brushType() == MASK) { brushTypeString = i18n("Mask"); } else if (m_brush->brushType() == IMAGE) { brushTypeString = i18n("GBR"); } else if (m_brush->brushType() == PIPE_MASK ) { brushTypeString = i18n("Animated Mask"); // GIH brush // cast to GIH brush and grab parasite name //m_brush KisImagePipeBrush* pipeBrush = dynamic_cast(resource); animatedBrushTipSelectionMode = pipeBrush->parasiteSelection(); } else if (m_brush->brushType() == PIPE_IMAGE ) { brushTypeString = i18n("Animated Image"); } QString brushDetailsText = QString("%1 (%2 x %3) %4") .arg(brushTypeString) .arg(m_brush->width()) .arg(m_brush->height()) .arg(animatedBrushTipSelectionMode); brushDetailsLabel->setText(brushDetailsText); // keep the current preset's tip settings if we are preserving it // this will set the brush's model data to keep what it currently has for size, spacing, etc. if (preserveBrushPresetSettings->isChecked() && !isChangingBrushPresets) { m_brush->setAutoSpacing(brushSpacingSelectionWidget->autoSpacingActive(), brushSpacingSelectionWidget->autoSpacingCoeff()); m_brush->setAngle(brushRotationSpinBox->value() * M_PI / 180); m_brush->setSpacing(brushSpacingSelectionWidget->spacing()); m_brush->setUserEffectiveSize(brushSizeSpinBox->value()); } brushSpacingSelectionWidget->setSpacing(m_brush->autoSpacingActive(), m_brush->autoSpacingActive() ? m_brush->autoSpacingCoeff() : m_brush->spacing()); brushRotationSpinBox->setValue(m_brush->angle() * 180 / M_PI); brushSizeSpinBox->setValue(m_brush->width() * m_brush->scale()); // useColorAsMask support is only in gimp brush so far KisGbrBrush *gimpBrush = dynamic_cast(m_brush.data()); if (gimpBrush) { useColorAsMaskCheckbox->setChecked(gimpBrush->useColorAsMask()); } useColorAsMaskCheckbox->setEnabled(m_brush->hasColor() && gimpBrush); emit sigBrushChanged(); } } void KisPredefinedBrushChooser::slotNewPredefinedBrush(KoResource *resource) { m_itemChooser->setCurrentResource(resource); updateBrushTip(resource); } void KisPredefinedBrushChooser::setBrushSize(qreal xPixels, qreal yPixels) { Q_UNUSED(yPixels); qreal oldWidth = m_brush->width() * m_brush->scale(); qreal newWidth = oldWidth + xPixels; newWidth = qMax(newWidth, qreal(0.1)); brushSizeSpinBox->setValue(newWidth); } void KisPredefinedBrushChooser::setImage(KisImageWSP image) { m_image = image; } void KisPredefinedBrushChooser::slotImportNewBrushResource() { m_itemChooser->slotButtonClicked(KoResourceItemChooser::Button_Import); } void KisPredefinedBrushChooser::slotDeleteBrushResource() { m_itemChooser->slotButtonClicked(KoResourceItemChooser::Button_Remove); } #include "moc_kis_brush_chooser.cpp" diff --git a/plugins/paintops/libpaintop/kis_custom_brush_widget.cpp b/plugins/paintops/libpaintop/kis_custom_brush_widget.cpp index 630064e59d..4617f04824 100644 --- a/plugins/paintops/libpaintop/kis_custom_brush_widget.cpp +++ b/plugins/paintops/libpaintop/kis_custom_brush_widget.cpp @@ -1,261 +1,267 @@ /* * Copyright (c) 2005 Bart Coppens * Copyright (c) 2010 Lukáš Tvrdý * * 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; either version 2 of the License, or * (at your option) any later version. * * 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. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include "kis_custom_brush_widget.h" #include #include #include #include #include #include #include #include #include #include #include "kis_image.h" #include "kis_layer.h" #include "kis_paint_device.h" #include "kis_gbr_brush.h" #include "kis_imagepipe_brush.h" #include #include "kis_brush_server.h" #include "kis_paint_layer.h" #include "kis_group_layer.h" #include #include #include "kis_iterator_ng.h" KisCustomBrushWidget::KisCustomBrushWidget(QWidget *parent, const QString& caption, KisImageWSP image) : KisWdgCustomBrush(parent) , m_image(image) { setWindowTitle(caption); preview->setScaledContents(false); preview->setFixedSize(preview->size()); preview->setStyleSheet("border: 2px solid #222; border-radius: 4px; padding: 5px; font: normal 10px;"); KisBrushResourceServer* rServer = KisBrushServer::instance()->brushServer(); m_rServerAdapter = QSharedPointer(new KisBrushResourceServerAdapter(rServer)); m_brush = 0; connect(this, SIGNAL(accepted()), SLOT(slotAddPredefined())); connect(brushStyle, SIGNAL(activated(int)), this, SLOT(slotUpdateCurrentBrush(int))); connect(colorAsMask, SIGNAL(toggled(bool)), this, SLOT(slotUpdateUseColorAsMask(bool))); connect(comboBox2, SIGNAL(currentIndexChanged(int)), this, SLOT(slotUpdateCurrentBrush(int))); colorAsMask->setChecked(true); // use color as mask by default. This is by far the most common way to make tip. spacingWidget->setSpacing(true, 1.0); connect(spacingWidget, SIGNAL(sigSpacingChanged()), SLOT(slotSpacingChanged())); } KisCustomBrushWidget::~KisCustomBrushWidget() { } KisBrushSP KisCustomBrushWidget::brush() { return m_brush; } +void KisCustomBrushWidget::setImage(KisImageWSP image){ + m_image = image; + createBrush(); + updatePreviewImage(); +} + void KisCustomBrushWidget::showEvent(QShowEvent *) { slotUpdateCurrentBrush(0); } void KisCustomBrushWidget::updatePreviewImage() { QImage brushImage = m_brush ? m_brush->brushTipImage() : QImage(); if (!brushImage.isNull()) { brushImage = brushImage.scaled(preview->size(), Qt::KeepAspectRatio); } preview->setPixmap(QPixmap::fromImage(brushImage)); } void KisCustomBrushWidget::slotUpdateCurrentBrush(int) { if (brushStyle->currentIndex() == 0) { comboBox2->setEnabled(false); } else { comboBox2->setEnabled(true); } if (m_image) { createBrush(); updatePreviewImage(); } } void KisCustomBrushWidget::slotSpacingChanged() { if (m_brush) { m_brush->setSpacing(spacingWidget->spacing()); m_brush->setAutoSpacing(spacingWidget->autoSpacingActive(), spacingWidget->autoSpacingCoeff()); } } void KisCustomBrushWidget::slotUpdateUseColorAsMask(bool useColorAsMask) { if (m_brush) { static_cast(m_brush.data())->setUseColorAsMask(useColorAsMask); updatePreviewImage(); } } void KisCustomBrushWidget::slotAddPredefined() { QString dir = KoResourcePaths::saveLocation("data", "brushes"); QString extension; if (brushStyle->currentIndex() == 0) { extension = ".gbr"; } else { extension = ".gih"; } QString name = nameLineEdit->text(); QString tempFileName; { QFileInfo fileInfo; fileInfo.setFile(dir + name + extension); int i = 1; while (fileInfo.exists()) { fileInfo.setFile(dir + name + QString("%1").arg(i) + extension); i++; } tempFileName = fileInfo.filePath(); } // Add it to the brush server, so that it automatically gets to the mediators, and // so to the other brush choosers can pick it up, if they want to if (m_rServerAdapter && m_brush) { qDebug() << "m_brush" << m_brush; KisGbrBrush *resource = dynamic_cast(m_brush->clone()); resource->setFilename(tempFileName); if (nameLineEdit->text().isEmpty()) { resource->setName(QDateTime::currentDateTime().toString("yyyy-MM-ddThh:mm")); } else { resource->setName(name); } if (colorAsMask->isChecked()) { resource->makeMaskImage(); } m_rServerAdapter->addResource(resource); emit sigNewPredefinedBrush(resource); } close(); } void KisCustomBrushWidget::createBrush() { if (!m_image) return; if (brushStyle->currentIndex() == 0) { KisSelectionSP selection = m_image->globalSelection(); // create copy of the data m_image->lock(); KisPaintDeviceSP dev = new KisPaintDevice(*m_image->projection()); m_image->unlock(); if (!selection) { m_brush = new KisGbrBrush(dev, 0, 0, m_image->width(), m_image->height()); } else { // apply selection mask QRect r = selection->selectedExactRect(); dev->crop(r); KisHLineIteratorSP pixelIt = dev->createHLineIteratorNG(r.x(), r.top(), r.width()); KisHLineConstIteratorSP maskIt = selection->projection()->createHLineIteratorNG(r.x(), r.top(), r.width()); for (qint32 y = r.top(); y <= r.bottom(); ++y) { do { dev->colorSpace()->applyAlphaU8Mask(pixelIt->rawData(), maskIt->oldRawData(), 1); } while (pixelIt->nextPixel() && maskIt->nextPixel()); pixelIt->nextRow(); maskIt->nextRow(); } QRect rc = dev->exactBounds(); m_brush = new KisGbrBrush(dev, rc.x(), rc.y(), rc.width(), rc.height()); } } else { // For each layer in the current image, create a new image, and add it to the list QVector< QVector > devices; devices.push_back(QVector()); int w = m_image->width(); int h = m_image->height(); m_image->lock(); // We only loop over the rootLayer. Since we actually should have a layer selection // list, no need to elaborate on that here and now KoProperties properties; properties.setProperty("visible", true); QList layers = m_image->root()->childNodes(QStringList("KisLayer"), properties); KisNodeSP node; Q_FOREACH (KisNodeSP node, layers) { devices[0].push_back(node->projection().data()); } QVector modes; switch (comboBox2->currentIndex()) { case 0: modes.push_back(KisParasite::Constant); break; case 1: modes.push_back(KisParasite::Random); break; case 2: modes.push_back(KisParasite::Incremental); break; case 3: modes.push_back(KisParasite::Pressure); break; case 4: modes.push_back(KisParasite::Angular); break; default: modes.push_back(KisParasite::Incremental); } m_brush = new KisImagePipeBrush(m_image->objectName(), w, h, devices, modes); m_image->unlock(); } static_cast(m_brush.data())->setUseColorAsMask(colorAsMask->isChecked()); m_brush->setSpacing(spacingWidget->spacing()); m_brush->setAutoSpacing(spacingWidget->autoSpacingActive(), spacingWidget->autoSpacingCoeff()); m_brush->setFilename(TEMPORARY_FILENAME); m_brush->setName(TEMPORARY_BRUSH_NAME); m_brush->setValid(true); } diff --git a/plugins/paintops/libpaintop/kis_custom_brush_widget.h b/plugins/paintops/libpaintop/kis_custom_brush_widget.h index b4deb71bc8..ffeebf0207 100644 --- a/plugins/paintops/libpaintop/kis_custom_brush_widget.h +++ b/plugins/paintops/libpaintop/kis_custom_brush_widget.h @@ -1,79 +1,81 @@ /* * Copyright (c) 2005 Bart Coppens * * 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; either version 2 of the License, or * (at your option) any later version. * * 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. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #ifndef KIS_CUSTOM_BRUSH_H_ #define KIS_CUSTOM_BRUSH_H_ #include #include #include #include "ui_wdgcustombrush.h" #include #include const QString TEMPORARY_FILENAME = "/tmp/temporaryKritaBrush.gbr"; const QString TEMPORARY_BRUSH_NAME = "Temporary custom brush"; const double DEFAULT_SPACING = 0.25; class KoResource; class KisWdgCustomBrush : public QDialog, public Ui::KisWdgCustomBrush { Q_OBJECT public: KisWdgCustomBrush(QWidget *parent) : QDialog(parent) { setupUi(this); } }; class KisCustomBrushWidget : public KisWdgCustomBrush { Q_OBJECT public: KisCustomBrushWidget(QWidget *parent, const QString& caption, KisImageWSP image); virtual ~KisCustomBrushWidget(); KisBrushSP brush(); + void setImage(KisImageWSP image); + protected: virtual void showEvent(QShowEvent *); private Q_SLOTS: void slotAddPredefined(); void slotUpdateCurrentBrush(int i = 0); // To connect with activated(int) void slotSpacingChanged(); void slotUpdateUseColorAsMask(bool useColorAsMask); Q_SIGNALS: void sigNewPredefinedBrush(KoResource *); private: void createBrush(); void updatePreviewImage(); KisImageWSP m_image; KisBrushSP m_brush; QSharedPointer m_rServerAdapter; }; #endif // KIS_CUSTOM_BRUSH_H_