File indexing completed on 2024-05-12 16:01:38

0001 /*
0002  *  kis_paintop_box.cc - part of KImageShop/Krayon/Krita
0003  *
0004  *  SPDX-FileCopyrightText: 2004 Boudewijn Rempt (boud@valdyas.org)
0005  *  SPDX-FileCopyrightText: 2009-2011 Sven Langkamp (sven.langkamp@gmail.com)
0006  *  SPDX-FileCopyrightText: 2010 Lukáš Tvrdý <lukast.dev@gmail.com>
0007  *  SPDX-FileCopyrightText: 2011 Silvio Heinrich <plassy@web.de>
0008  *  SPDX-FileCopyrightText: 2011 Srikanth Tiyyagura <srikanth.tulasiram@gmail.com>
0009  *  SPDX-FileCopyrightText: 2014 Mohit Goyal <mohit.bits2011@gmail.com>
0010  *
0011  *  SPDX-License-Identifier: GPL-2.0-or-later
0012  */
0013 
0014 #include "kis_paintop_box.h"
0015 
0016 #include <QHBoxLayout>
0017 #include <QLabel>
0018 #include <QToolButton>
0019 #include <QPixmap>
0020 #include <QWidgetAction>
0021 #include <QApplication>
0022 #include <QMenu>
0023 #include <QTime>
0024 
0025 #include <kis_debug.h>
0026 #include <kis_types.h>
0027 
0028 #include <kactioncollection.h>
0029 #include <kacceleratormanager.h>
0030 #include <QKeySequence>
0031 
0032 #include <kis_icon.h>
0033 #include <KoColorSpace.h>
0034 #include <KoCompositeOpRegistry.h>
0035 #include <KoToolManager.h>
0036 #include <KoColorSpaceRegistry.h>
0037 
0038 #include <KoResource.h>
0039 #include <KisDirtyStateSaver.h>
0040 
0041 #include <kis_paint_device.h>
0042 #include <brushengine/kis_paintop_registry.h>
0043 #include <brushengine/kis_paintop_preset.h>
0044 #include <brushengine/kis_paintop_settings.h>
0045 #include <brushengine/KisPaintOpPresetUpdateProxy.h>
0046 #include <kis_config_widget.h>
0047 #include <kis_image.h>
0048 #include <kis_node.h>
0049 #include <brushengine/kis_paintop_config_widget.h>
0050 #include <kis_action.h>
0051 
0052 #include "kis_canvas2.h"
0053 #include "kis_node_manager.h"
0054 #include "KisViewManager.h"
0055 #include "kis_canvas_resource_provider.h"
0056 #include "KisResourceServerProvider.h"
0057 #include "kis_favorite_resource_manager.h"
0058 #include "kis_config.h"
0059 #include "kis_image_config.h"
0060 
0061 #include "KisPopupButton.h"
0062 #include "widgets/kis_iconwidget.h"
0063 #include "widgets/kis_tool_options_popup.h"
0064 #include "widgets/kis_paintop_presets_editor.h"
0065 #include "widgets/kis_paintop_presets_chooser_popup.h"
0066 #include "widgets/kis_workspace_chooser.h"
0067 #include "widgets/kis_paintop_list_widget.h"
0068 #include "kis_slider_spin_box.h"
0069 #include "widgets/kis_multipliers_double_slider_spinbox.h"
0070 #include "widgets/kis_cmb_composite.h"
0071 #include "widgets/kis_widget_chooser.h"
0072 #include "tool/kis_tool.h"
0073 #include "kis_signals_blocker.h"
0074 #include "kis_action_manager.h"
0075 #include "KisHighlightedToolButton.h"
0076 #include <KisGlobalResourcesInterface.h>
0077 #include "KisResourceLoader.h"
0078 #include "KisResourceLoaderRegistry.h"
0079 #include "kis_acyclic_signal_connector.h"
0080 #include "KisMainWindow.h"
0081 
0082 
0083 KisPaintopBox::KisPaintopBox(KisViewManager *viewManager, QWidget *parent, const char *name)
0084     : QWidget(parent)
0085     , m_resourceProvider(viewManager->canvasResourceProvider())
0086     , m_viewManager(viewManager)
0087     , m_optionWidgetUpdateCompressor(100, KisSignalCompressor::FIRST_ACTIVE)
0088 {
0089     Q_ASSERT(viewManager != 0);
0090 
0091     setObjectName(name);
0092     KisConfig cfg(true);
0093     m_dirtyPresetsEnabled = cfg.useDirtyPresets();
0094     m_eraserBrushSizeEnabled = cfg.useEraserBrushSize();
0095     m_eraserBrushOpacityEnabled = cfg.useEraserBrushOpacity();
0096 
0097     KAcceleratorManager::setNoAccel(this);
0098 
0099     setWindowTitle(i18n("Painter's Toolchest"));
0100 
0101     m_favoriteResourceManager = new KisFavoriteResourceManager(this);
0102 
0103     KConfigGroup grp =  KSharedConfig::openConfig()->group("krita").group("Toolbar BrushesAndStuff");
0104     int iconsize = grp.readEntry("IconSize", 22);
0105     // NOTE: buttonsize should be the same value as the one used in ktoolbar for all QToolButton
0106     int buttonsize = grp.readEntry("ButtonSize", 32);
0107 
0108     if (!cfg.toolOptionsInDocker()) {
0109         m_toolOptionsPopupButton = new KisPopupButton(this);
0110         m_toolOptionsPopupButton->setIcon(KisIconUtils::loadIcon("view-choose"));
0111         m_toolOptionsPopupButton->setToolTip(i18n("Tool Settings"));
0112         m_toolOptionsPopupButton->setFixedSize(buttonsize, buttonsize);
0113         m_toolOptionsPopupButton->setIconSize(QSize(iconsize, iconsize));
0114         m_toolOptionsPopupButton->setAutoRaise(true);
0115     }
0116 
0117     m_brushEditorPopupButton = new KisIconWidget(this);
0118     m_brushEditorPopupButton->setIcon(KisIconUtils::loadIcon("paintop_settings_02"));
0119     m_brushEditorPopupButton->setToolTip(i18n("Edit brush settings"));
0120     m_brushEditorPopupButton->setFixedSize(buttonsize, buttonsize);
0121     m_brushEditorPopupButton->setIconSize(QSize(iconsize, iconsize));
0122     m_brushEditorPopupButton->setAutoRaise(true);
0123 
0124     m_presetSelectorPopupButton = new KisIconWidget(this);
0125     m_presetSelectorPopupButton->setIcon(KisIconUtils::loadIcon("paintop_settings_01"));
0126     m_presetSelectorPopupButton->setToolTip(i18n("Choose brush preset"));
0127     m_presetSelectorPopupButton->setFixedSize(buttonsize, buttonsize);
0128     m_presetSelectorPopupButton->setIconSize(QSize(iconsize, iconsize));
0129     m_presetSelectorPopupButton->setAutoRaise(true);
0130     m_presetSelectorPopupButton->setArrowVisible(false);
0131 
0132     m_eraseModeButton = new KisHighlightedToolButton(this);
0133     m_eraseModeButton->setFixedSize(buttonsize, buttonsize);
0134     m_eraseModeButton->setIconSize(QSize(iconsize, iconsize));
0135     m_eraseModeButton->setCheckable(true);
0136     m_eraseModeButton->setAutoRaise(true);
0137 
0138 
0139     m_eraseAction = m_viewManager->actionManager()->createAction("erase_action");
0140     m_eraseModeButton->setDefaultAction(m_eraseAction);
0141 
0142     m_reloadButton = new QToolButton(this);
0143     m_reloadButton->setFixedSize(buttonsize, buttonsize);
0144     m_reloadButton->setIconSize(QSize(iconsize, iconsize));
0145     m_reloadButton->setAutoRaise(true); // make button flat
0146 
0147 
0148     m_reloadAction = m_viewManager->actionManager()->createAction("reload_preset_action");
0149     m_reloadButton->setDefaultAction(m_reloadAction);
0150 
0151     m_alphaLockButton = new KisHighlightedToolButton(this);
0152     m_alphaLockButton->setFixedSize(buttonsize, buttonsize);
0153     m_alphaLockButton->setIconSize(QSize(iconsize, iconsize));
0154     m_alphaLockButton->setCheckable(true);
0155     m_alphaLockButton->setAutoRaise(true);
0156 
0157     KisAction* alphaLockAction = m_viewManager->actionManager()->createAction("preserve_alpha");
0158     m_alphaLockButton->setDefaultAction(alphaLockAction);
0159 
0160     // horizontal and vertical mirror toolbar buttons
0161 
0162     // mirror tool options for the X Mirror
0163     toolbarMenuXMirror = new QMenu();
0164 
0165     hideCanvasDecorationsX = m_viewManager->actionManager()->createAction("mirrorX-hideDecorations");
0166     toolbarMenuXMirror->addAction(hideCanvasDecorationsX);
0167 
0168     lockActionX = m_viewManager->actionManager()->createAction("mirrorX-lock");
0169     toolbarMenuXMirror->addAction(lockActionX);
0170 
0171     moveToCenterActionX = m_viewManager->actionManager()->createAction("mirrorX-moveToCenter");
0172     toolbarMenuXMirror->addAction(moveToCenterActionX);
0173 
0174 
0175     // mirror tool options for the Y Mirror
0176     toolbarMenuYMirror = new QMenu();
0177 
0178     hideCanvasDecorationsY = m_viewManager->actionManager()->createAction("mirrorY-hideDecorations");
0179     toolbarMenuYMirror->addAction(hideCanvasDecorationsY);
0180 
0181 
0182     lockActionY = m_viewManager->actionManager()->createAction("mirrorY-lock");
0183     toolbarMenuYMirror->addAction(lockActionY);
0184 
0185     moveToCenterActionY = m_viewManager->actionManager()->createAction("mirrorY-moveToCenter");
0186     toolbarMenuYMirror->addAction(moveToCenterActionY);
0187 
0188     // create horizontal and vertical mirror buttons
0189 
0190     m_hMirrorButton = new KisHighlightedToolButton(this);
0191     int menuPadding = 20;
0192     m_hMirrorButton->setFixedSize(buttonsize + menuPadding, buttonsize);
0193     m_hMirrorButton->setIconSize(QSize(iconsize, iconsize));
0194     m_hMirrorButton->setCheckable(true);
0195     m_hMirrorAction = m_viewManager->actionManager()->createAction("hmirror_action");
0196     m_hMirrorButton->setDefaultAction(m_hMirrorAction);
0197     m_hMirrorButton->setMenu(toolbarMenuXMirror);
0198     m_hMirrorButton->setPopupMode(QToolButton::MenuButtonPopup);
0199     m_hMirrorButton->setAutoRaise(true);
0200 
0201     m_vMirrorButton = new KisHighlightedToolButton(this);
0202     m_vMirrorButton->setFixedSize(buttonsize + menuPadding, buttonsize);
0203     m_vMirrorButton->setIconSize(QSize(iconsize, iconsize));
0204     m_vMirrorButton->setCheckable(true);
0205     m_vMirrorAction = m_viewManager->actionManager()->createAction("vmirror_action");
0206     m_vMirrorButton->setDefaultAction(m_vMirrorAction);
0207     m_vMirrorButton->setMenu(toolbarMenuYMirror);
0208     m_vMirrorButton->setPopupMode(QToolButton::MenuButtonPopup);
0209     m_vMirrorButton->setAutoRaise(true);
0210 
0211     QAction *wrapAroundAction = m_viewManager->actionManager()->createAction("wrap_around_mode");
0212 
0213     m_wrapAroundButton = new KisHighlightedToolButton(this);
0214     m_wrapAroundButton->setFixedSize(buttonsize, buttonsize);
0215     m_wrapAroundButton->setIconSize(QSize(iconsize, iconsize));
0216     m_wrapAroundButton->setDefaultAction(wrapAroundAction);
0217     m_wrapAroundButton->setCheckable(true);
0218     m_wrapAroundButton->setAutoRaise(true);
0219 
0220     // add connections for horizontal and mirrror buttons
0221     connect(lockActionX, SIGNAL(toggled(bool)), this, SLOT(slotLockXMirrorToggle(bool)));
0222     connect(lockActionY, SIGNAL(toggled(bool)), this, SLOT(slotLockYMirrorToggle(bool)));
0223 
0224     connect(moveToCenterActionX, SIGNAL(triggered(bool)), this, SLOT(slotMoveToCenterMirrorX()));
0225     connect(moveToCenterActionY, SIGNAL(triggered(bool)), this, SLOT(slotMoveToCenterMirrorY()));
0226 
0227     connect(hideCanvasDecorationsX, SIGNAL(toggled(bool)), this, SLOT(slotHideDecorationMirrorX(bool)));
0228     connect(hideCanvasDecorationsY, SIGNAL(toggled(bool)), this, SLOT(slotHideDecorationMirrorY(bool)));
0229 
0230     const bool sliderLabels = cfg.sliderLabels();
0231     int sliderWidth;
0232 
0233     if (sliderLabels) {
0234         sliderWidth = 150 * logicalDpiX() / 96;
0235     }
0236     else {
0237         sliderWidth = 120 * logicalDpiX() / 96;
0238     }
0239 
0240     for (int i = 0; i < 4; ++i) {
0241         m_sliderChooser[i] = new KisWidgetChooser(i + 1);
0242 
0243         KisDoubleSliderSpinBox* slOpacity;
0244         KisDoubleSliderSpinBox* slFlow;
0245         KisDoubleSliderSpinBox* slSize;
0246         KisMultipliersDoubleSliderSpinBox* slPatternSize;
0247         if (sliderLabels) {
0248             slOpacity     = m_sliderChooser[i]->addWidget<KisDoubleSliderSpinBox>("opacity");
0249             slFlow        = m_sliderChooser[i]->addWidget<KisDoubleSliderSpinBox>("flow");
0250             slSize        = m_sliderChooser[i]->addWidget<KisDoubleSliderSpinBox>("size");
0251             slPatternSize = m_sliderChooser[i]->addWidget<KisMultipliersDoubleSliderSpinBox>("patternsize");
0252             slOpacity->setPrefix(QString("%1 ").arg(i18n("Opacity:")));
0253             slFlow->setPrefix(QString("%1 ").arg(i18n("Flow:")));
0254             slSize->setPrefix(QString("%1 ").arg(i18n("Size:")));
0255             slPatternSize->setPrefix(QString("%1 ").arg(i18n("Pattern Scale:")));
0256         }
0257         else {
0258             slOpacity = m_sliderChooser[i]->addWidget<KisDoubleSliderSpinBox>("opacity", i18n("Opacity:"));
0259             slFlow    = m_sliderChooser[i]->addWidget<KisDoubleSliderSpinBox>("flow", i18n("Flow:"));
0260             slSize    = m_sliderChooser[i]->addWidget<KisDoubleSliderSpinBox>("size", i18n("Size:"));
0261             slPatternSize = m_sliderChooser[i]->addWidget<KisMultipliersDoubleSliderSpinBox>("patternsize", i18n("Pattern Scale:"));
0262         }
0263 
0264         slOpacity->setRange(0, 100, 0);
0265         slOpacity->setValue(100);
0266         slOpacity->setSingleStep(5);
0267         slOpacity->setSuffix(i18n("%"));
0268         slOpacity->setMinimumWidth(qMax(sliderWidth, slOpacity->sizeHint().width()));
0269         slOpacity->setFixedHeight(buttonsize);
0270         slOpacity->setBlockUpdateSignalOnDrag(true);
0271 
0272         slFlow->setRange(0, 100, 0);
0273         slFlow->setValue(100);
0274         slFlow->setSingleStep(5);
0275         slFlow->setSuffix(i18n("%"));
0276         slFlow->setMinimumWidth(qMax(sliderWidth, slFlow->sizeHint().width()));
0277         slFlow->setFixedHeight(buttonsize);
0278         slFlow->setBlockUpdateSignalOnDrag(true);
0279 
0280         slSize->setRange(0.01, KisImageConfig(true).maxBrushSize(), 2);
0281         slSize->setValue(100);
0282 
0283         slSize->setSingleStep(1);
0284         slSize->setExponentRatio(3.0);
0285         slSize->setSuffix(i18n(" px"));
0286         slSize->setMinimumWidth(qMax(sliderWidth, slSize->sizeHint().width()));
0287         slSize->setFixedHeight(buttonsize);
0288         slSize->setBlockUpdateSignalOnDrag(true);
0289 
0290         slPatternSize->setRange(0.0, 2.0, 2);
0291         slPatternSize->setValue(1.0);
0292         slPatternSize->addMultiplier(0.1);
0293         slPatternSize->addMultiplier(2);
0294         slPatternSize->addMultiplier(10);
0295 
0296         slPatternSize->setSingleStep(0.01);
0297         slPatternSize->setSuffix(i18n("x"));
0298         slPatternSize->setMinimumWidth(qMax(sliderWidth, slPatternSize->sizeHint().width()));
0299         slPatternSize->setFixedHeight(buttonsize);
0300         slPatternSize->setBlockUpdateSignalOnDrag(true);
0301 
0302         m_sliderChooser[i]->setMinimumWidth(qMax(sliderWidth, slPatternSize->sizeHint().width()));
0303 
0304         m_sliderChooser[i]->chooseWidget(cfg.toolbarSlider(i + 1));
0305     }
0306 
0307     m_cmbCompositeOp = new KisCompositeOpComboBox();
0308     m_cmbCompositeOp->setFixedHeight(buttonsize);
0309     m_cmbCompositeOp->connectBlendmodeActions(m_viewManager->actionManager());
0310 
0311     KisWorkspaceChooser *workspacePopup = new KisWorkspaceChooser(viewManager);
0312     m_workspaceWidget = new KisPopupButton(this);
0313     m_workspaceWidget->setIcon(KisIconUtils::loadIcon("workspace-chooser"));
0314     m_workspaceWidget->setToolTip(i18n("Choose workspace"));
0315     m_workspaceWidget->setFixedSize(buttonsize, buttonsize);
0316     m_workspaceWidget->setIconSize(QSize(iconsize, iconsize));
0317     m_workspaceWidget->setPopupWidget(workspacePopup);
0318     m_workspaceWidget->setAutoRaise(true);
0319     m_workspaceWidget->setArrowVisible(false);
0320 
0321     m_presetsChooserPopup = new KisPaintOpPresetsChooserPopup();
0322     m_presetsChooserPopup->setMinimumHeight(550);
0323     m_presetsChooserPopup->setMinimumWidth(450);
0324     m_presetSelectorPopupButton->setPopupWidget(m_presetsChooserPopup);
0325 
0326     QHBoxLayout* baseLayout = new QHBoxLayout(this);
0327     m_paintopWidget = new QWidget(this);
0328     baseLayout->addWidget(m_paintopWidget);
0329     baseLayout->setSpacing(4);
0330     baseLayout->setContentsMargins(0, 0, 0, 0);
0331 
0332     m_layout = new QHBoxLayout(m_paintopWidget);
0333     if (!cfg.toolOptionsInDocker()) {
0334         m_layout->addWidget(m_toolOptionsPopupButton);
0335     }
0336     m_layout->addWidget(m_brushEditorPopupButton);
0337     m_layout->addWidget(m_presetSelectorPopupButton);
0338     m_layout->setSpacing(4);
0339     m_layout->setContentsMargins(0, 0, 0, 0);
0340 
0341     QWidget* compositeActions = new QWidget(this);
0342     QHBoxLayout* compositeLayout = new QHBoxLayout(compositeActions);
0343     compositeLayout->addWidget(m_cmbCompositeOp);
0344     compositeLayout->addWidget(m_eraseModeButton);
0345     compositeLayout->addWidget(m_alphaLockButton);
0346 
0347     compositeLayout->setSpacing(4);
0348     compositeLayout->setContentsMargins(0, 0, 0, 0);
0349 
0350     compositeLayout->addWidget(m_reloadButton);
0351 
0352     QWidgetAction * action;
0353 
0354     action = new QWidgetAction(this);
0355     viewManager->actionCollection()->addAction("composite_actions", action);
0356     action->setText(i18n("Brush composite"));
0357     action->setDefaultWidget(compositeActions);
0358 
0359     action = new QWidgetAction(this);
0360     KisActionRegistry::instance()->propertizeAction("brushslider1", action);
0361     viewManager->actionCollection()->addAction("brushslider1", action);
0362     action->setDefaultWidget(m_sliderChooser[0]);
0363     connect(action, SIGNAL(triggered()), m_sliderChooser[0], SLOT(showPopupWidget()));
0364     connect(m_viewManager->mainWindow(), SIGNAL(themeChanged()), m_sliderChooser[0], SLOT(updateThemedIcons()));
0365 
0366     action = new QWidgetAction(this);
0367     KisActionRegistry::instance()->propertizeAction("brushslider2", action);
0368     viewManager->actionCollection()->addAction("brushslider2", action);
0369     action->setDefaultWidget(m_sliderChooser[1]);
0370     connect(action, SIGNAL(triggered()), m_sliderChooser[1], SLOT(showPopupWidget()));
0371     connect(m_viewManager->mainWindow(), SIGNAL(themeChanged()), m_sliderChooser[1], SLOT(updateThemedIcons()));
0372 
0373     action = new QWidgetAction(this);
0374     KisActionRegistry::instance()->propertizeAction("brushslider3", action);
0375     viewManager->actionCollection()->addAction("brushslider3", action);
0376     action->setDefaultWidget(m_sliderChooser[2]);
0377     connect(action, SIGNAL(triggered()), m_sliderChooser[2], SLOT(showPopupWidget()));
0378     connect(m_viewManager->mainWindow(), SIGNAL(themeChanged()), m_sliderChooser[2], SLOT(updateThemedIcons()));
0379 
0380     action = new QWidgetAction(this);
0381     KisActionRegistry::instance()->propertizeAction("brushslider4", action);
0382     viewManager->actionCollection()->addAction("brushslider4", action);
0383     action->setDefaultWidget(m_sliderChooser[3]);
0384     connect(action, SIGNAL(triggered()), m_sliderChooser[3], SLOT(showPopupWidget()));
0385     connect(m_viewManager->mainWindow(), SIGNAL(themeChanged()), m_sliderChooser[3], SLOT(updateThemedIcons()));
0386 
0387     action = new QWidgetAction(this);
0388     KisActionRegistry::instance()->propertizeAction("next_favorite_preset", action);
0389     viewManager->actionCollection()->addAction("next_favorite_preset", action);
0390     connect(action, SIGNAL(triggered()), this, SLOT(slotNextFavoritePreset()));
0391 
0392     action = new QWidgetAction(this);
0393     KisActionRegistry::instance()->propertizeAction("previous_favorite_preset", action);
0394     viewManager->actionCollection()->addAction("previous_favorite_preset", action);
0395     connect(action, SIGNAL(triggered()), this, SLOT(slotPreviousFavoritePreset()));
0396 
0397     action = new QWidgetAction(this);
0398     KisActionRegistry::instance()->propertizeAction("previous_preset", action);
0399     viewManager->actionCollection()->addAction("previous_preset", action);
0400     connect(action, SIGNAL(triggered()), this, SLOT(slotSwitchToPreviousPreset()));
0401 
0402     if (!cfg.toolOptionsInDocker()) {
0403         action = new QWidgetAction(this);
0404         KisActionRegistry::instance()->propertizeAction("show_tool_options", action);
0405         viewManager->actionCollection()->addAction("show_tool_options", action);
0406         connect(action, SIGNAL(triggered()), m_toolOptionsPopupButton, SLOT(showPopupWidget()));
0407     }
0408 
0409 
0410     action = new QWidgetAction(this);
0411     KisActionRegistry::instance()->propertizeAction("show_brush_presets", action);
0412     viewManager->actionCollection()->addAction("show_brush_presets", action);
0413     connect(action, SIGNAL(triggered()), m_presetSelectorPopupButton, SLOT(showPopupWidget()));
0414     m_presetsChooserPopup->addAction(action);
0415 
0416     QWidget* mirrorActions = new QWidget(this);
0417     QHBoxLayout* mirrorLayout = new QHBoxLayout(mirrorActions);
0418     mirrorLayout->addWidget(m_hMirrorButton);
0419 
0420     mirrorLayout->addWidget(m_vMirrorButton);
0421     mirrorLayout->addWidget(m_wrapAroundButton);
0422     mirrorLayout->setSpacing(4);
0423     mirrorLayout->setContentsMargins(0, 0, 0, 0);
0424 
0425     action = new QWidgetAction(this);
0426     KisActionRegistry::instance()->propertizeAction("mirror_actions", action);
0427     action->setDefaultWidget(mirrorActions);
0428     viewManager->actionCollection()->addAction("mirror_actions", action);
0429 
0430     action = new QWidgetAction(this);
0431     KisActionRegistry::instance()->propertizeAction(ResourceType::Workspaces, action);
0432     viewManager->actionCollection()->addAction(ResourceType::Workspaces, action);
0433     action->setDefaultWidget(m_workspaceWidget);
0434     connect(action, SIGNAL(triggered()), m_workspaceWidget, SLOT(showPopupWidget()));
0435     workspacePopup->addAction(action);
0436 
0437     if (!cfg.toolOptionsInDocker()) {
0438         m_toolOptionsPopup = new KisToolOptionsPopup();
0439         m_toolOptionsPopupButton->setPopupWidget(m_toolOptionsPopup);
0440     }
0441 
0442 
0443     m_savePresetWidget = new KisPresetSaveWidget(this);
0444 
0445     m_presetsEditor = new KisPaintOpPresetsEditor(m_resourceProvider, m_favoriteResourceManager, m_savePresetWidget, m_brushEditorPopupButton);
0446     m_presetsEditor->setWindowTitle(i18n("Brush Editor"));
0447     m_brushEditorPopupButton->setPopupWidget(m_presetsEditor);
0448     m_brushEditorPopupButton->setPopupWidgetDetached(cfg.paintopPopupDetached());
0449 
0450     connect(m_presetsEditor, SIGNAL(brushEditorShown()), SLOT(slotUpdateOptionsWidgetPopup()));
0451     connect(m_presetsEditor, SIGNAL(toggleDetachState(bool)), m_brushEditorPopupButton, SLOT(setPopupWidgetDetached(bool)));
0452     connect(m_viewManager->mainWindow(), SIGNAL(themeChanged()), m_presetsEditor, SLOT(updateThemedIcons()));
0453 
0454     action = new QWidgetAction(this);
0455     KisActionRegistry::instance()->propertizeAction("show_brush_editor", action);
0456     viewManager->actionCollection()->addAction("show_brush_editor", action);
0457     connect(action, SIGNAL(toggled(bool)), this, SLOT(togglePresetEditor()));
0458     m_presetsEditor->addAction(action);
0459 
0460     m_currCompositeOpID = KoCompositeOpRegistry::instance().getDefaultCompositeOp().id();
0461 
0462     slotNodeChanged(viewManager->activeNode());
0463     // Get all the paintops
0464     QList<QString> keys = KisPaintOpRegistry::instance()->keys();
0465     QList<KisPaintOpFactory*> factoryList;
0466 
0467     Q_FOREACH (const QString & paintopId, keys) {
0468         factoryList.append(KisPaintOpRegistry::instance()->get(paintopId));
0469     }
0470     m_presetsEditor->setPaintOpList(factoryList);
0471 
0472     connect(m_presetsEditor       , SIGNAL(paintopActivated(QString))          , SLOT(slotSetPaintop(QString)));
0473     connect(m_presetsEditor       , SIGNAL(defaultPresetClicked())             , SLOT(slotSetupDefaultPreset()));
0474     connect(m_presetsEditor       , SIGNAL(signalResourceSelected(KoResourceSP )), SLOT(resourceSelected(KoResourceSP )));
0475     connect(m_presetsEditor       , SIGNAL(reloadPresetClicked())              , SLOT(slotReloadPreset()));
0476     connect(m_presetsEditor       , SIGNAL(dirtyPresetToggled(bool))           , SLOT(slotDirtyPresetToggled(bool)));
0477     connect(m_presetsEditor       , SIGNAL(eraserBrushSizeToggled(bool))       , SLOT(slotEraserBrushSizeToggled(bool)));
0478     connect(m_presetsEditor       , SIGNAL(eraserBrushOpacityToggled(bool))       , SLOT(slotEraserBrushOpacityToggled(bool)));
0479 
0480     connect(m_presetsEditor, SIGNAL(createPresetFromScratch(QString)), this, SLOT(slotCreatePresetFromScratch(QString)));
0481 
0482     connect(m_presetsChooserPopup, SIGNAL(resourceSelected(KoResourceSP ))      , SLOT(resourceSelected(KoResourceSP )));
0483     connect(m_presetsChooserPopup, SIGNAL(resourceClicked(KoResourceSP ))      , SLOT(resourceSelected(KoResourceSP )));
0484 
0485     connect(m_resourceProvider   , SIGNAL(sigNodeChanged(KisNodeSP))    , SLOT(slotNodeChanged(KisNodeSP)));
0486     connect(m_cmbCompositeOp     , SIGNAL(currentIndexChanged(int))           , SLOT(slotSetCompositeMode(int)));
0487     connect(m_eraseAction          , SIGNAL(toggled(bool))                    , SLOT(slotToggleEraseMode(bool)));
0488     connect(alphaLockAction      , SIGNAL(toggled(bool))                    , SLOT(slotToggleAlphaLockMode(bool)));
0489 
0490     m_disablePressureAction = m_viewManager->actionManager()->createAction("disable_pressure");
0491     connect(m_disablePressureAction  , SIGNAL(toggled(bool))                    , SLOT(slotDisablePressureMode(bool)));
0492     m_disablePressureAction->setChecked(true);
0493 
0494     connect(m_hMirrorAction        , SIGNAL(toggled(bool))                    , SLOT(slotHorizontalMirrorChanged(bool)));
0495     connect(m_vMirrorAction        , SIGNAL(toggled(bool))                    , SLOT(slotVerticalMirrorChanged(bool)));
0496     connect(m_reloadAction         , SIGNAL(triggered())                        , SLOT(slotReloadPreset()));
0497 
0498     connect(m_sliderChooser[0]->getWidget<KisDoubleSliderSpinBox>("opacity")               , SIGNAL(valueChanged(qreal)), SLOT(slotSlider1Changed()));
0499     connect(m_sliderChooser[0]->getWidget<KisDoubleSliderSpinBox>("flow")                  , SIGNAL(valueChanged(qreal)), SLOT(slotSlider1Changed()));
0500     connect(m_sliderChooser[0]->getWidget<KisDoubleSliderSpinBox>("size")                  , SIGNAL(valueChanged(qreal)), SLOT(slotSlider1Changed()));
0501     connect(m_sliderChooser[0]->getWidget<KisMultipliersDoubleSliderSpinBox>("patternsize"), SIGNAL(valueChanged(qreal)), SLOT(slotSlider1Changed()));
0502     connect(m_sliderChooser[1]->getWidget<KisDoubleSliderSpinBox>("opacity")               , SIGNAL(valueChanged(qreal)), SLOT(slotSlider2Changed()));
0503     connect(m_sliderChooser[1]->getWidget<KisDoubleSliderSpinBox>("flow")                  , SIGNAL(valueChanged(qreal)), SLOT(slotSlider2Changed()));
0504     connect(m_sliderChooser[1]->getWidget<KisDoubleSliderSpinBox>("size")                  , SIGNAL(valueChanged(qreal)), SLOT(slotSlider2Changed()));
0505     connect(m_sliderChooser[1]->getWidget<KisMultipliersDoubleSliderSpinBox>("patternsize"), SIGNAL(valueChanged(qreal)), SLOT(slotSlider2Changed()));
0506     connect(m_sliderChooser[2]->getWidget<KisDoubleSliderSpinBox>("opacity")               , SIGNAL(valueChanged(qreal)), SLOT(slotSlider3Changed()));
0507     connect(m_sliderChooser[2]->getWidget<KisDoubleSliderSpinBox>("flow")                  , SIGNAL(valueChanged(qreal)), SLOT(slotSlider3Changed()));
0508     connect(m_sliderChooser[2]->getWidget<KisDoubleSliderSpinBox>("size")                  , SIGNAL(valueChanged(qreal)), SLOT(slotSlider3Changed()));
0509     connect(m_sliderChooser[2]->getWidget<KisMultipliersDoubleSliderSpinBox>("patternsize"), SIGNAL(valueChanged(qreal)), SLOT(slotSlider3Changed()));
0510     connect(m_sliderChooser[3]->getWidget<KisDoubleSliderSpinBox>("opacity")               , SIGNAL(valueChanged(qreal)), SLOT(slotSlider4Changed()));
0511     connect(m_sliderChooser[3]->getWidget<KisDoubleSliderSpinBox>("flow")                  , SIGNAL(valueChanged(qreal)), SLOT(slotSlider4Changed()));
0512     connect(m_sliderChooser[3]->getWidget<KisDoubleSliderSpinBox>("size")                  , SIGNAL(valueChanged(qreal)), SLOT(slotSlider4Changed()));
0513     connect(m_sliderChooser[3]->getWidget<KisMultipliersDoubleSliderSpinBox>("patternsize"), SIGNAL(valueChanged(qreal)), SLOT(slotSlider4Changed()));
0514 
0515     connect(m_resourceProvider, SIGNAL(sigFGColorUsed(KoColor)), m_favoriteResourceManager, SLOT(slotAddRecentColor(KoColor)));
0516 
0517     connect(m_resourceProvider, SIGNAL(sigFGColorChanged(KoColor)), m_favoriteResourceManager, SLOT(slotChangeFGColorSelector(KoColor)));
0518     connect(m_resourceProvider, SIGNAL(sigBGColorChanged(KoColor)), m_favoriteResourceManager, SLOT(slotSetBGColor(KoColor)));
0519 
0520     // cold initialization
0521     m_favoriteResourceManager->slotChangeFGColorSelector(m_resourceProvider->fgColor());
0522     m_favoriteResourceManager->slotSetBGColor(m_resourceProvider->bgColor());
0523 
0524     connect(m_favoriteResourceManager, SIGNAL(sigSetFGColor(KoColor)), m_resourceProvider, SLOT(slotSetFGColor(KoColor)));
0525     connect(m_favoriteResourceManager, SIGNAL(sigSetBGColor(KoColor)), m_resourceProvider, SLOT(slotSetBGColor(KoColor)));
0526 
0527     connect(viewManager->mainWindow(), SIGNAL(themeChanged()), this, SLOT(slotUpdateSelectionIcon()));
0528     connect(m_resourceProvider->resourceManager(), SIGNAL(canvasResourceChanged(int,QVariant)),
0529             this, SLOT(slotCanvasResourceChanged(int,QVariant)));
0530     connect(m_resourceProvider->resourceManager(), SIGNAL(canvasResourceChangeAttempted(int,QVariant)),
0531             this, SLOT(slotCanvasResourceChangeAttempted(int,QVariant)));
0532 
0533     connect(&m_optionWidgetUpdateCompressor, SIGNAL(timeout()), this, SLOT(slotUpdateOptionsWidgetPopup()));
0534 
0535     slotInputDeviceChanged(KoToolManager::instance()->currentInputDevice());
0536 
0537     findDefaultPresets();
0538 }
0539 
0540 
0541 KisPaintopBox::~KisPaintopBox()
0542 {
0543     KisConfig cfg(false);
0544     QMapIterator<TabletToolID, TabletToolData> iter(m_tabletToolMap);
0545     while (iter.hasNext()) {
0546         iter.next();
0547         if ((iter.key().pointer) == QTabletEvent::Eraser) {
0548             cfg.writeEntry(QString("LastEraser_%1").arg(iter.key().uniqueTabletId), iter.value().preset->name());
0549         }
0550         else {
0551             cfg.writeEntry(QString("LastPreset_%1").arg(iter.key().uniqueTabletId), iter.value().preset->name());
0552         }
0553     }
0554     // Do not delete the widget, since it is global to the application, not owned by the view
0555     m_presetsEditor->setPaintOpSettingsWidget(0);
0556     qDeleteAll(m_paintopOptionWidgets);
0557     delete m_favoriteResourceManager;
0558 
0559     delete toolbarMenuXMirror;
0560     delete toolbarMenuYMirror;
0561 
0562     for (int i = 0; i < 3; ++i)
0563     {
0564         delete m_sliderChooser[i];
0565     }
0566 }
0567 
0568 void KisPaintopBox::restoreResource(KoResourceSP resource)
0569 {
0570     KisPaintOpPresetSP preset = resource.dynamicCast<KisPaintOpPreset>();
0571 
0572     if (preset) {
0573         setCurrentPaintop(preset);
0574 
0575         m_presetsEditor->setPresetImage(preset->image());
0576         m_presetsEditor->resourceSelected(resource);
0577     }
0578 }
0579 
0580 void KisPaintopBox::newOptionWidgets(const QList<QPointer<QWidget> > &optionWidgetList)
0581 {
0582     if (m_toolOptionsPopup) {
0583         m_toolOptionsPopup->newOptionWidgets(optionWidgetList);
0584     }
0585 }
0586 
0587 void KisPaintopBox::resourceSelected(KoResourceSP resource)
0588 {
0589     // This happens if no storages were available on startup
0590     if (!m_optionWidget) {
0591         KisPaintOpPresetSP preset = resource.dynamicCast<KisPaintOpPreset>();
0592         setCurrentPaintop(preset);
0593         return;
0594     }
0595 
0596     m_presetsEditor->setCreatingBrushFromScratch(false); // show normal UI elements when we are not creating
0597 
0598     KisPaintOpPresetSP preset = resource.dynamicCast<KisPaintOpPreset>();
0599 
0600     if (preset && preset->valid() && preset != m_resourceProvider->currentPreset()) {
0601         if (!m_dirtyPresetsEnabled) {
0602             KisSignalsBlocker blocker(m_optionWidget);
0603             Q_UNUSED(blocker);
0604 
0605             KisPaintOpPresetResourceServer *rserver = KisResourceServerProvider::instance()->paintOpPresetServer();
0606 
0607             if (!rserver->reloadResource(preset)) {
0608                 qWarning() << "failed to reload the preset.";
0609             }
0610         }
0611 
0612         dbgResources << "resourceSelected: preset" << preset << (preset ? QString("%1").arg(preset->valid()) : "");
0613         setCurrentPaintop(preset);
0614 
0615         m_presetsEditor->setPresetImage(preset->image());
0616         m_presetsEditor->resourceSelected(resource);
0617     }
0618 }
0619 
0620 void KisPaintopBox::setCurrentPaintop(const KoID& paintop)
0621 {
0622     KisPaintOpPresetSP preset = activePreset(paintop);
0623     setCurrentPaintop(preset);
0624 }
0625 
0626 void KisPaintopBox::setCurrentPaintop(KisPaintOpPresetSP preset)
0627 {
0628     if (preset == m_resourceProvider->currentPreset()) {
0629         if (preset == m_tabletToolMap[m_currTabletToolID].preset) {
0630             return;
0631         }
0632     }
0633     Q_ASSERT(preset);
0634     const KoID& paintop = preset->paintOp();
0635     m_presetConnections.clear();
0636 
0637     if (m_resourceProvider->currentPreset()) {
0638         m_resourceProvider->setPreviousPaintOpPreset(m_resourceProvider->currentPreset());
0639 
0640         if (m_optionWidget) {
0641             m_optionWidget->hide();
0642         }
0643 
0644     }
0645 
0646     if (!m_paintopOptionWidgets.contains(paintop)) {
0647         m_paintopOptionWidgets[paintop] = KisPaintOpRegistry::instance()->get(paintop.id())->createConfigWidget(this);
0648         m_paintopOptionWidgets[paintop]->setResourcesInterface(KisGlobalResourcesInterface::instance());
0649         m_paintopOptionWidgets[paintop]->setCanvasResourcesInterface(m_viewManager->canvasResourceProvider()->resourceManager()->canvasResourcesInterface());
0650     }
0651 
0652     m_optionWidget = m_paintopOptionWidgets[paintop];
0653 
0654     Q_ASSERT(m_optionWidget && m_presetSelectorPopupButton);
0655 
0656     KisSignalsBlocker b(m_optionWidget);
0657 
0658     m_optionWidget->setImage(m_viewManager->image());
0659     m_optionWidget->setNode(m_viewManager->activeNode());
0660 
0661     m_optionWidget->setConfigurationSafe(preset->settings());
0662 
0663     m_presetsEditor->setPaintOpSettingsWidget(m_optionWidget);
0664 
0665     m_resourceProvider->setPaintOpPreset(preset);
0666 
0667 
0668 
0669     /// We must connect to the **uncompressed** version of the preset
0670     /// update signal. That is the only way we can guarantee that
0671     /// the signals will not form cycles. As a consequence, we should
0672     /// compress this signal ourselves.
0673     m_optionsWidgetConnections.reset(new KisAcyclicSignalConnector());
0674     m_optionsWidgetConnections->connectForwardVoid(m_optionWidget, SIGNAL(sigConfigurationUpdated()), this, SLOT(slotGuiChangedCurrentPreset()));
0675     m_optionsWidgetConnections->connectBackwardVoid(preset->updateProxy(), SIGNAL(sigSettingsChangedUncompressed()), &m_optionWidgetUpdateCompressor, SLOT(start()));
0676 
0677     m_presetConnections.addConnection(m_optionWidget, SIGNAL(sigSaveLockedConfig(KisPropertiesConfigurationSP)), this, SLOT(slotSaveLockedOptionToPreset(KisPropertiesConfigurationSP)));
0678     m_presetConnections.addConnection(m_optionWidget, SIGNAL(sigDropLockedConfig(KisPropertiesConfigurationSP)), this, SLOT(slotDropLockedOption(KisPropertiesConfigurationSP)));
0679 
0680     // load the current preset icon to the preset selector toolbar button
0681     m_presetSelectorPopupButton->setThumbnail(preset->image());
0682     m_presetsEditor->setCurrentPaintOpId(paintop.id());
0683 
0684 
0685     //o() << "\tsetting the new preset for" << m_currTabletToolID.uniqueID << "to" << preset->name();
0686     m_paintOpPresetMap[m_resourceProvider->currentPreset()->paintOp()] = preset;
0687     m_tabletToolMap[m_currTabletToolID].preset = preset;
0688     m_tabletToolMap[m_currTabletToolID].paintOpID = preset->paintOp();
0689 
0690 
0691     if (m_presetsEditor->currentPaintOpId() != paintop.id()) {
0692         // Must change the paintop as the current one is not supported
0693         // by the new colorspace.
0694         dbgKrita << "current paintop " << paintop.name() << " was not set, not supported by colorspace";
0695     }
0696 
0697     m_currCompositeOpID = preset->settings()->paintOpCompositeOp();
0698     updateCompositeOp(m_currCompositeOpID);
0699 
0700     if (preset->settings()->hasPatternSettings()) {
0701         setMultiplierSliderValue("patternsize", preset->settings()->paintOpPatternSize());
0702         setWidgetState(ENABLE_PATTERNSIZE);
0703     }
0704     else {
0705         setWidgetState(DISABLE_PATTERNSIZE);
0706     }
0707 
0708     // MyPaint brushes don't support custom blend modes, they always perform "Normal and Erase" blending.
0709     if (preset->paintOp().id() == "mypaintbrush") {
0710         setWidgetState(DISABLE_COMPOSITEOP);
0711         if (m_resourceProvider->currentCompositeOp() != COMPOSITE_ERASE && m_resourceProvider->currentCompositeOp() != COMPOSITE_OVER) {
0712             m_resourceProvider->setCurrentCompositeOp(COMPOSITE_OVER);
0713         }
0714     }
0715     else {
0716         setWidgetState(ENABLE_COMPOSITEOP);
0717     }
0718 }
0719 
0720 void KisPaintopBox::slotUpdateOptionsWidgetPopup()
0721 {
0722     KisPaintOpPresetSP preset = m_resourceProvider->currentPreset();
0723 
0724     // This happens when we have a new brush engine for which no default preset exists yet.
0725     if (!preset) return;
0726 
0727     // the connection to the preset is maintained even when the editor
0728     // is hidden, so skip the updates
0729     if (!m_presetsEditor->isVisible()) return;
0730 
0731     KIS_SAFE_ASSERT_RECOVER_RETURN(preset);
0732     KIS_SAFE_ASSERT_RECOVER_RETURN(m_optionWidget);
0733 
0734     m_optionWidget->setConfigurationSafe(preset->settings());
0735 
0736     m_presetsEditor->resourceSelected(preset);
0737     m_presetsEditor->updateViewSettings();
0738 
0739     // the m_viewManager->image() is set earlier, but the reference will be missing when the stamp button is pressed
0740     // need to later do some research on how and when we should be using weak shared pointers (WSP) that creates this situation
0741     m_optionWidget->setImage(m_viewManager->image());
0742 }
0743 
0744 void KisPaintopBox::togglePresetEditor()
0745 {
0746     if (m_brushEditorPopupButton->isPopupWidgetVisible()) {
0747         m_brushEditorPopupButton->hidePopupWidget();
0748     } else {
0749         m_brushEditorPopupButton->showPopupWidget();
0750     }
0751 }
0752 
0753 KisPaintOpPresetSP KisPaintopBox::defaultPreset(const KoID& paintOp)
0754 {
0755     QString path = ":/presets/" + paintOp.id() + ".kpp";
0756 
0757     if (paintOp.id() == "mypaintbrush") {
0758         path = ":/presets/" + paintOp.id() + ".myb";
0759     }
0760 
0761     dbgResources << "Getting default presets from qrc resources" << path;
0762 
0763     KisPaintOpPresetSP preset(new KisPaintOpPreset(path));
0764 
0765     if (!preset->load(KisGlobalResourcesInterface::instance())) {
0766         bool success = false;
0767 
0768         QFile file(path);
0769 
0770         if (file.open(QIODevice::ReadOnly))
0771         {
0772             // this is needed specifically for MyPaint brushes
0773             QVector<KisResourceLoaderBase*> loaders = KisResourceLoaderRegistry::instance()->resourceTypeLoaders(ResourceType::PaintOpPresets);
0774             for (int i = 0; i < loaders.count(); i++) {
0775                 file.seek(0); // to ensure that one loader reading bytes won't interfere with another
0776                 KoResourceSP resource = loaders[i]->load(paintOp.id(), file, KisGlobalResourcesInterface::instance());
0777                 if (resource) {
0778                     preset = resource.dynamicCast<KisPaintOpPreset>();
0779                     success = !preset.isNull();
0780                     if (success) {
0781                         break;
0782                     }
0783                 }
0784             }
0785             file.close();
0786         }
0787 
0788         if (!success) {
0789             preset = KisPaintOpRegistry::instance()->defaultPreset(paintOp, KisGlobalResourcesInterface::instance());
0790         }
0791     }
0792 
0793     Q_ASSERT(preset);
0794     Q_ASSERT(preset->valid());
0795 
0796     return preset;
0797 }
0798 
0799 KisPaintOpPresetSP KisPaintopBox::activePreset(const KoID& paintOp)
0800 {
0801     if (m_paintOpPresetMap[paintOp] == 0) {
0802         m_paintOpPresetMap[paintOp] = defaultPreset(paintOp);
0803     }
0804 
0805     return m_paintOpPresetMap[paintOp];
0806 }
0807 
0808 void KisPaintopBox::updateCompositeOp(QString compositeOpID)
0809 {
0810     if (!m_optionWidget) return;
0811     KisSignalsBlocker blocker(m_optionWidget);
0812 
0813     KisNodeSP node = m_resourceProvider->currentNode();
0814 
0815     if (node && node->paintDevice()) {
0816         if (!node->paintDevice()->compositionSourceColorSpace()->hasCompositeOp(compositeOpID)) {
0817             compositeOpID = KoCompositeOpRegistry::instance().getDefaultCompositeOp().id();
0818         }
0819 
0820         {
0821             KisSignalsBlocker b1(m_cmbCompositeOp);
0822             m_cmbCompositeOp->selectCompositeOp(KoID(compositeOpID));
0823         }
0824         if (compositeOpID != m_currCompositeOpID) {
0825             m_currCompositeOpID = compositeOpID;
0826         }
0827         if (compositeOpID == COMPOSITE_ERASE || m_resourceProvider->eraserMode()) {
0828             m_eraseModeButton->setChecked(true);
0829         }
0830         else {
0831             m_eraseModeButton->setChecked(false);
0832         }
0833     }
0834     else if (!node) {
0835         KisSignalsBlocker b1(m_cmbCompositeOp);
0836         m_cmbCompositeOp->selectCompositeOp(KoID(compositeOpID));
0837         m_currCompositeOpID = compositeOpID;
0838 
0839     }
0840 }
0841 
0842 void KisPaintopBox::setWidgetState(int flags)
0843 {
0844     if (flags & (ENABLE_COMPOSITEOP | DISABLE_COMPOSITEOP)) {
0845         m_cmbCompositeOp->setEnabled(flags & ENABLE_COMPOSITEOP);
0846         m_eraseModeButton->setEnabled(flags & ENABLE_COMPOSITEOP);
0847     }
0848 
0849     if (flags & (ENABLE_PRESETS | DISABLE_PRESETS)) {
0850         m_presetSelectorPopupButton->setEnabled(flags & ENABLE_PRESETS);
0851         m_brushEditorPopupButton->setEnabled(flags & ENABLE_PRESETS);
0852     }
0853 }
0854 
0855 void KisPaintopBox::setSliderValue(const QString& sliderID, qreal value)
0856 {
0857     for (int i = 0; i < 4; ++i) {
0858         KisDoubleSliderSpinBox* slider = m_sliderChooser[i]->getWidget<KisDoubleSliderSpinBox>(sliderID);
0859         KisSignalsBlocker b(slider);
0860 
0861         if (sliderID == "opacity" || sliderID == "flow") { // opacity and flows UI stored at 0-100%
0862             slider->setValue(value*100);
0863         } else {
0864             slider->setValue(value); // brush size
0865         }
0866 
0867 
0868     }
0869 }
0870 
0871 void KisPaintopBox::setMultiplierSliderValue(const QString& sliderID, qreal value)
0872 {
0873     for (int i = 0; i < 4; ++i) {
0874         KisMultipliersDoubleSliderSpinBox* slider = m_sliderChooser[i]->getWidget<KisMultipliersDoubleSliderSpinBox>(sliderID);
0875         if (!slider) continue;
0876         KisSignalsBlocker b(slider);
0877 
0878         slider->setValue(value); // brush pattern size
0879     }
0880 }
0881 
0882 void KisPaintopBox::slotSetPaintop(const QString& paintOpId)
0883 {
0884     if (KisPaintOpRegistry::instance()->get(paintOpId) != 0) {
0885         KoID id(paintOpId, KisPaintOpRegistry::instance()->get(paintOpId)->name());
0886         //qDebug() << "slotsetpaintop" << id;
0887         setCurrentPaintop(id);
0888     }
0889 }
0890 
0891 void KisPaintopBox::slotInputDeviceChanged(const KoInputDevice& inputDevice)
0892 {
0893     TabletToolMap::iterator toolData = m_tabletToolMap.find(inputDevice);
0894 
0895     //qDebug() << "slotInputDeviceChanged()" << inputDevice.device() << inputDevice.uniqueTabletId();
0896 
0897     m_currTabletToolID = TabletToolID(inputDevice);
0898 
0899     if (toolData == m_tabletToolMap.end()) {
0900         KisConfig cfg(true);
0901         KisPaintOpPresetResourceServer *rserver = KisResourceServerProvider::instance()->paintOpPresetServer();
0902         KisPaintOpPresetSP preset;
0903         if (inputDevice.pointer() == QTabletEvent::Eraser) {
0904             preset = rserver->resource("", "", cfg.readEntry<QString>(QString("LastEraser_%1").arg(inputDevice.uniqueTabletId()), m_eraserName));
0905         }
0906         else {
0907             preset = rserver->resource("", "", cfg.readEntry<QString>(QString("LastPreset_%1").arg(inputDevice.uniqueTabletId()), m_defaultPresetName));
0908 //            if (preset)
0909 //                qDebug() << "found stored preset " << preset->name() << "for" << inputDevice.uniqueTabletId();
0910 //            else
0911 //                qDebug() << "no preset found for" << inputDevice.uniqueTabletId();
0912         }
0913         if (!preset) {
0914             preset = rserver->resource("", "", m_defaultPresetName);
0915         }
0916         if (preset) {
0917 //            qDebug() << "inputdevicechanged 1" << preset;
0918             setCurrentPaintop(preset);
0919         }
0920     }
0921     else {
0922         if (toolData->preset) {
0923             //qDebug() << "inputdevicechanged 2" << toolData->preset;
0924             setCurrentPaintop(toolData->preset);
0925         }
0926         else {
0927             //qDebug() << "inputdevicechanged 3" << toolData->paintOpID;
0928             setCurrentPaintop(toolData->paintOpID);
0929         }
0930     }
0931 }
0932 
0933 void KisPaintopBox::slotCreatePresetFromScratch(QString paintop)
0934 {
0935     //First try to select an available default preset for that engine. If it doesn't exist, then
0936     //manually set the engine to use a new preset.
0937     KoID id(paintop, KisPaintOpRegistry::instance()->get(paintop)->name());
0938     KisPaintOpPresetSP preset = defaultPreset(id);
0939 
0940     slotSetPaintop(paintop);  // change the paintop settings area and update the UI
0941 
0942     if (!preset) {
0943         m_presetsEditor->setCreatingBrushFromScratch(true); // disable UI elements while creating from scratch
0944         preset = m_resourceProvider->currentPreset();
0945     } else {
0946         m_resourceProvider->setPaintOpPreset(preset);
0947         if (m_optionWidget) {
0948             m_optionWidget->setConfigurationSafe(preset->settings());
0949         }
0950     }
0951     m_presetsEditor->resourceSelected(preset);  // this helps update the UI on the brush editor
0952 }
0953 
0954 void KisPaintopBox::slotCanvasResourceChangeAttempted(int key, const QVariant &value)
0955 {
0956     Q_UNUSED(value);
0957 
0958     if (key == KoCanvasResource::ForegroundColor) {
0959         slotUnsetEraseMode();
0960     }
0961 }
0962 
0963 void KisPaintopBox::slotCanvasResourceChanged(int key, const QVariant &value)
0964 {
0965     if (m_viewManager) {
0966         sender()->blockSignals(true);
0967         KisPaintOpPresetSP preset = m_viewManager->canvasResourceProvider()->resourceManager()->resource(KoCanvasResource::CurrentPaintOpPreset).value<KisPaintOpPresetSP>();
0968         if (preset && m_resourceProvider->currentPreset()->name() != preset->name()) {
0969             QString compositeOp = preset->settings()->getString("CompositeOp");
0970             updateCompositeOp(compositeOp);
0971             resourceSelected(preset);
0972         }
0973 
0974         if (key == KoCanvasResource::CurrentPaintOpPreset) {
0975             /**
0976              * Update currently selected preset in both the popup widgets
0977              */
0978             m_presetsChooserPopup->canvasResourceChanged(preset);
0979             m_presetsEditor->currentPresetChanged(preset);
0980         }
0981 
0982         if (key == KoCanvasResource::CurrentCompositeOp) {
0983             if (m_resourceProvider->currentCompositeOp() != m_currCompositeOpID) {
0984                 updateCompositeOp(m_resourceProvider->currentCompositeOp());
0985             }
0986         }
0987 
0988         if (key == KoCanvasResource::Size) {
0989             setSliderValue("size", m_resourceProvider->size());
0990         }
0991 
0992         if (key == KoCanvasResource::PatternSize) {
0993             setMultiplierSliderValue("patternsize", m_resourceProvider->patternSize());
0994         }
0995 
0996         if (key == KoCanvasResource::Opacity) {
0997             setSliderValue("opacity", m_resourceProvider->opacity());
0998         }
0999 
1000         if (key == KoCanvasResource::Flow) {
1001             setSliderValue("flow", m_resourceProvider->flow());
1002         }
1003 
1004         if (key == KoCanvasResource::EraserMode) {
1005             m_eraseAction->setChecked(value.toBool());
1006         }
1007 
1008         if (key == KoCanvasResource::DisablePressure) {
1009             m_disablePressureAction->setChecked(value.toBool());
1010         }
1011 
1012         if (key == KoCanvasResource::MirrorHorizontal) {
1013             m_hMirrorAction->setChecked(value.toBool());
1014         }
1015 
1016         if (key == KoCanvasResource::MirrorVertical) {
1017             m_vMirrorAction->setChecked(value.toBool());
1018         }
1019 
1020         sender()->blockSignals(false);
1021     }
1022 }
1023 
1024 void KisPaintopBox::slotSetupDefaultPreset()
1025 {
1026     KisPaintOpPresetSP preset = defaultPreset(m_resourceProvider->currentPreset()->paintOp());
1027     if (m_optionWidget) {
1028         m_optionWidget->setConfigurationSafe(preset->settings());
1029     }
1030     m_resourceProvider->setPaintOpPreset(preset);
1031 
1032     // tell the brush editor that the resource has changed
1033     // so it can update everything
1034     m_presetsEditor->resourceSelected(preset);
1035 }
1036 
1037 void KisPaintopBox::slotNodeChanged(const KisNodeSP node)
1038 {
1039     KisNodeSP previousNode(m_currentNode);
1040     if (previousNode && previousNode->paintDevice())
1041         disconnect(previousNode->paintDevice().data(), SIGNAL(colorSpaceChanged(const KoColorSpace*)), this, SLOT(slotColorSpaceChanged(const KoColorSpace*)));
1042 
1043     // Reconnect colorspace change of node
1044     if (node && node->paintDevice()) {
1045         connect(node->paintDevice().data(), SIGNAL(colorSpaceChanged(const KoColorSpace*)), this, SLOT(slotColorSpaceChanged(const KoColorSpace*)));
1046         m_resourceProvider->setCurrentCompositeOp(m_currCompositeOpID);
1047         m_currentNode = node;
1048         slotColorSpaceChanged(node->paintDevice()->colorSpace());
1049     }
1050 
1051     if (m_optionWidget) {
1052         m_optionWidget->setNode(node);
1053     }
1054 }
1055 
1056 void KisPaintopBox::slotColorSpaceChanged(const KoColorSpace* colorSpace)
1057 {
1058     KisNodeSP node(m_currentNode);
1059     const KoColorSpace *compositionSpace = colorSpace;
1060     if (node && node->paintDevice()) {
1061         // Currently, composition source is enough to determine the available blending mode,
1062         // because either destination is the same (paint layers), or composition happens
1063         // in source space (masks).
1064         compositionSpace = node->paintDevice()->compositionSourceColorSpace();
1065     }
1066     m_cmbCompositeOp->validate(compositionSpace);
1067 }
1068 
1069 void KisPaintopBox::slotToggleEraseMode(bool checked)
1070 {
1071     const bool oldEraserMode = m_resourceProvider->eraserMode();
1072     m_resourceProvider->setEraserMode(checked);
1073 
1074     if (oldEraserMode != checked && m_eraserBrushSizeEnabled) {
1075         const qreal currentSize = m_resourceProvider->size();
1076 
1077         KisPaintOpSettingsSP settings = m_resourceProvider->currentPreset()->settings();
1078 
1079         // remember brush size. set the eraser size to the normal brush size if not set
1080         if (checked) {
1081             settings->setSavedBrushSize(currentSize);
1082             if (qFuzzyIsNull(settings->savedEraserSize())) {
1083                 settings->setSavedEraserSize(currentSize);
1084             }
1085         } else {
1086             settings->setSavedEraserSize(currentSize);
1087             if (qFuzzyIsNull(settings->savedBrushSize())) {
1088                 settings->setSavedBrushSize(currentSize);
1089             }
1090         }
1091 
1092         //update value in UI (this is the main place the value is 'stored' in memory)
1093         qreal newSize = checked ? settings->savedEraserSize() : settings->savedBrushSize();
1094         m_resourceProvider->setSize(newSize);
1095     }
1096     if (oldEraserMode != checked && m_eraserBrushOpacityEnabled) {
1097         const qreal currentOpacity = m_resourceProvider->opacity();
1098 
1099         KisPaintOpSettingsSP settings = m_resourceProvider->currentPreset()->settings();
1100 
1101         // remember brush opacity. set the eraser opacity to the normal brush opacity if not set
1102         if (checked) {
1103             settings->setSavedBrushOpacity(currentOpacity);
1104             if (qFuzzyIsNull(settings->savedEraserOpacity())) {
1105                 settings->setSavedEraserOpacity(currentOpacity);
1106             }
1107         } else {
1108             settings->setSavedEraserOpacity(currentOpacity);
1109             if (qFuzzyIsNull(settings->savedBrushOpacity())) {
1110                 settings->setSavedBrushOpacity(currentOpacity);
1111             }
1112         }
1113 
1114         //update value in UI (this is the main place the value is 'stored' in memory)
1115         qreal newOpacity = checked ? settings->savedEraserOpacity() : settings->savedBrushOpacity();
1116         m_resourceProvider->setOpacity(newOpacity);
1117     }
1118 }
1119 
1120 void KisPaintopBox::slotSetCompositeMode(int index)
1121 {
1122     Q_UNUSED(index);
1123     QString compositeOp = m_cmbCompositeOp->selectedCompositeOp().id();
1124     m_resourceProvider->setCurrentCompositeOp(compositeOp);
1125 }
1126 
1127 void KisPaintopBox::slotHorizontalMirrorChanged(bool value)
1128 {
1129     m_resourceProvider->setMirrorHorizontal(value);
1130 }
1131 
1132 void KisPaintopBox::slotVerticalMirrorChanged(bool value)
1133 {
1134     m_resourceProvider->setMirrorVertical(value);
1135 }
1136 
1137 void KisPaintopBox::sliderChanged(int n)
1138 {
1139     if (!m_optionWidget) // widget will not exist if the are no documents open
1140         return;
1141 
1142 
1143     KisSignalsBlocker blocker(m_optionWidget);
1144 
1145     // flow and opacity are shown as 0-100% on the UI, but their data is actually 0-1. Convert those two values
1146     // back for further work
1147     qreal opacity = m_sliderChooser[n]->getWidget<KisDoubleSliderSpinBox>("opacity")->value()/100;
1148     qreal flow    = m_sliderChooser[n]->getWidget<KisDoubleSliderSpinBox>("flow")->value()/100;
1149     qreal size    = m_sliderChooser[n]->getWidget<KisDoubleSliderSpinBox>("size")->value();
1150     qreal patternsize = m_sliderChooser[n]->getWidget<KisMultipliersDoubleSliderSpinBox>("patternsize")->value();
1151 
1152 
1153     setSliderValue("opacity", opacity);
1154     setSliderValue("flow"   , flow);
1155     setSliderValue("size"   , size);
1156     setMultiplierSliderValue("patternsize", patternsize);
1157 
1158     if (m_presetsEnabled) {
1159         // IMPORTANT: set the PaintOp size before setting the other properties
1160         //            it won't work the other way
1161         // TODO: why?!
1162 
1163         m_resourceProvider->setSize(size);
1164         m_resourceProvider->setPatternSize(patternsize);
1165         m_resourceProvider->setOpacity(opacity);
1166         m_resourceProvider->setFlow(flow);
1167 
1168 
1169         KisLockedPropertiesProxySP propertiesProxy = KisLockedPropertiesServer::instance()->createLockedPropertiesProxy(m_resourceProvider->currentPreset()->settings());
1170         propertiesProxy->setProperty("OpacityValue", opacity);
1171         propertiesProxy->setProperty("FlowValue", flow);
1172         propertiesProxy->setProperty("Texture/Pattern/Scale", patternsize);
1173         m_optionWidget->setConfigurationSafe(m_resourceProvider->currentPreset()->settings().data());
1174     } else {
1175         m_resourceProvider->setOpacity(opacity);
1176     }
1177 
1178     m_presetsEditor->resourceSelected(m_resourceProvider->currentPreset());
1179 }
1180 
1181 void KisPaintopBox::slotSlider1Changed()
1182 {
1183     sliderChanged(0);
1184 }
1185 
1186 void KisPaintopBox::slotSlider2Changed()
1187 {
1188     sliderChanged(1);
1189 }
1190 
1191 void KisPaintopBox::slotSlider3Changed()
1192 {
1193     sliderChanged(2);
1194 }
1195 
1196 void KisPaintopBox::slotSlider4Changed()
1197 {
1198     sliderChanged(3);
1199 }
1200 
1201 void KisPaintopBox::slotToolChanged(KoCanvasController* canvas)
1202 {
1203     Q_UNUSED(canvas);
1204 
1205     if (!m_viewManager->canvasBase()) return;
1206 
1207     QString  id   = KoToolManager::instance()->activeToolId();
1208     KisTool* tool = dynamic_cast<KisTool*>(KoToolManager::instance()->toolById(m_viewManager->canvasBase(), id));
1209 
1210     if (tool) {
1211         int flags = tool->flags();
1212 
1213         if (flags & KisTool::FLAG_USES_CUSTOM_COMPOSITEOP) {
1214             setWidgetState(ENABLE_COMPOSITEOP | ENABLE_OPACITY | ENABLE_PATTERNSIZE);
1215         } else                                              {
1216             setWidgetState(DISABLE_COMPOSITEOP | DISABLE_OPACITY | DISABLE_PATTERNSIZE);
1217         }
1218 
1219         if (flags & KisTool::FLAG_USES_CUSTOM_PRESET) {
1220             setWidgetState(ENABLE_PRESETS);
1221             if (!m_resourceProvider->currentPreset()) return;
1222 
1223             // block updates of avoid some over updating of the option widget
1224             m_blockUpdate = true;
1225 
1226             setSliderValue("size", m_resourceProvider->size());
1227 
1228             {
1229                 qreal opacity = m_resourceProvider->currentPreset()->settings()->paintOpOpacity();
1230                 m_resourceProvider->setOpacity(opacity);
1231                 setSliderValue("opacity", opacity);
1232                 setWidgetState(ENABLE_OPACITY);
1233             }
1234 
1235             {
1236                 setSliderValue("flow", m_resourceProvider->currentPreset()->settings()->paintOpFlow());
1237                 setWidgetState(ENABLE_FLOW);
1238             }
1239 
1240             {
1241                 setMultiplierSliderValue("patternsize", m_resourceProvider->currentPreset()->settings()->paintOpPatternSize());
1242                 setWidgetState(ENABLE_PATTERNSIZE);
1243             }
1244 
1245             // MyPaint brushes don't support custom blend modes, they always perform "Normal and Erase" blending.
1246             if (m_resourceProvider->currentPreset()->paintOp().id() == "mypaintbrush") {
1247                 if (m_resourceProvider->currentCompositeOp() != COMPOSITE_ERASE && m_resourceProvider->currentCompositeOp() != COMPOSITE_OVER) {
1248                     updateCompositeOp(COMPOSITE_OVER);
1249                 }
1250                 setWidgetState(DISABLE_COMPOSITEOP);
1251             } else {
1252                 updateCompositeOp(m_resourceProvider->currentPreset()->settings()->paintOpCompositeOp());
1253                 setWidgetState(ENABLE_COMPOSITEOP);
1254             }
1255 
1256             m_blockUpdate = false;
1257 
1258             m_presetsEnabled = true;
1259         } else {
1260             setWidgetState(DISABLE_PRESETS);
1261             m_presetsEnabled = false;
1262         }
1263 
1264         if (flags & KisTool::FLAG_USES_CUSTOM_SIZE) {
1265             setWidgetState(ENABLE_SIZE | ENABLE_FLOW | ENABLE_PATTERNSIZE);
1266         } else {
1267             setWidgetState(DISABLE_SIZE | DISABLE_FLOW| DISABLE_PATTERNSIZE);
1268         }
1269 
1270     } else setWidgetState(DISABLE_ALL);
1271 }
1272 
1273 void KisPaintopBox::slotPreviousFavoritePreset()
1274 {
1275     if (!m_favoriteResourceManager) return;
1276 
1277     QVector<QString> presets = m_favoriteResourceManager->favoritePresetNamesList();
1278     for (int i=0; i < presets.size(); ++i) {
1279         if (m_resourceProvider->currentPreset() &&
1280                 m_resourceProvider->currentPreset()->name() == presets[i]) {
1281             if (i > 0) {
1282                 m_favoriteResourceManager->slotChangeActivePaintop(i - 1);
1283             } else {
1284                 m_favoriteResourceManager->slotChangeActivePaintop(m_favoriteResourceManager->numFavoritePresets() - 1);
1285             }
1286             //floating message should have least 2 lines, otherwise
1287             //preset thumbnail will be too small to distinguish
1288             //(because size of image on floating message depends on amount of lines in msg)
1289             m_viewManager->showFloatingMessage(
1290                         i18n("%1\nselected",
1291                              m_resourceProvider->currentPreset()->name()),
1292                         QIcon(QPixmap::fromImage(m_resourceProvider->currentPreset()->image())));
1293 
1294             return;
1295         }
1296     }
1297 }
1298 
1299 void KisPaintopBox::slotNextFavoritePreset()
1300 {
1301     if (!m_favoriteResourceManager) return;
1302 
1303     QVector<QString> presets = m_favoriteResourceManager->favoritePresetNamesList();
1304     for(int i = 0; i < presets.size(); ++i) {
1305         if (m_resourceProvider->currentPreset()->name() == presets[i]) {
1306             if (i < m_favoriteResourceManager->numFavoritePresets() - 1) {
1307                 m_favoriteResourceManager->slotChangeActivePaintop(i + 1);
1308             } else {
1309                 m_favoriteResourceManager->slotChangeActivePaintop(0);
1310             }
1311             m_viewManager->showFloatingMessage(
1312                         i18n("%1\nselected",
1313                              m_resourceProvider->currentPreset()->name()),
1314                         QIcon(QPixmap::fromImage(m_resourceProvider->currentPreset()->image())));
1315 
1316             return;
1317         }
1318     }
1319 }
1320 
1321 void KisPaintopBox::slotSwitchToPreviousPreset()
1322 {
1323     if (m_resourceProvider->previousPreset()) {
1324         setCurrentPaintop(m_resourceProvider->previousPreset());
1325         m_viewManager->showFloatingMessage(
1326                     i18n("%1\nselected",
1327                          m_resourceProvider->currentPreset()->name()),
1328                     QIcon(QPixmap::fromImage(m_resourceProvider->currentPreset()->image())));
1329     }
1330 }
1331 
1332 void KisPaintopBox::slotUnsetEraseMode()
1333 {
1334     m_eraseAction->setChecked(false);
1335 }
1336 
1337 void KisPaintopBox::slotToggleAlphaLockMode(bool checked)
1338 {
1339     if (checked) {
1340         m_alphaLockButton->actions()[0]->setIcon(KisIconUtils::loadIcon("bar-transparency-locked"));
1341     } else {
1342         m_alphaLockButton->actions()[0]->setIcon(KisIconUtils::loadIcon("bar-transparency-unlocked"));
1343     }
1344     m_resourceProvider->setGlobalAlphaLock(checked);
1345 }
1346 
1347 void KisPaintopBox::slotDisablePressureMode(bool checked)
1348 {
1349     if (checked) {
1350         m_disablePressureAction->setIcon(KisIconUtils::loadIcon("transform_icons_penPressure"));
1351     } else {
1352         m_disablePressureAction->setIcon(KisIconUtils::loadIcon("transform_icons_penPressure_locked"));
1353     }
1354 
1355     m_resourceProvider->setDisablePressure(checked);
1356 }
1357 
1358 void KisPaintopBox::slotReloadPreset()
1359 {
1360     KisSignalsBlocker blocker(m_optionWidget);
1361 
1362     KisPaintOpPresetResourceServer *rserver = KisResourceServerProvider::instance()->paintOpPresetServer();
1363     QSharedPointer<KisPaintOpPreset> preset = m_resourceProvider->currentPreset();
1364 
1365     // Presets that just have been created cannot be reloaded.
1366     if (preset && preset->resourceId() > -1) {
1367         const bool result = rserver->reloadResource(preset);
1368         KIS_SAFE_ASSERT_RECOVER_NOOP(result && "couldn't reload preset");
1369     }
1370 }
1371 void KisPaintopBox::slotGuiChangedCurrentPreset() // Called only when UI is changed and not when preset is changed
1372 {
1373     KisPaintOpPresetSP preset = m_resourceProvider->currentPreset();
1374 
1375     {
1376         /**
1377          * Here we postpone all the settings updates events until the entire writing
1378          * operation will be finished. As soon as it is finished, the updates will be
1379          * emitted happily (if there were any).
1380          */
1381 
1382         KisPaintOpPreset::UpdatedPostponer postponer(preset);
1383 
1384 
1385         QStringList preserveProperties;
1386         preserveProperties << "lodUserAllowed";
1387         preserveProperties << "lodSizeThreshold";
1388 
1389         // clear all the properties before dumping the stuff into the preset,
1390         // some of the options add the values incrementally
1391         // (e.g. KisPaintOpUtils::RequiredBrushFilesListTag), therefore they
1392         // may add up if we pass the same preset multiple times
1393         preset->settings()->resetSettings(preserveProperties);
1394 
1395         m_optionWidget->writeConfigurationSafe(const_cast<KisPaintOpSettings*>(preset->settings().data()));
1396     }
1397 
1398     // we should also update the preset strip to update the status of the "dirty" mark
1399     m_presetsEditor->resourceSelected(m_resourceProvider->currentPreset());
1400 
1401     // TODO!!!!!!!!
1402     //m_presetsPopup->updateViewSettings();
1403 }
1404 void KisPaintopBox::slotSaveLockedOptionToPreset(KisPropertiesConfigurationSP p)
1405 {
1406 
1407     QMapIterator<QString, QVariant> i(p->getProperties());
1408     while (i.hasNext()) {
1409         i.next();
1410         m_resourceProvider->currentPreset()->settings()->setProperty(i.key(), QVariant(i.value()));
1411         if (m_resourceProvider->currentPreset()->settings()->hasProperty(i.key() + "_previous")) {
1412             m_resourceProvider->currentPreset()->settings()->removeProperty(i.key() + "_previous");
1413         }
1414 
1415     }
1416     slotGuiChangedCurrentPreset();
1417 
1418 }
1419 
1420 void KisPaintopBox::slotDropLockedOption(KisPropertiesConfigurationSP p)
1421 {
1422     KisSignalsBlocker blocker(m_optionWidget);
1423     KisPaintOpPresetSP preset = m_resourceProvider->currentPreset();
1424 
1425     {
1426         KisDirtyStateSaver<KisPaintOpPresetSP> dirtySaver(preset);
1427 
1428         QMapIterator<QString, QVariant> i(p->getProperties());
1429         while (i.hasNext()) {
1430             i.next();
1431             if (preset->settings()->hasProperty(i.key() + "_previous")) {
1432                 preset->settings()->setProperty(i.key(), preset->settings()->getProperty(i.key() + "_previous"));
1433                 preset->settings()->removeProperty(i.key() + "_previous");
1434             }
1435 
1436         }
1437     }
1438 
1439 }
1440 void KisPaintopBox::slotDirtyPresetToggled(bool value)
1441 {
1442     if (!value) {
1443         slotReloadPreset();
1444         m_presetsEditor->resourceSelected(m_resourceProvider->currentPreset());
1445         m_presetsEditor->updateViewSettings();
1446     }
1447     m_dirtyPresetsEnabled = value;
1448     KisConfig cfg(false);
1449     cfg.setUseDirtyPresets(m_dirtyPresetsEnabled);
1450 }
1451 
1452 void KisPaintopBox::slotEraserBrushSizeToggled(bool value)
1453 {
1454     m_eraserBrushSizeEnabled = value;
1455     KisConfig cfg(false);
1456     cfg.setUseEraserBrushSize(m_eraserBrushSizeEnabled);
1457 }
1458 
1459 void KisPaintopBox::slotEraserBrushOpacityToggled(bool value)
1460 {
1461     m_eraserBrushOpacityEnabled = value;
1462     KisConfig cfg(false);
1463     cfg.setUseEraserBrushOpacity(m_eraserBrushOpacityEnabled);
1464 }
1465 
1466 void KisPaintopBox::slotUpdateSelectionIcon()
1467 {
1468     m_hMirrorAction->setIcon(KisIconUtils::loadIcon("symmetry-horizontal"));
1469     m_vMirrorAction->setIcon(KisIconUtils::loadIcon("symmetry-vertical"));
1470 
1471     KisConfig cfg(true);
1472     if (!cfg.toolOptionsInDocker() && m_toolOptionsPopupButton) {
1473         m_toolOptionsPopupButton->setIcon(KisIconUtils::loadIcon("configure"));
1474     }
1475 
1476     m_presetSelectorPopupButton->setIcon(KisIconUtils::loadIcon("paintop_settings_01"));
1477     m_brushEditorPopupButton->setIcon(KisIconUtils::loadIcon("paintop_settings_02"));
1478     m_workspaceWidget->setIcon(KisIconUtils::loadIcon("workspace-chooser"));
1479 
1480     m_eraseAction->setIcon(KisIconUtils::loadIcon("draw-eraser"));
1481     m_reloadAction->setIcon(KisIconUtils::loadIcon("reload-preset"));
1482 
1483     if (m_disablePressureAction->isChecked()) {
1484         m_disablePressureAction->setIcon(KisIconUtils::loadIcon("transform_icons_penPressure"));
1485     } else {
1486         m_disablePressureAction->setIcon(KisIconUtils::loadIcon("transform_icons_penPressure_locked"));
1487     }
1488 }
1489 
1490 void KisPaintopBox::slotLockXMirrorToggle(bool toggleLock) {
1491     m_resourceProvider->setMirrorHorizontalLock(toggleLock);
1492 }
1493 
1494 void KisPaintopBox::slotLockYMirrorToggle(bool toggleLock) {
1495     m_resourceProvider->setMirrorVerticalLock(toggleLock);
1496 }
1497 
1498 void KisPaintopBox::slotHideDecorationMirrorX(bool toggled) {
1499     m_resourceProvider->setMirrorHorizontalHideDecorations(toggled);
1500 }
1501 
1502 void KisPaintopBox::slotHideDecorationMirrorY(bool toggled) {
1503     m_resourceProvider->setMirrorVerticalHideDecorations(toggled);
1504 }
1505 
1506 void KisPaintopBox::slotMoveToCenterMirrorX() {
1507     m_resourceProvider->mirrorHorizontalMoveCanvasToCenter();
1508 }
1509 
1510 void KisPaintopBox::slotMoveToCenterMirrorY() {
1511     m_resourceProvider->mirrorVerticalMoveCanvasToCenter();
1512 }
1513 
1514 void KisPaintopBox::findDefaultPresets()
1515 {
1516     m_eraserName = "a) Eraser Circle";
1517     m_defaultPresetName = "b) Basic-5 Size Opacity";
1518 }