kis_paintop_box.cc 59.4 KB
Newer Older
1
2
3
/*
 *  kis_paintop_box.cc - part of KImageShop/Krayon/Krita
 *
4
5
6
7
8
9
 *  SPDX-FileCopyrightText: 2004 Boudewijn Rempt (boud@valdyas.org)
 *  SPDX-FileCopyrightText: 2009-2011 Sven Langkamp (sven.langkamp@gmail.com)
 *  SPDX-FileCopyrightText: 2010 Lukáš Tvrdý <lukast.dev@gmail.com>
 *  SPDX-FileCopyrightText: 2011 Silvio Heinrich <plassy@web.de>
 *  SPDX-FileCopyrightText: 2011 Srikanth Tiyyagura <srikanth.tulasiram@gmail.com>
 *  SPDX-FileCopyrightText: 2014 Mohit Goyal <mohit.bits2011@gmail.com>
10
 *
Samuel Gaist's avatar
Samuel Gaist committed
11
 *  SPDX-License-Identifier: GPL-2.0-or-later
12
 */
13
14

#include "kis_paintop_box.h"
15

Adrian Page's avatar
Adrian Page committed
16
#include <QHBoxLayout>
Halla Rempt's avatar
Halla Rempt committed
17
#include <QLabel>
18
#include <QToolButton>
19
#include <QPixmap>
20
#include <QWidgetAction>
21
#include <QApplication>
22
#include <QMenu>
23
#include <QTime>
Halla Rempt's avatar
Halla Rempt committed
24

25
#include <kis_debug.h>
26
#include <kis_types.h>
Halla Rempt's avatar
Halla Rempt committed
27
28

#include <kactioncollection.h>
Laurent Montel's avatar
Laurent Montel committed
29
#include <kacceleratormanager.h>
30
#include <QKeySequence>
Halla Rempt's avatar
Halla Rempt committed
31

32
#include <kis_icon.h>
Halla Rempt's avatar
Halla Rempt committed
33
#include <KoColorSpace.h>
34
#include <KoCompositeOpRegistry.h>
35
#include <KoToolManager.h>
36
#include <KoColorSpaceRegistry.h>
37

38
#include <KoResource.h>
39
#include <KisResourceDirtyStateSaver.h>
40

41
#include <kis_paint_device.h>
Halla Rempt's avatar
Halla Rempt committed
42
43
44
#include <brushengine/kis_paintop_registry.h>
#include <brushengine/kis_paintop_preset.h>
#include <brushengine/kis_paintop_settings.h>
45
#include <brushengine/kis_paintop_settings_update_proxy.h>
46
#include <kis_config_widget.h>
Halla Rempt's avatar
Halla Rempt committed
47
#include <kis_image.h>
Halla Rempt's avatar
Halla Rempt committed
48
#include <kis_node.h>
Halla Rempt's avatar
Halla Rempt committed
49
#include <brushengine/kis_paintop_config_widget.h>
50
#include <kis_action.h>
Halla Rempt's avatar
Halla Rempt committed
51

52
#include "kis_canvas2.h"
Halla Rempt's avatar
Halla Rempt committed
53
#include "kis_node_manager.h"
54
#include "KisViewManager.h"
55
#include "kis_canvas_resource_provider.h"
56
#include "KisResourceServerProvider.h"
57
#include "kis_favorite_resource_manager.h"
58
#include "kis_config.h"
59

60
#include "KisPopupButton.h"
61
#include "widgets/kis_iconwidget.h"
62
#include "widgets/kis_tool_options_popup.h"
63
#include "widgets/kis_paintop_presets_editor.h"
64
#include "widgets/kis_paintop_presets_chooser_popup.h"
Sven Langkamp's avatar
Sven Langkamp committed
65
#include "widgets/kis_workspace_chooser.h"
66
#include "widgets/kis_paintop_list_widget.h"
67
#include "kis_slider_spin_box.h"
68
#include "widgets/kis_multipliers_double_slider_spinbox.h"
69
#include "widgets/kis_cmb_composite.h"
70
71
#include "widgets/kis_widget_chooser.h"
#include "tool/kis_tool.h"
72
#include "kis_signals_blocker.h"
73
#include "kis_action_manager.h"
74
#include "KisHighlightedToolButton.h"
75
#include <KisGlobalResourcesInterface.h>
76

77
KisPaintopBox::KisPaintopBox(KisViewManager *viewManager, QWidget *parent, const char *name)
78
    : QWidget(parent)
79
80
    , m_resourceProvider(viewManager->canvasResourceProvider())
    , m_viewManager(viewManager)
