File indexing completed on 2024-05-19 04:29:04

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