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