Halla Rempt's avatar
Halla Rempt committed
81
{
82
    Q_ASSERT(viewManager != 0);
Halla Rempt's avatar
Halla Rempt committed
83

Adrian Page's avatar
Adrian Page committed
84
    setObjectName(name);
85
    KisConfig cfg(true);
86
    m_dirtyPresetsEnabled = cfg.useDirtyPresets();
87
    m_eraserBrushSizeEnabled = cfg.useEraserBrushSize();
88
    m_eraserBrushOpacityEnabled = cfg.useEraserBrushOpacity();
Adrian Page's avatar
Adrian Page committed
89

90
91
    KAcceleratorManager::setNoAccel(this);

Adrian Page's avatar
Adrian Page committed
92
    setWindowTitle(i18n("Painter's Toolchest"));
93

94
95
    m_favoriteResourceManager = new KisFavoriteResourceManager(this);

96
    KConfigGroup grp =  KSharedConfig::openConfig()->group("krita").group("Toolbar BrushesAndStuff");
97
    int iconsize = grp.readEntry("IconSize", 22);
98
    // NOTE: buttonsize should be the same value as the one used in ktoolbar for all QToolButton
99
    int buttonsize = grp.readEntry("ButtonSize", 32);
Halla Rempt's avatar
Halla Rempt committed
100

101
102
    if (!cfg.toolOptionsInDocker()) {
        m_toolOptionsPopupButton = new KisPopupButton(this);
103
        m_toolOptionsPopupButton->setIcon(KisIconUtils::loadIcon("view-choose"));
104
        m_toolOptionsPopupButton->setToolTip(i18n("Tool Settings"));
105
106
        m_toolOptionsPopupButton->setFixedSize(buttonsize, buttonsize);
        m_toolOptionsPopupButton->setIconSize(QSize(iconsize, iconsize));
107
        m_toolOptionsPopupButton->setFlat(true);
108
109
    }

110
    m_brushEditorPopupButton = new KisIconWidget(this);
Timothée Giet's avatar
Timothée Giet committed
111
    m_brushEditorPopupButton->setIcon(KisIconUtils::loadIcon("paintop_settings_02"));
112
    m_brushEditorPopupButton->setToolTip(i18n("Edit brush settings"));
113
114
    m_brushEditorPopupButton->setFixedSize(buttonsize, buttonsize);
    m_brushEditorPopupButton->setIconSize(QSize(iconsize, iconsize));
115
    m_brushEditorPopupButton->setFlat(true);
116

117
    m_presetSelectorPopupButton = new KisIconWidget(this);
Timothée Giet's avatar
Timothée Giet committed
118
    m_presetSelectorPopupButton->setIcon(KisIconUtils::loadIcon("paintop_settings_01"));
119
    m_presetSelectorPopupButton->setToolTip(i18n("Choose brush preset"));
120
121
    m_presetSelectorPopupButton->setFixedSize(buttonsize, buttonsize);
    m_presetSelectorPopupButton->setIconSize(QSize(iconsize, iconsize));
122
    m_presetSelectorPopupButton->setFlat(true);
123
    m_presetSelectorPopupButton->setArrowVisible(false);
Halla Rempt's avatar
Halla Rempt committed
124

125
    m_eraseModeButton = new KisHighlightedToolButton(this);
126
127
    m_eraseModeButton->setFixedSize(buttonsize, buttonsize);
    m_eraseModeButton->setIconSize(QSize(iconsize, iconsize));
128
    m_eraseModeButton->setCheckable(true);
129
130
    m_eraseModeButton->setAutoRaise(true);

131

Michael Abrahams's avatar
Michael Abrahams committed
132
    m_eraseAction = m_viewManager->actionManager()->createAction("erase_action");
133
    m_eraseModeButton->setDefaultAction(m_eraseAction);
134

135
    m_reloadButton = new QToolButton(this);
136
137
    m_reloadButton->setFixedSize(buttonsize, buttonsize);
    m_reloadButton->setIconSize(QSize(iconsize, iconsize));
138
139
    m_reloadButton->setAutoRaise(true); // make button flat

140

Michael Abrahams's avatar
Michael Abrahams committed
141
    m_reloadAction = m_viewManager->actionManager()->createAction("reload_preset_action");
142
    m_reloadButton->setDefaultAction(m_reloadAction);
143

144
    m_alphaLockButton = new KisHighlightedToolButton(this);
145
146
    m_alphaLockButton->setFixedSize(buttonsize, buttonsize);
    m_alphaLockButton->setIconSize(QSize(iconsize, iconsize));
147
    m_alphaLockButton->setCheckable(true);
148
    m_alphaLockButton->setAutoRaise(true);
Michael Abrahams's avatar
Michael Abrahams committed
149
150

    KisAction* alphaLockAction = m_viewManager->actionManager()->createAction("preserve_alpha");
151
152
    m_alphaLockButton->setDefaultAction(alphaLockAction);

153
154
155
156
157
    // horizontal and vertical mirror toolbar buttons

    // mirror tool options for the X Mirror
    QMenu *toolbarMenuXMirror = new QMenu();

158
    hideCanvasDecorationsX = m_viewManager->actionManager()->createAction("mirrorX-hideDecorations");
159
160
    toolbarMenuXMirror->addAction(hideCanvasDecorationsX);

161
    lockActionX = m_viewManager->actionManager()->createAction("mirrorX-lock");
162
163
    toolbarMenuXMirror->addAction(lockActionX);

164
    moveToCenterActionX = m_viewManager->actionManager()->createAction("mirrorX-moveToCenter");
165
166
167
168
169
170
    toolbarMenuXMirror->addAction(moveToCenterActionX);


    // mirror tool options for the Y Mirror
    QMenu *toolbarMenuYMirror = new QMenu();

171
    hideCanvasDecorationsY = m_viewManager->actionManager()->createAction("mirrorY-hideDecorations");
172
173
174
    toolbarMenuYMirror->addAction(hideCanvasDecorationsY);


175
    lockActionY = m_viewManager->actionManager()->createAction("mirrorY-lock");
176
177
    toolbarMenuYMirror->addAction(lockActionY);

178
    moveToCenterActionY = m_viewManager->actionManager()->createAction("mirrorY-moveToCenter");
179
180
181
182
    toolbarMenuYMirror->addAction(moveToCenterActionY);

    // create horizontal and vertical mirror buttons

183
    m_hMirrorButton = new KisHighlightedToolButton(this);
184
185
186
    int menuPadding = 20;
    m_hMirrorButton->setFixedSize(buttonsize + menuPadding, buttonsize);
    m_hMirrorButton->setIconSize(QSize(iconsize, iconsize));
187
    m_hMirrorButton->setCheckable(true);
Michael Abrahams's avatar
Michael Abrahams committed
188
    m_hMirrorAction = m_viewManager->actionManager()->createAction("hmirror_action");
189
    m_hMirrorButton->setDefaultAction(m_hMirrorAction);
190
191
    m_hMirrorButton->setMenu(toolbarMenuXMirror);
    m_hMirrorButton->setPopupMode(QToolButton::MenuButtonPopup);
192
    m_hMirrorButton->setAutoRaise(true);
193

194
    m_vMirrorButton = new KisHighlightedToolButton(this);
195
196
    m_vMirrorButton->setFixedSize(buttonsize + menuPadding, buttonsize);
    m_vMirrorButton->setIconSize(QSize(iconsize, iconsize));
197
    m_vMirrorButton->setCheckable(true);
Michael Abrahams's avatar
Michael Abrahams committed
198
    m_vMirrorAction = m_viewManager->actionManager()->createAction("vmirror_action");
199
    m_vMirrorButton->setDefaultAction(m_vMirrorAction);
200
201
    m_vMirrorButton->setMenu(toolbarMenuYMirror);
    m_vMirrorButton->setPopupMode(QToolButton::MenuButtonPopup);
202
    m_vMirrorButton->setAutoRaise(true);
203

204
205
    QAction *wrapAroundAction = m_viewManager->actionManager()->createAction("wrap_around_mode");

206
    m_wrapAroundButton = new KisHighlightedToolButton(this);
207
208
    m_wrapAroundButton->setFixedSize(buttonsize, buttonsize);
    m_wrapAroundButton->setIconSize(QSize(iconsize, iconsize));
209
210
    m_wrapAroundButton->setDefaultAction(wrapAroundAction);
    m_wrapAroundButton->setCheckable(true);
211
    m_wrapAroundButton->setAutoRaise(true);
212
213
214
215
216

    // add connections for horizontal and mirrror buttons
    connect(lockActionX, SIGNAL(toggled(bool)), this, SLOT(slotLockXMirrorToggle(bool)));
    connect(lockActionY, SIGNAL(toggled(bool)), this, SLOT(slotLockYMirrorToggle(bool)));

217
218
    connect(moveToCenterActionX, SIGNAL(triggered(bool)), this, SLOT(slotMoveToCenterMirrorX()));
    connect(moveToCenterActionY, SIGNAL(triggered(bool)), this, SLOT(slotMoveToCenterMirrorY()));
219
220
221

    connect(hideCanvasDecorationsX, SIGNAL(toggled(bool)), this, SLOT(slotHideDecorationMirrorX(bool)));
    connect(hideCanvasDecorationsY, SIGNAL(toggled(bool)), this, SLOT(slotHideDecorationMirrorY(bool)));
Friedrich W. H. Kossebau's avatar
Friedrich W. H. Kossebau committed
222

223
224
225
226
227
228
229
230
231
    const bool sliderLabels = cfg.sliderLabels();
    int sliderWidth;

    if (sliderLabels) {
        sliderWidth = 150 * logicalDpiX() / 96;
    }
    else {
        sliderWidth = 120 * logicalDpiX() / 96;
    }
232

233
    for (int i = 0; i < 4; ++i) {
234
        m_sliderChooser[i] = new KisWidgetChooser(i + 1);
235

236
237
238
        KisDoubleSliderSpinBox* slOpacity;
        KisDoubleSliderSpinBox* slFlow;
        KisDoubleSliderSpinBox* slSize;
239
        KisMultipliersDoubleSliderSpinBox* slPatternSize;
240
        if (sliderLabels) {
241
242
243
            slOpacity     = m_sliderChooser[i]->addWidget<KisDoubleSliderSpinBox>("opacity");
            slFlow        = m_sliderChooser[i]->addWidget<KisDoubleSliderSpinBox>("flow");
            slSize        = m_sliderChooser[i]->addWidget<KisDoubleSliderSpinBox>("size");
244
            slPatternSize = m_sliderChooser[i]->addWidget<KisMultipliersDoubleSliderSpinBox>("patternsize");
245
246
247
            slOpacity->setPrefix(QString("%1 ").arg(i18n("Opacity:")));
            slFlow->setPrefix(QString("%1 ").arg(i18n("Flow:")));
            slSize->setPrefix(QString("%1 ").arg(i18n("Size:")));
248
            slPatternSize->setPrefix(QString("%1 ").arg(i18n("Pattern Scale:")));
249
250
251
252
253
        }
        else {
            slOpacity = m_sliderChooser[i]->addWidget<KisDoubleSliderSpinBox>("opacity", i18n("Opacity:"));
            slFlow    = m_sliderChooser[i]->addWidget<KisDoubleSliderSpinBox>("flow", i18n("Flow:"));
            slSize    = m_sliderChooser[i]->addWidget<KisDoubleSliderSpinBox>("size", i18n("Size:"));
254
            slPatternSize = m_sliderChooser[i]->addWidget<KisMultipliersDoubleSliderSpinBox>("patternsize", i18n("Pattern Scale:"));
255
        }
256

257
258
259
        slOpacity->setRange(0, 100, 0);
        slOpacity->setValue(100);
        slOpacity->setSingleStep(5);
260
        slOpacity->setSuffix(i18n("%"));
Moritz Molch's avatar
Moritz Molch committed
261
        slOpacity->setMinimumWidth(qMax(sliderWidth, slOpacity->sizeHint().width()));
262
        slOpacity->setFixedHeight(buttonsize);
263
        slOpacity->setBlockUpdateSignalOnDrag(true);
264

265
266
267
        slFlow->setRange(0, 100, 0);
        slFlow->setValue(100);
        slFlow->setSingleStep(5);
268
        slFlow->setSuffix(i18n("%"));
Moritz Molch's avatar
Moritz Molch committed
269
        slFlow->setMinimumWidth(qMax(sliderWidth, slFlow->sizeHint().width()));
270
        slFlow->setFixedHeight(buttonsize);
271
        slFlow->setBlockUpdateSignalOnDrag(true);
272

273
        slSize->setRange(0.01, cfg.readEntry("maximumBrushSize", 1000), 2);
274
        slSize->setValue(100);
275

276
        slSize->setSingleStep(1);
277
        slSize->setExponentRatio(3.0);
278
        slSize->setSuffix(i18n(" px"));
Moritz Molch's avatar
Moritz Molch committed
279
        slSize->setMinimumWidth(qMax(sliderWidth, slSize->sizeHint().width()));
280
        slSize->setFixedHeight(buttonsize);
281
        slSize->setBlockUpdateSignalOnDrag(true);
282

283
284
285
286
287
        slPatternSize->setRange(0.0, 2.0, 2);
        slPatternSize->setValue(1.0);
        slPatternSize->addMultiplier(0.1);
        slPatternSize->addMultiplier(2);
        slPatternSize->addMultiplier(10);
288

289
        slPatternSize->setSingleStep(.01);
290
        slPatternSize->setSuffix(i18n("x"));
291
        slPatternSize->setMinimumWidth(qMax(sliderWidth, slPatternSize->sizeHint().width()));
292
        slPatternSize->setFixedHeight(buttonsize);
293
294
        slPatternSize->setBlockUpdateSignalOnDrag(true);

295
296
        m_sliderChooser[i]->setMinimumWidth(qMax(sliderWidth, slPatternSize->sizeHint().width()));

297
        m_sliderChooser[i]->chooseWidget(cfg.toolbarSlider(i + 1));
298
    }
299

300
    m_cmbCompositeOp = new KisCompositeOpComboBox();
301
    m_cmbCompositeOp->setFixedHeight(buttonsize);
302
    m_cmbCompositeOp->connectBlendmodeActions(m_viewManager->actionManager());
303

304
    m_workspaceWidget = new KisPopupButton(this);
Timothée Giet's avatar
Timothée Giet committed
305
    m_workspaceWidget->setIcon(KisIconUtils::loadIcon("workspace-chooser"));
Sven Langkamp's avatar
Sven Langkamp committed
306
    m_workspaceWidget->setToolTip(i18n("Choose workspace"));
307
308
    m_workspaceWidget->setFixedSize(buttonsize, buttonsize);
    m_workspaceWidget->setIconSize(QSize(iconsize, iconsize));
309
    m_workspaceWidget->setPopupWidget(new KisWorkspaceChooser(viewManager));
310
    m_workspaceWidget->setFlat(true);
311
    m_workspaceWidget->setArrowVisible(false);
312

313
314
315
    QHBoxLayout* baseLayout = new QHBoxLayout(this);
    m_paintopWidget = new QWidget(this);
    baseLayout->addWidget(m_paintopWidget);
316
    baseLayout->setSpacing(4);
317
    baseLayout->setContentsMargins(0, 0, 0, 0);
318

319
    m_layout = new QHBoxLayout(m_paintopWidget);
320
321
322
323
324
    if (!cfg.toolOptionsInDocker()) {
        m_layout->addWidget(m_toolOptionsPopupButton);
    }
    m_layout->addWidget(m_brushEditorPopupButton);
    m_layout->addWidget(m_presetSelectorPopupButton);
325
    m_layout->setSpacing(4);
Sven Langkamp's avatar
Sven Langkamp committed
326
    m_layout->setContentsMargins(0, 0, 0, 0);
327

328
329
330
331
    QWidget* compositeActions = new QWidget(this);
    QHBoxLayout* compositeLayout = new QHBoxLayout(compositeActions);
    compositeLayout->addWidget(m_cmbCompositeOp);
    compositeLayout->addWidget(m_eraseModeButton);
332
    compositeLayout->addWidget(m_alphaLockButton);
333

334
335
    compositeLayout->setSpacing(4);
    compositeLayout->setContentsMargins(0, 0, 0, 0);
336

337
338
    compositeLayout->addWidget(m_reloadButton);

339
    QWidgetAction * action;
340

341
    action = new QWidgetAction(this);
342
    viewManager->actionCollection()->addAction("composite_actions", action);
343
    action->setText(i18n("Brush composite"));
344
345
    action->setDefaultWidget(compositeActions);

346
    action = new QWidgetAction(this);
Michael Abrahams's avatar
Michael Abrahams committed
347
    KisActionRegistry::instance()->propertizeAction("brushslider1", action);
348
    viewManager->actionCollection()->addAction("brushslider1", action);
349
    action->setDefaultWidget(m_sliderChooser[0]);
350
    connect(action, SIGNAL(triggered()), m_sliderChooser[0], SLOT(showPopupWidget()));
351
    connect(m_viewManager->mainWindow(), SIGNAL(themeChanged()), m_sliderChooser[0], SLOT(updateThemedIcons()));
352

353
    action = new QWidgetAction(this);
Michael Abrahams's avatar
Michael Abrahams committed
354
    KisActionRegistry::instance()->propertizeAction("brushslider2", action);
355
    viewManager->actionCollection()->addAction("brushslider2", action);
356
    action->setDefaultWidget(m_sliderChooser[1]);
357
    connect(action, SIGNAL(triggered()), m_sliderChooser[1], SLOT(showPopupWidget()));
358
    connect(m_viewManager->mainWindow(), SIGNAL(themeChanged()), m_sliderChooser[1], SLOT(updateThemedIcons()));
359

360
    action = new QWidgetAction(this);
Michael Abrahams's avatar
Michael Abrahams committed
361
    KisActionRegistry::instance()->propertizeAction("brushslider3", action);
362
    viewManager->actionCollection()->addAction("brushslider3", action);
363
364
    action->setDefaultWidget(m_sliderChooser[2]);
    connect(action, SIGNAL(triggered()), m_sliderChooser[2], SLOT(showPopupWidget()));
365
    connect(m_viewManager->mainWindow(), SIGNAL(themeChanged()), m_sliderChooser[2], SLOT(updateThemedIcons()));
366

367
368
    action = new QWidgetAction(this);
    KisActionRegistry::instance()->propertizeAction("brushslider4", action);
369
    viewManager->actionCollection()->addAction("brushslider4", action);
370
371
372
373
    action->setDefaultWidget(m_sliderChooser[3]);
    connect(action, SIGNAL(triggered()), m_sliderChooser[3], SLOT(showPopupWidget()));
    connect(m_viewManager->mainWindow(), SIGNAL(themeChanged()), m_sliderChooser[3], SLOT(updateThemedIcons()));

374
    action = new QWidgetAction(this);
Michael Abrahams's avatar
Michael Abrahams committed
375
    KisActionRegistry::instance()->propertizeAction("next_favorite_preset", action);
376
    viewManager->actionCollection()->addAction("next_favorite_preset", action);
377
378
    connect(action, SIGNAL(triggered()), this, SLOT(slotNextFavoritePreset()));

379
    action = new QWidgetAction(this);
Michael Abrahams's avatar
Michael Abrahams committed
380
    KisActionRegistry::instance()->propertizeAction("previous_favorite_preset", action);
381
    viewManager->actionCollection()->addAction("previous_favorite_preset", action);
382
383
    connect(action, SIGNAL(triggered()), this, SLOT(slotPreviousFavoritePreset()));

384
    action = new QWidgetAction(this);
Michael Abrahams's avatar
Michael Abrahams committed
385
    KisActionRegistry::instance()->propertizeAction("previous_preset", action);
386
    viewManager->actionCollection()->addAction("previous_preset", action);
387
388
    connect(action, SIGNAL(triggered()), this, SLOT(slotSwitchToPreviousPreset()));

389
    if (!cfg.toolOptionsInDocker()) {
390
        action = new QWidgetAction(this);
Michael Abrahams's avatar
Michael Abrahams committed
391
        KisActionRegistry::instance()->propertizeAction("show_tool_options", action);
392
        viewManager->actionCollection()->addAction("show_tool_options", action);
393
394
395
        connect(action, SIGNAL(triggered()), m_toolOptionsPopupButton, SLOT(showPopupWidget()));
    }

396
    action = new QWidgetAction(this);
Michael Abrahams's avatar
Michael Abrahams committed
397
    KisActionRegistry::instance()->propertizeAction("show_brush_editor", action);
398
    viewManager->actionCollection()->addAction("show_brush_editor", action);
Halla Rempt's avatar
Halla Rempt committed
399
400
    connect(action, SIGNAL(triggered()), m_brushEditorPopupButton, SLOT(showPopupWidget()));

401
    action = new QWidgetAction(this);
Michael Abrahams's avatar
Michael Abrahams committed
402
    KisActionRegistry::instance()->propertizeAction("show_brush_presets", action);
403
    viewManager->actionCollection()->addAction("show_brush_presets", action);
Halla Rempt's avatar
Halla Rempt committed
404
405
    connect(action, SIGNAL(triggered()), m_presetSelectorPopupButton, SLOT(showPopupWidget()));

406
407
    QWidget* mirrorActions = new QWidget(this);
    QHBoxLayout* mirrorLayout = new QHBoxLayout(mirrorActions);
408
    mirrorLayout->addWidget(m_hMirrorButton);
409

410
    mirrorLayout->addWidget(m_vMirrorButton);
411
    mirrorLayout->addWidget(m_wrapAroundButton);
412
    mirrorLayout->setSpacing(4);
413
    mirrorLayout->setContentsMargins(0, 0, 0, 0);
414
415

    action = new QWidgetAction(this);
Michael Abrahams's avatar
Michael Abrahams committed
416
    KisActionRegistry::instance()->propertizeAction("mirror_actions", action);
417
    action->setDefaultWidget(mirrorActions);
418
    viewManager->actionCollection()->addAction("mirror_actions", action);
419

420
    action = new QWidgetAction(this);
421
    KisActionRegistry::instance()->propertizeAction(ResourceType::Workspaces, action);
422
    viewManager->actionCollection()->addAction(ResourceType::Workspaces, action);
423
    action->setDefaultWidget(m_workspaceWidget);
Halla Rempt's avatar
Halla Rempt committed
424

425
426
427
428
429
430
    if (!cfg.toolOptionsInDocker()) {
        m_toolOptionsPopup = new KisToolOptionsPopup();
        m_toolOptionsPopupButton->setPopupWidget(m_toolOptionsPopup);
        m_toolOptionsPopup->switchDetached(false);
    }

431

432
433
    m_savePresetWidget = new KisPresetSaveWidget(this);

434
435
436
    m_presetsEditor = new KisPaintOpPresetsEditorDialog(m_resourceProvider, m_favoriteResourceManager, m_savePresetWidget, m_viewManager->mainWindow());
    m_presetsEditor->hide();
    m_presetsEditor->setWindowTitle(i18n("Brush Editor"));
437

438
439
440
    connect(m_brushEditorPopupButton, SIGNAL(clicked(bool)), m_presetsEditor, SLOT(show()));
    connect(m_presetsEditor->editorWidget(), SIGNAL(brushEditorShown()), SLOT(slotUpdateOptionsWidgetPopup()));
    connect(m_viewManager->mainWindow(), SIGNAL(themeChanged()), m_presetsEditor->editorWidget(), SLOT(updateThemedIcons()));
441

442
    m_presetsChooserPopup = new KisPaintOpPresetsChooserPopup();
443
444
    m_presetsChooserPopup->setMinimumHeight(550);
    m_presetsChooserPopup->setMinimumWidth(450);
445
    m_presetSelectorPopupButton->setPopupWidget(m_presetsChooserPopup);
446

447
    m_currCompositeOpID = KoCompositeOpRegistry::instance().getDefaultCompositeOp().id();
448

449
    slotNodeChanged(viewManager->activeNode());
450
451
452
453
    // Get all the paintops
    QList<QString> keys = KisPaintOpRegistry::instance()->keys();
    QList<KisPaintOpFactory*> factoryList;

454
    Q_FOREACH (const QString & paintopId, keys) {
455
456
        factoryList.append(KisPaintOpRegistry::instance()->get(paintopId));
    }
457
    m_presetsEditor->editorWidget()->setPaintOpList(factoryList);
458

459
460
461
462
463
464
465
    connect(m_presetsEditor->editorWidget()       , SIGNAL(paintopActivated(QString))          , SLOT(slotSetPaintop(QString)));
    connect(m_presetsEditor->editorWidget()       , SIGNAL(defaultPresetClicked())             , SLOT(slotSetupDefaultPreset()));
    connect(m_presetsEditor->editorWidget()       , SIGNAL(signalResourceSelected(KoResourceSP )), SLOT(resourceSelected(KoResourceSP )));
    connect(m_presetsEditor->editorWidget()       , SIGNAL(reloadPresetClicked())              , SLOT(slotReloadPreset()));
    connect(m_presetsEditor->editorWidget()       , SIGNAL(dirtyPresetToggled(bool))           , SLOT(slotDirtyPresetToggled(bool)));
    connect(m_presetsEditor->editorWidget()       , SIGNAL(eraserBrushSizeToggled(bool))       , SLOT(slotEraserBrushSizeToggled(bool)));
    connect(m_presetsEditor->editorWidget()       , SIGNAL(eraserBrushOpacityToggled(bool))       , SLOT(slotEraserBrushOpacityToggled(bool)));
466

467
    connect(m_presetsEditor->editorWidget(), SIGNAL(createPresetFromScratch(QString)), this, SLOT(slotCreatePresetFromScratch(QString)));
468

469
470
    connect(m_presetsChooserPopup, SIGNAL(resourceSelected(KoResourceSP ))      , SLOT(resourceSelected(KoResourceSP )));
    connect(m_presetsChooserPopup, SIGNAL(resourceClicked(KoResourceSP ))      , SLOT(resourceSelected(KoResourceSP )));
471

472
    connect(m_resourceProvider   , SIGNAL(sigNodeChanged(KisNodeSP))    , SLOT(slotNodeChanged(KisNodeSP)));
Halla Rempt's avatar
Halla Rempt committed
473
    connect(m_cmbCompositeOp     , SIGNAL(currentIndexChanged(int))           , SLOT(slotSetCompositeMode(int)));
474
475
    connect(m_eraseAction          , SIGNAL(toggled(bool))                    , SLOT(slotToggleEraseMode(bool)));
    connect(alphaLockAction      , SIGNAL(toggled(bool))                    , SLOT(slotToggleAlphaLockMode(bool)));
476

477
478
    m_disablePressureAction = m_viewManager->actionManager()->createAction("disable_pressure");
    connect(m_disablePressureAction  , SIGNAL(toggled(bool))                    , SLOT(slotDisablePressureMode(bool)));
479
    m_disablePressureAction->setChecked(true);
480

481
482
    connect(m_hMirrorAction        , SIGNAL(toggled(bool))                    , SLOT(slotHorizontalMirrorChanged(bool)));
    connect(m_vMirrorAction        , SIGNAL(toggled(bool))                    , SLOT(slotVerticalMirrorChanged(bool)));
483
    connect(m_reloadAction         , SIGNAL(triggered())                        , SLOT(slotReloadPreset()));
484

485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
    connect(m_sliderChooser[0]->getWidget<KisDoubleSliderSpinBox>("opacity")               , SIGNAL(valueChanged(qreal)), SLOT(slotSlider1Changed()));
    connect(m_sliderChooser[0]->getWidget<KisDoubleSliderSpinBox>("flow")                  , SIGNAL(valueChanged(qreal)), SLOT(slotSlider1Changed()));
    connect(m_sliderChooser[0]->getWidget<KisDoubleSliderSpinBox>("size")                  , SIGNAL(valueChanged(qreal)), SLOT(slotSlider1Changed()));
    connect(m_sliderChooser[0]->getWidget<KisMultipliersDoubleSliderSpinBox>("patternsize"), SIGNAL(valueChanged(qreal)), SLOT(slotSlider1Changed()));
    connect(m_sliderChooser[1]->getWidget<KisDoubleSliderSpinBox>("opacity")               , SIGNAL(valueChanged(qreal)), SLOT(slotSlider2Changed()));
    connect(m_sliderChooser[1]->getWidget<KisDoubleSliderSpinBox>("flow")                  , SIGNAL(valueChanged(qreal)), SLOT(slotSlider2Changed()));
    connect(m_sliderChooser[1]->getWidget<KisDoubleSliderSpinBox>("size")                  , SIGNAL(valueChanged(qreal)), SLOT(slotSlider2Changed()));
    connect(m_sliderChooser[1]->getWidget<KisMultipliersDoubleSliderSpinBox>("patternsize"), SIGNAL(valueChanged(qreal)), SLOT(slotSlider2Changed()));
    connect(m_sliderChooser[2]->getWidget<KisDoubleSliderSpinBox>("opacity")               , SIGNAL(valueChanged(qreal)), SLOT(slotSlider3Changed()));
    connect(m_sliderChooser[2]->getWidget<KisDoubleSliderSpinBox>("flow")                  , SIGNAL(valueChanged(qreal)), SLOT(slotSlider3Changed()));
    connect(m_sliderChooser[2]->getWidget<KisDoubleSliderSpinBox>("size")                  , SIGNAL(valueChanged(qreal)), SLOT(slotSlider3Changed()));
    connect(m_sliderChooser[2]->getWidget<KisMultipliersDoubleSliderSpinBox>("patternsize"), SIGNAL(valueChanged(qreal)), SLOT(slotSlider3Changed()));
    connect(m_sliderChooser[3]->getWidget<KisDoubleSliderSpinBox>("opacity")               , SIGNAL(valueChanged(qreal)), SLOT(slotSlider4Changed()));
    connect(m_sliderChooser[3]->getWidget<KisDoubleSliderSpinBox>("flow")                  , SIGNAL(valueChanged(qreal)), SLOT(slotSlider4Changed()));
    connect(m_sliderChooser[3]->getWidget<KisDoubleSliderSpinBox>("size")                  , SIGNAL(valueChanged(qreal)), SLOT(slotSlider4Changed()));
    connect(m_sliderChooser[3]->getWidget<KisMultipliersDoubleSliderSpinBox>("patternsize"), SIGNAL(valueChanged(qreal)), SLOT(slotSlider4Changed()));
Sven Langkamp's avatar
Sven Langkamp committed
501

502
    connect(m_resourceProvider, SIGNAL(sigFGColorUsed(KoColor)), m_favoriteResourceManager, SLOT(slotAddRecentColor(KoColor)));
503

504
    connect(m_resourceProvider, SIGNAL(sigFGColorChanged(KoColor)), m_favoriteResourceManager, SLOT(slotChangeFGColorSelector(KoColor)));
505
    connect(m_resourceProvider, SIGNAL(sigBGColorChanged(KoColor)), m_favoriteResourceManager, SLOT(slotSetBGColor(KoColor)));
Halla Rempt's avatar
Halla Rempt committed
506

507
508
509
510
    // cold initialization
    m_favoriteResourceManager->slotChangeFGColorSelector(m_resourceProvider->fgColor());
    m_favoriteResourceManager->slotSetBGColor(m_resourceProvider->bgColor());

511
    connect(m_favoriteResourceManager, SIGNAL(sigSetFGColor(KoColor)), m_resourceProvider, SLOT(slotSetFGColor(KoColor)));
512
    connect(m_favoriteResourceManager, SIGNAL(sigSetBGColor(KoColor)), m_resourceProvider, SLOT(slotSetBGColor(KoColor)));
513

514
    connect(viewManager->mainWindow(), SIGNAL(themeChanged()), this, SLOT(slotUpdateSelectionIcon()));
515
516
    connect(m_resourceProvider->resourceManager(), SIGNAL(canvasResourceChanged(int,QVariant)),
            this, SLOT(slotCanvasResourceChanged(int,QVariant)));
517
518
    connect(m_resourceProvider->resourceManager(), SIGNAL(canvasResourceChangeAttempted(int,QVariant)),
            this, SLOT(slotCanvasResourceChangeAttempted(int,QVariant)));
519

520
    slotInputDeviceChanged(KoToolManager::instance()->currentInputDevice());
521

522
    findDefaultPresets();
523
}
524

525

526
527
KisPaintopBox::~KisPaintopBox()
{
528
    KisConfig cfg(false);
529
530
531
532
    QMapIterator<TabletToolID, TabletToolData> iter(m_tabletToolMap);
    while (iter.hasNext()) {
        iter.next();
        if ((iter.key().pointer) == QTabletEvent::Eraser) {
533
            cfg.writeEntry(QString("LastEraser_%1").arg(iter.key().uniqueTabletId), iter.value().preset->name());
534
535
        }
        else {
536
            cfg.writeEntry(QString("LastPreset_%1").arg(iter.key().uniqueTabletId), iter.value().preset->name());
537
538
        }
    }
luz paz's avatar
luz paz committed
539
    // Do not delete the widget, since it is global to the application, not owned by the view
540
    m_presetsEditor->editorWidget()->setPaintOpSettingsWidget(0);
541
    qDeleteAll(m_paintopOptionWidgets);
542
    delete m_favoriteResourceManager;
543
544
545
546

    for (int i = 0; i < 3; ++i) {
        delete m_sliderChooser[i];
    }
547
}
Halla Rempt's avatar
Halla Rempt committed
548

549
void KisPaintopBox::restoreResource(KoResourceSP resource)
550
{
551
    KisPaintOpPresetSP preset = resource.dynamicCast<KisPaintOpPreset>();
552

553
    if (preset) {
554
        setCurrentPaintop(preset);
555

556
557
        m_presetsEditor->editorWidget()->setPresetImage(preset->image());
        m_presetsEditor->editorWidget()->resourceSelected(resource);
558
559
560
    }
}

561
562
563
564
565
566
567
void KisPaintopBox::newOptionWidgets(const QList<QPointer<QWidget> > &optionWidgetList)
{
    if (m_toolOptionsPopup) {
        m_toolOptionsPopup->newOptionWidgets(optionWidgetList);
    }
}

568
void KisPaintopBox::resourceSelected(KoResourceSP resource)
569
{
570
571
572
573
574
575
    // This happens if no storages were available on startup
    if (!m_optionWidget) {
        KisPaintOpPresetSP preset = resource.dynamicCast<KisPaintOpPreset>();
        setCurrentPaintop(preset);
        return;
    }
576

577
    m_presetsEditor->editorWidget()->setCreatingBrushFromScratch(false); // show normal UI elements when we are not creating
578

579
    KisPaintOpPresetSP preset = resource.dynamicCast<KisPaintOpPreset>();
580
581

    if (preset && preset->valid() && preset != m_resourceProvider->currentPreset()) {
582
583
584
585
586
587
588
        if (!m_dirtyPresetsEnabled) {
            KisSignalsBlocker blocker(m_optionWidget);
            Q_UNUSED(blocker);

            KisPaintOpPresetResourceServer *rserver = KisResourceServerProvider::instance()->paintOpPresetServer();

            if (!rserver->reloadResource(preset)) {
589
                qWarning() << "failed to reload the preset.";
590
591
592
            }
        }

593
        dbgResources << "resourceSelected: preset" << preset << (preset ? QString("%1").arg(preset->valid()) : "");
594
595
        setCurrentPaintop(preset);

596
597
        m_presetsEditor->editorWidget()->setPresetImage(preset->image());
        m_presetsEditor->editorWidget()->resourceSelected(resource);
Halla Rempt's avatar
Halla Rempt committed
598
    }
599
600
}

601
void KisPaintopBox::setCurrentPaintop(const KoID& paintop)
602
{
603
604
605
    KisPaintOpPresetSP preset = activePreset(paintop);
    Q_ASSERT(preset && preset->settings());
    setCurrentPaintop(preset);
606
607
}

608
void KisPaintopBox::setCurrentPaintop(KisPaintOpPresetSP preset)
609
{
610
    if (preset == m_resourceProvider->currentPreset()) {
611
612
613
614

        if (preset == m_tabletToolMap[m_currTabletToolID].preset) {
            return;
        }
615
616
617
    }
    Q_ASSERT(preset);
    const KoID& paintop = preset->paintOp();
618
619
    m_presetConnections.clear();

620
    if (m_resourceProvider->currentPreset()) {
621

622
        m_resourceProvider->setPreviousPaintOpPreset(m_resourceProvider->currentPreset());
623
624

        if (m_optionWidget) {
625
626
            m_optionWidget->hide();
        }
627

628
629
    }

630
    if (!m_paintopOptionWidgets.contains(paintop)) {
631
        m_paintopOptionWidgets[paintop] = KisPaintOpRegistry::instance()->get(paintop.id())->createConfigWidget(this);
632
633
634
        m_paintopOptionWidgets[paintop]->setResourcesInterface(KisGlobalResourcesInterface::instance());
        m_paintopOptionWidgets[paintop]->setCanvasResourcesInterface(m_viewManager->canvasResourceProvider()->resourceManager()->canvasResourcesInterface());
    }
635

636
    m_optionWidget = m_paintopOptionWidgets[paintop];
637

638
639
    KisSignalsBlocker b(m_optionWidget);

640
    preset->setOptionsWidget(m_optionWidget);
641

Halla Rempt's avatar
Halla Rempt committed
642
643
    m_optionWidget->setImage(m_viewManager->image());
    m_optionWidget->setNode(m_viewManager->activeNode());
644

645
    m_presetsEditor->editorWidget()->setPaintOpSettingsWidget(m_optionWidget);
646

647
648
    m_resourceProvider->setPaintOpPreset(preset);

649
    Q_ASSERT(m_optionWidget && m_presetSelectorPopupButton);
650

651
    m_presetConnections.addConnection(m_optionWidget, SIGNAL(sigConfigurationUpdated()), this, SLOT(slotGuiChangedCurrentPreset()));
652
653
    m_presetConnections.addConnection(m_optionWidget, SIGNAL(sigSaveLockedConfig(KisPropertiesConfigurationSP)), this, SLOT(slotSaveLockedOptionToPreset(KisPropertiesConfigurationSP)));
    m_presetConnections.addConnection(m_optionWidget, SIGNAL(sigDropLockedConfig(KisPropertiesConfigurationSP)), this, SLOT(slotDropLockedOption(KisPropertiesConfigurationSP)));
654

655

656
657
    // load the current preset icon to the preset selector toolbar button
    m_presetSelectorPopupButton->setThumbnail(preset->image());
658
    m_presetsEditor->editorWidget()->setCurrentPaintOpId(paintop.id());
659

660

661
    //o() << "\tsetting the new preset for" << m_currTabletToolID.uniqueID << "to" << preset->name();
662
663
664
665
666
    m_paintOpPresetMap[m_resourceProvider->currentPreset()->paintOp()] = preset;
    m_tabletToolMap[m_currTabletToolID].preset = preset;
    m_tabletToolMap[m_currTabletToolID].paintOpID = preset->paintOp();


667
    if (m_presetsEditor->editorWidget()->currentPaintOpId() != paintop.id()) {
668
669
        // Must change the paintop as the current one is not supported
        // by the new colorspace.
Halla Rempt's avatar
Halla Rempt committed
670
        dbgKrita << "current paintop " << paintop.name() << " was not set, not supported by colorspace";
671
    }
672
673
674

    m_currCompositeOpID = preset->settings()->paintOpCompositeOp();
    updateCompositeOp(m_currCompositeOpID);
675
676
677
678
679
680
681
682

    if (preset->settings()->hasPatternSettings()) {
        setMultiplierSliderValue("patternsize", preset->settings()->paintOpPatternSize());
        setWidgetState(ENABLE_PATTERNSIZE);
    }
    else {
        setWidgetState(DISABLE_PATTERNSIZE);
    }
683
684
}

685
void KisPaintopBox::slotUpdateOptionsWidgetPopup()
686
687
{
    KisPaintOpPresetSP preset = m_resourceProvider->currentPreset();
688
689
690
691

    // This happens when we have a new brush engine for which no default preset exists yet.
    if (!preset) return;

692
693
694
    KIS_SAFE_ASSERT_RECOVER_RETURN(preset);
    KIS_SAFE_ASSERT_RECOVER_RETURN(m_optionWidget);

695
    m_optionWidget->setConfigurationSafe(preset->settings());
696

697
698
    m_presetsEditor->editorWidget()->resourceSelected(preset);
    m_presetsEditor->editorWidget()->updateViewSettings();
699
700
701
702

    // the m_viewManager->image() is set earlier, but the reference will be missing when the stamp button is pressed
    // need to later do some research on how and when we should be using weak shared pointers (WSP) that creates this situation
    m_optionWidget->setImage(m_viewManager->image());
703
704
}

705
KisPaintOpPresetSP KisPaintopBox::defaultPreset(const KoID& paintOp)
706
{
707
708
    QString path = ":/presets/" + paintOp.id() + ".kpp";
    dbgResources << "Getting default presets from qrc resources" << path;
709