diff --git a/libs/ui/CMakeLists.txt b/libs/ui/CMakeLists.txt
--- a/libs/ui/CMakeLists.txt
+++ b/libs/ui/CMakeLists.txt
@@ -252,6 +252,7 @@
widgets/kis_stopgradient_slider_widget.cpp
widgets/kis_spinbox_color_selector.cpp
widgets/kis_screen_color_picker.cpp
+ widgets/kis_preset_live_preview_view.cpp
widgets/KoDualColorButton.cpp
widgets/kis_color_input.cpp
widgets/kis_color_button.cpp
@@ -264,6 +265,7 @@
widgets/KoFillConfigWidget.cpp
widgets/KoShapeFillWrapper.cpp
+
utils/kis_document_aware_spin_box_unit_manager.cpp
input/kis_input_manager.cpp
diff --git a/libs/ui/forms/wdgpaintopsettings.ui b/libs/ui/forms/wdgpaintopsettings.ui
--- a/libs/ui/forms/wdgpaintopsettings.ui
+++ b/libs/ui/forms/wdgpaintopsettings.ui
@@ -6,367 +6,21 @@
0
0
- 1431
- 512
+ 1441
+ 495
Brush Editor
-
- 3
-
-
- 3
-
-
- 3
-
-
- 3
-
-
- 3
-
-
- 5
-
- -
-
-
-
-
-
- false
-
-
-
- 0
-
-
- 3
-
-
- 1
-
-
- 3
-
-
- 3
-
-
-
-
-
-
- 0
- 4
-
-
-
-
- 120
- 0
-
-
-
- QFrame::NoFrame
-
-
- QFrame::Plain
-
-
- 0
-
-
-
- -
-
-
- 5
-
-
- 5
-
-
- 0
-
-
- 5
-
-
- 5
-
-
-
-
-
-
- 0
- 0
-
-
-
- Erase mode will use a separate brush size
-
-
- Eraser switch size
-
-
- false
-
-
-
- -
-
-
-
- 0
- 0
-
-
-
- Temporarily Save Tweaks To Presets
-
-
- true
-
-
-
- -
-
-
-
- 0
- 0
-
-
-
- Erase mode will use a separate brush opacity
-
-
- Eraser switch opacity
-
-
- false
-
-
-
- -
-
-
- Qt::Horizontal
-
-
-
- 40
- 20
-
-
-
-
- -
-
-
-
- 60
- 0
-
-
-
-
-
-
- -
-
-
- 5
-
-
- 5
-
-
- 0
-
-
- 5
-
-
- 0
-
-
-
-
-
-
- 0
- 0
-
-
-
- Load Engine Defaults
-
-
-
- -
-
-
- Qt::Horizontal
-
-
-
- 40
- 20
-
-
-
-
- -
-
-
- Overwrite Brush
-
-
-
- -
-
-
- Save New Brush Preset...
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
- false
-
-
-
- 5
-
-
- 5
-
-
- 5
-
-
- 5
-
-
- 5
-
-
-
-
-
- QFrame::NoFrame
-
-
- QFrame::Plain
-
-
- 0
-
-
-
- 0
-
-
- 0
-
-
- 0
-
-
- 0
-
-
- 0
-
-
-
-
-
-
- 0
- 0
-
-
-
-
- 250
- 300
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
- -
-
-
- Fill area with gradient
-
-
-
-
-
-
- -
-
-
- Fill area with background color
-
-
-
-
-
-
- -
-
-
- Reset area to white
-
-
-
-
-
-
-
-
-
-
-
-
- 10
+ 5
- 10
+ 1
-
@@ -378,14 +32,14 @@
- 30
- 30
+ 55
+ 55
- 30
- 30
+ 55
+ 55
@@ -408,107 +62,266 @@
false
+
+ Qt::AlignHCenter|Qt::AlignTop
+
QPainter::Antialiasing
-
-
- -
-
-
-
- 200
- 0
-
-
-
- Current Brush Name
-
-
- 0
-
-
- 5
+
+ QGraphicsView::AnchorViewCenter
-
-
-
-
- 0
- 0
-
-
-
-
+
+
+ 5
-
+
-
+
+
+
+ 0
+ 0
+
+
+
+
+ 32
+ 32
+
+
+
+
+ 32
+ 32
+
+
+
+
+
+
+
+ -
+
+
+
+ 0
+ 0
+
+
+
+
+ 32
+ 32
+
+
+
+
+ 32
+ 32
+
+
+
+
+
+
+
+
-
-
+
0
0
-
-
-
-
-
- -
-
-
-
- 0
- 0
-
+
+
+ 320
+ 60
+
- 50
- 16777215
+ 320
+ 60
-
-
+
+
+ false
+
+
+
+ QFrame::StyledPanel
+
+
+ QFrame::Raised
+
+
+ 0
+
+
+ Qt::ScrollBarAlwaysOff
-
+
+ Qt::ScrollBarAlwaysOff
+
+
true
-
-
- -
-
-
-
- 250
- 0
-
+
+ QPainter::Antialiasing|QPainter::HighQualityAntialiasing|QPainter::SmoothPixmapTransform
+
+
+ QGraphicsView::AnchorViewCenter
-
-
-
-
- 0
- 0
-
+
+
+ 0
-
- Save
+
+ 5
-
+
-
+
+
+
+ 0
+ 0
+
+
+
+
+ 150
+ 0
+
+
+
+
+ 16777215
+ 20
+
+
+
+
+ 10
+ 75
+ true
+
+
+
+ 0
+
+
+ Current Brush Name
+
+
+ false
+
+
+ Qt::AlignBottom|Qt::AlignLeading|Qt::AlignLeft
+
+
+ 0
+
+
+ 5
+
+
+
+ -
+
+
+
+ 0
+ 0
+
+
+
+
+ 16777215
+ 20
+
+
+
+ Current Brush Engine
+
+
+ false
+
+
+ Qt::AlignLeading|Qt::AlignLeft|Qt::AlignTop
+
+
+ 5
+
+
+
+
-
-
-
- Cancel
-
-
+
+
-
+
+
+
+ 0
+ 0
+
+
+
+
+ 32
+ 32
+
+
+
+
+ 32
+ 32
+
+
+
+
+
+
+ false
+
+
+
+ -
+
+
+
+ 0
+ 0
+
+
+
+
+ 32
+ 32
+
+
+
+
+ 32
+ 32
+
+
+
+
+
+
+
+
-
@@ -531,64 +344,86 @@
-
-
-
-
- 0
- 0
-
-
-
-
- 35
- 20
-
-
-
- Presets
-
-
-
- -
-
-
-
- 0
- 0
-
-
-
-
- 35
- 30
-
-
-
- Settings
-
-
-
- -
-
-
-
- 0
- 0
-
-
-
-
- 35
- 30
-
-
-
- Scratchpad
-
-
- true
-
-
+
+
-
+
+
+
+ 0
+ 0
+
+
+
+
+ 35
+ 20
+
+
+
+
+ 16777215
+ 20
+
+
+
+ Presets
+
+
+
+ -
+
+
+
+ 0
+ 0
+
+
+
+
+ 35
+ 20
+
+
+
+
+ 16777215
+ 20
+
+
+
+ Settings
+
+
+
+ -
+
+
+
+ 0
+ 0
+
+
+
+
+ 35
+ 20
+
+
+
+
+ 16777215
+ 20
+
+
+
+ Scratchpad
+
+
+ true
+
+
+
+
@@ -614,9 +449,238 @@
5
-
-
+
+
-
+
+
+
+ 0
+ 0
+
+
+
+ Engine:
+
+
+
+ -
+
+
+
+ 0
+ 0
+
+
+
+
+ -
+
+
+
+ 0
+ 0
+
+
+
+
+
+
+
+
+
+ -
+
+
+
+ 0
+ 0
+
+
+
+
+ 0
+ 350
+
+
+
+
+ 1677215
+ 1677215
+
+
+
+
+
+
+
+ -
+
+
+
+
+
+ false
+
+
+
+ 0
+
+
+ 3
+
+
+ 1
+
+
+ 3
+
+
+ 3
+
+
-
+
+
+
+ 0
+ 4
+
+
+
+
+ 120
+ 0
+
+
+
+ QFrame::NoFrame
+
+
+ QFrame::Plain
+
+
+ 0
+
+
+
+ -
+
+
+ 5
+
+
+ 5
+
+
+ 0
+
+
+ 5
+
+
+ 5
+
+
-
+
+
+
+ 0
+ 0
+
+
+
+ Erase mode will use a separate brush size
+
+
+ Eraser switch size
+
+
+ false
+
+
+
+ -
+
+
+
+ 0
+ 0
+
+
+
+ Temporarily Save Tweaks To Presets
+
+
+ true
+
+
+
+ -
+
+
+
+ 0
+ 0
+
+
+
+ Erase mode will use a separate brush opacity
+
+
+ Eraser switch opacity
+
+
+ false
+
+
+
+ -
+
+
+ Qt::Horizontal
+
+
+
+ 40
+ 20
+
+
+
+
+ -
+
+
+
+ 60
+ 0
+
+
+
+
+
+
+ -
+
+
+ 5
+
+
+ 5
+
+
+ 0
+
+
+ 5
+
+
+ 0
+
+
+
+ -
+
-
-
+
0
@@ -624,64 +688,207 @@
- Engine:
+ Load Engine Defaults
-
-
+
-
+
0
0
+
+ Rename
+
-
-
+
+
+
+ 250
+ 0
+
+
+
+
+ -
+
-
+
0
0
-
+ Save
+
+
+
+ -
+
+
+ Cancel
+
+
+
+ -
+
+
+ Qt::Horizontal
+
+
+
+ 40
+ 20
+
+
+
+
+ -
+
+
+ Overwrite Brush
+
+
+
+ -
+
+
+ Save New Brush Preset...
+
+
+
+ -
+
+
+
+
+
+ false
+
+
+
+ 5
+
+
+ 5
+
+
+ 5
+
+
+ 5
+
+
+ 5
+
-
-
-
-
- 0
- 0
-
+
+
+ QFrame::NoFrame
-
-
- 0
- 350
-
+
+ QFrame::Plain
-
-
- 1677215
- 1677215
-
+
+ 0
+
+
+ 0
+
+
+ 0
+
+
+ 0
+
+
+ 0
+
+
+ 0
+
+
-
+
+
+
+ 0
+ 0
+
+
+
+
+ 250
+ 300
+
+
+
+
+
+ -
+
+
-
+
+
+
+
+
+
+ -
+
+
+
+
+
+
+ -
+
+
+ Fill area with gradient
+
+
+
+
+
+
+ -
+
+
+ Fill area with background color
+
+
+
+
+
+
+ -
+
+
+ Reset area to white
+
+
+
+
+
+
+
+
- presetsContainer
- brushEditorSettingsControls
- scratchpadControls
@@ -691,6 +898,12 @@
1
+ KisPresetLivePreviewView
+ QGraphicsView
+ kis_preset_live_preview_view.h
+ 1
+
+
KisPresetSelectorStrip
QWidget
kis_preset_selector_strip.h
diff --git a/libs/ui/widgets/kis_paintop_presets_popup.cpp b/libs/ui/widgets/kis_paintop_presets_popup.cpp
--- a/libs/ui/widgets/kis_paintop_presets_popup.cpp
+++ b/libs/ui/widgets/kis_paintop_presets_popup.cpp
@@ -56,10 +56,10 @@
#include "kis_signal_auto_connection.h"
#include
+
// ones from brush engine selector
#include
-
-
+#include
struct KisPaintOpPresetsPopup::Private
@@ -170,8 +170,6 @@
menu->addAction(sliderAction);
-
-
// configure the button and assign menu
m_d->uiWdgPaintOpPresetSettings.presetChangeViewToolButton->setMenu(menu);
m_d->uiWdgPaintOpPresetSettings.presetChangeViewToolButton->setIcon(KisIconUtils::loadIcon("view-choose"));
@@ -276,9 +274,6 @@
connect(m_d->uiWdgPaintOpPresetSettings.reloadPresetButton, SIGNAL(clicked()), SLOT(slotUpdatePresetSettings()));
-
-
-
m_d->detached = false;
m_d->ignoreHideEvents = false;
m_d->minimumSettingsWidgetSize = QSize(0, 0);
@@ -305,6 +300,20 @@
connect(m_d->uiWdgPaintOpPresetSettings.brushEgineComboBox, SIGNAL(currentIndexChanged(int)), this, SLOT(slotUpdatePaintOpFilter()));
+ // setup things like the scene construct images, layers, etc that is a one-time thing
+ m_d->uiWdgPaintOpPresetSettings.liveBrushPreviewView->setup();
+
+ m_d->uiWdgPaintOpPresetSettings.zoomOutGraphicsViewButton->setIcon(KisIconUtils::loadIcon("view-fullscreen"));
+ connect(m_d->uiWdgPaintOpPresetSettings.zoomOutGraphicsViewButton, SIGNAL(clicked(bool)),
+ m_d->uiWdgPaintOpPresetSettings.liveBrushPreviewView,
+ SLOT(slotZoomToOneHundredPercent()));
+
+
+ m_d->uiWdgPaintOpPresetSettings.resetGraphicsViewButton->setIcon(KisIconUtils::loadIcon("view-refresh"));
+ connect(m_d->uiWdgPaintOpPresetSettings.resetGraphicsViewButton, SIGNAL(clicked(bool)),
+ m_d->uiWdgPaintOpPresetSettings.liveBrushPreviewView,
+ SLOT(slotResetViewZoom()));
+
}
@@ -323,8 +332,6 @@
// This function doesn't really do anything except get the UI in a state to rename a brush preset
m_d->uiWdgPaintOpPresetSettings.renameBrushPresetButton->setVisible(!isRenaming);
- m_d->uiWdgPaintOpPresetSettings.currentBrushNameLabel->setVisible(!isRenaming);
- m_d->uiWdgPaintOpPresetSettings.reloadPresetButton->setVisible(!isRenaming);
m_d->uiWdgPaintOpPresetSettings.renameBrushNameTextField->setVisible(isRenaming);
m_d->uiWdgPaintOpPresetSettings.updateBrushNameButton->setVisible(isRenaming);
@@ -332,6 +339,9 @@
m_d->uiWdgPaintOpPresetSettings.saveBrushPresetButton->setEnabled(!isRenaming);
m_d->uiWdgPaintOpPresetSettings.saveNewBrushPresetButton->setEnabled(!isRenaming);
+
+ m_d->uiWdgPaintOpPresetSettings.bnDefaultPreset->setVisible(!isRenaming);
+
}
void KisPaintOpPresetsPopup::slotSaveRenameCurrentBrush()
@@ -466,29 +476,6 @@
m_d->uiWdgPaintOpPresetSettings.wdgLodAvailability->setLimitations(l);
}
-
-void KisPaintOpPresetsPopup::slotUpdatePresetSettings()
-{
- if (!m_d->resourceProvider) {
- return;
- }
- if (!m_d->resourceProvider->currentPreset()) {
- return;
- }
-
-
- bool isPresetDirty = m_d->resourceProvider->currentPreset()->isPresetDirty();
-
- // don't need to reload or overwrite a clean preset
- m_d->uiWdgPaintOpPresetSettings.dirtyPresetIndicatorButton->setVisible(isPresetDirty);
- m_d->uiWdgPaintOpPresetSettings.reloadPresetButton->setVisible(isPresetDirty);
- m_d->uiWdgPaintOpPresetSettings.saveBrushPresetButton->setEnabled(isPresetDirty);
-
-
-
-}
-
-
QImage KisPaintOpPresetsPopup::cutOutOverlay()
{
return m_d->uiWdgPaintOpPresetSettings.scratchPad->cutoutOverlay();
@@ -556,16 +543,17 @@
}
}
- QString selectedBrush = resource->name().append(" (").append(currentBrushEngineName).append(" ").append("Engine").append(")");
+ QString selectedBrush = resource->name();
m_d->uiWdgPaintOpPresetSettings.currentBrushNameLabel->setText(selectedBrush);
+ m_d->uiWdgPaintOpPresetSettings.currentBrushEngineLabel->setText(currentBrushEngineName.append(" ").append("Engine"));
m_d->uiWdgPaintOpPresetSettings.renameBrushNameTextField->setText(resource->name());
// get the preset image and pop it into the thumbnail area on the top of the brush editor
QGraphicsScene * thumbScene = new QGraphicsScene(this);
- thumbScene->addPixmap(QPixmap::fromImage(resource->image().scaled(30, 30)));
- thumbScene->setSceneRect(0, 0, 30, 30); // 30 x 30 image for thumb. this is also set in the UI
+ thumbScene->addPixmap(QPixmap::fromImage(resource->image().scaled(55, 55)));
+ thumbScene->setSceneRect(0, 0, 55, 55); // 55 x 55 image for thumb. this is also set in the UI
m_d->uiWdgPaintOpPresetSettings.presetThumbnailicon->setScene(thumbScene);
toggleBrushRenameUIActive(false); // reset the UI state of renaming a brush if we are changing brush presets
@@ -762,3 +750,25 @@
m_d->uiWdgPaintOpPresetSettings.eraseScratchPad->setIcon(KisIconUtils::loadIcon("edit-delete"));
m_d->uiWdgPaintOpPresetSettings.presetChangeViewToolButton->setIcon(KisIconUtils::loadIcon("view-choose"));
}
+
+void KisPaintOpPresetsPopup::slotUpdatePresetSettings()
+{
+ if (!m_d->resourceProvider) {
+ return;
+ }
+ if (!m_d->resourceProvider->currentPreset()) {
+ return;
+ }
+
+ bool isPresetDirty = m_d->resourceProvider->currentPreset()->isPresetDirty();
+
+ // don't need to reload or overwrite a clean preset
+ m_d->uiWdgPaintOpPresetSettings.dirtyPresetIndicatorButton->setVisible(isPresetDirty);
+ m_d->uiWdgPaintOpPresetSettings.reloadPresetButton->setVisible(isPresetDirty);
+ m_d->uiWdgPaintOpPresetSettings.saveBrushPresetButton->setEnabled(isPresetDirty);
+
+
+ // update live preview area in here...
+ m_d->uiWdgPaintOpPresetSettings.liveBrushPreviewView->setCurrentPreset(m_d->resourceProvider->currentPreset());
+ m_d->uiWdgPaintOpPresetSettings.liveBrushPreviewView->updateStroke();
+}
diff --git a/libs/ui/widgets/kis_preset_live_preview_view.h b/libs/ui/widgets/kis_preset_live_preview_view.h
new file mode 100644
--- /dev/null
+++ b/libs/ui/widgets/kis_preset_live_preview_view.h
@@ -0,0 +1,177 @@
+/*
+ * Copyright (c) 2017 Scott Petrovic
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+#ifndef _KIS_PRESET_LIVE_PREVIEW_
+#define _KIS_PRESET_LIVE_PREVIEW_
+
+#include
+#include
+#include
+#include
+#include
+
+#include "kis_paintop_preset.h"
+#include "KoColorSpaceRegistry.h"
+#include "kis_paint_layer.h"
+#include "kis_painter.h"
+#include "kis_distance_information.h"
+#include "kis_painting_information_builder.h"
+#include
+#include
+
+/**
+ * Widget for displaying a live brush preview of your
+ * selected brush. It listens for signalsetting changes
+ * that the brush preset outputs and updates the preview
+ * accordingly. This class can be added to a UI file
+ * similar to how a QGraphicsView is added
+ */
+class KisPresetLivePreviewView : public QGraphicsView
+{
+ Q_OBJECT
+
+
+public:
+
+ KisPresetLivePreviewView(QWidget *parent);
+ ~KisPresetLivePreviewView();
+
+ /**
+ * @brief one time setup for initialization of many variables.
+ * This live preview might be in a UI file, so make sure to
+ * call this before starting to use it
+ */
+ void setup();
+
+ /**
+ * @brief set the current preset from resource manager for the live preview to use.
+ * Good to call this every stroke update in case the preset has changed
+ * @param the current preset from the resource manager
+ */
+ void setCurrentPreset(KisPaintOpPresetSP preset);
+ void updateStroke();
+
+
+public Q_SLOTS:
+ /**
+ * @brief scales the view to fit the brush stroke and moves it back to the center position
+ */
+ void slotResetViewZoom();
+
+ /**
+ * @brief sets the zoom level to full size to get a close up of larger brushes
+ */
+ void slotZoomToOneHundredPercent();
+
+
+
+private:
+
+ /// internally sets the image area for brush preview
+ KisImageSP m_image;
+
+ /// internally sets the layer area for brush preview
+ KisLayerSP m_layer;
+
+ /// internally sets the color space for brush preview
+ const KoColorSpace *m_colorSpace;
+
+ /// painter that actually paints the stroke
+ KisPainter *m_brushPreviewPainter;
+
+ /// the scene that can add items like text and the brush stroke image
+ QGraphicsScene *m_brushPreviewScene;
+
+ /// holds the preview brush stroke data
+ QGraphicsPixmapItem *m_sceneImageItem;
+
+ /// holds the 'no preview available' text object
+ QGraphicsTextItem *m_noPreviewText;
+
+ /// holds the width and height of the image of the brush preview
+ /// Probably can later add set functions to make this customizable
+ /// It is hard-coded to 1200 x 400 for right now for image size
+ QRect m_canvasSize;
+
+ /// convenience variable used internally when positioning the objects
+ /// and points in the scene
+ QPointF m_canvasCenterPoint;
+
+ /// internal variables for constructing the stroke start and end shape
+ /// there are two points that construct the "S" curve with this
+ QPen m_penSettings;
+ KisDistanceInformation m_currentDistance;
+ QPointF m_startPoint;
+ QPointF m_endPoint;
+ KisPaintInformation m_pi1;
+ KisPaintInformation m_pi2;
+ KisPaintInformation m_paintDabStart;
+ KisPaintInformation m_paintDabEnd;
+
+ QPainterPath m_curvedLine;
+ KisPaintInformation m_curvePointPI1;
+ KisPaintInformation m_curvePointPI2;
+
+ /// internally stores the current preset.
+ /// See setCurrentPreset(KisPaintOpPresetSP preset)
+ /// for setting this externally
+ KisPaintOpPresetSP m_currentPreset;
+
+ /// holds the current zoom(scale) level of scene
+ float m_scaleFactor;
+
+ /// internal reference for internal brush size
+ /// used to check if our brush size has changed
+ /// do zooming and other things internall if it has changed
+ float m_currentBrushSize = 1.0;
+
+ /// the range of brush sizes that will control zooming in/out
+ const float m_minBrushVal = 10.0;
+ const float m_maxBrushVal = 100.0;
+
+ /// range of scale values. 1.0 == 100%
+ const qreal m_minScale = 1.0;
+ const qreal m_maxScale = 0.3;
+
+ /// multiplier that is used for lengthening the brush stroke points
+ const float m_minStrokeScale = 0.4; // for smaller brush stroke
+ const float m_maxStrokeScale = 1.0; // for larger brush stroke
+
+
+ /**
+ * @brief reads the brush size and scales the view out to fit it
+ * used internally when resetting the views or changing brush sizes
+ */
+ void zoomToBrushSize();
+
+ /**
+ * @brief works as both clearing the previous stroke, providing
+ * striped backgrounds for smudging brushes, and text if there is no preview
+ */
+ void paintBackground();
+
+ /**
+ * @brief creates and performs the actual stroke that goes on top of the background
+ * this is internally and should always be called after the paintBackground()
+ */
+ void setupAndPaintStroke();
+
+
+};
+
+#endif
diff --git a/libs/ui/widgets/kis_preset_live_preview_view.cpp b/libs/ui/widgets/kis_preset_live_preview_view.cpp
new file mode 100644
--- /dev/null
+++ b/libs/ui/widgets/kis_preset_live_preview_view.cpp
@@ -0,0 +1,258 @@
+/*
+ * Copyright (c) 2017 Scott Petrovic
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+#include
+#include
+#include
+#include "kis_paintop_settings.h"
+
+KisPresetLivePreviewView::KisPresetLivePreviewView(QWidget *parent): QGraphicsView(parent)
+{
+
+}
+
+KisPresetLivePreviewView::~KisPresetLivePreviewView()
+{
+ delete m_brushPreviewPainter;
+ delete m_noPreviewText;
+ delete m_brushPreviewScene;
+}
+
+void KisPresetLivePreviewView::setup()
+{
+ // initializing to 0 helps check later if they actually have something in them
+ m_noPreviewText = 0;
+ m_sceneImageItem = 0;
+
+ setCursor(Qt::SizeAllCursor);
+
+ setHorizontalScrollBarPolicy ( Qt::ScrollBarAlwaysOff );
+ setVerticalScrollBarPolicy ( Qt::ScrollBarAlwaysOff );
+
+
+ // layer image needs to be big enough to get an entire stroke of data
+ m_canvasSize.setWidth(1200);
+ m_canvasSize.setHeight(400);
+
+ m_canvasCenterPoint.setX(m_canvasSize.width()*0.5);
+ m_canvasCenterPoint.setY(m_canvasSize.height()*0.5);
+
+ m_colorSpace = KoColorSpaceRegistry::instance()->rgb8();
+ m_image = new KisImage(0, m_canvasSize.width(), m_canvasSize.height(), m_colorSpace, "stroke sample image");
+
+
+ m_layer = new KisPaintLayer(m_image, "livePreviewStrokeSample", OPACITY_OPAQUE_U8, m_colorSpace);
+ m_brushPreviewPainter = new KisPainter(m_layer->paintDevice());
+
+ // set scene for the view
+ m_brushPreviewScene = new QGraphicsScene();
+ setScene(m_brushPreviewScene);
+
+ zoomToBrushSize();
+}
+
+void KisPresetLivePreviewView::setCurrentPreset(KisPaintOpPresetSP preset)
+{
+ m_currentPreset = preset;
+}
+
+void KisPresetLivePreviewView::updateStroke()
+{
+ paintBackground();
+
+ // do not paint a stroke if we are either of these two engines
+ if (m_currentPreset->paintOp().id() == "roundmarker" || m_currentPreset->paintOp().id() == "experimentbrush") {
+ return;
+ }
+
+ setupAndPaintStroke();
+
+
+ // crop the layer so a brush stroke won't go outside of the area
+ m_layer->paintDevice()->crop(0,0, m_layer->image()->width(), m_layer->image()->height());
+
+ QImage m_temp_image;
+ m_temp_image = m_layer->paintDevice()->convertToQImage(0);
+
+
+ // only add the object once...then just update the pixmap so we can move the preview around
+ if (!m_sceneImageItem) {
+ m_sceneImageItem = m_brushPreviewScene->addPixmap(QPixmap::fromImage(m_temp_image));
+ m_sceneImageItem->setFlag(QGraphicsItem::ItemIsSelectable);
+ m_sceneImageItem->setFlag(QGraphicsItem::ItemIsMovable);
+ m_sceneImageItem->setFlag(QGraphicsItem::ItemSendsGeometryChanges);
+ m_sceneImageItem->setPos(-m_canvasCenterPoint.x(), -m_canvasCenterPoint.y()); // center the object
+ } else {
+ m_sceneImageItem->setPixmap(QPixmap::fromImage(m_temp_image));
+ }
+
+}
+
+void KisPresetLivePreviewView::slotResetViewZoom()
+{
+ zoomToBrushSize();
+}
+
+void KisPresetLivePreviewView::slotZoomToOneHundredPercent()
+{
+ m_scaleFactor = 1.0;
+ resetMatrix();
+ this->scale(m_scaleFactor, m_scaleFactor);
+}
+
+void KisPresetLivePreviewView::paintBackground()
+{
+ // clean up "no preview" text object if it exists. we will add it later if we need it
+ if (m_noPreviewText) {
+ this->scene()->removeItem(m_noPreviewText);
+ m_noPreviewText = 0;
+ }
+
+
+ if (m_currentPreset->paintOp().id() == "colorsmudge" || m_currentPreset->paintOp().id() == "deformbrush") {
+
+ // easier to see deformations and smudging with alternating stripes in the background
+ // paint the whole background with alternating stripes
+ int grayStrips = 20;
+ for (int i=0; i < grayStrips; i++ ) {
+
+ float sectionPercent = 1.0 / (float)grayStrips;
+ bool isAlternating = i % 2;
+ KoColor fillColor;
+
+ if (isAlternating) {
+ fillColor.fromQColor(QColor(80,80,80));
+ } else {
+ fillColor.fromQColor(QColor(140,140,140));
+ }
+
+
+ m_brushPreviewPainter->fill(m_layer->image()->width()*sectionPercent*i,
+ 0,
+ m_layer->image()->width()*(sectionPercent*i +sectionPercent),
+ m_layer->image()->height(),
+ fillColor);
+
+ }
+
+ m_brushPreviewPainter->setPaintColor(KoColor(Qt::white, m_colorSpace));
+
+ }
+ else if (m_currentPreset->paintOp().id() == "roundmarker" || m_currentPreset->paintOp().id() == "experimentbrush"){
+ // cases where we will not show a preview for now
+ // roundbrush (quick) -- this isn't showing anything, disable showing preview
+ // experimentbrush -- this creates artifacts that carry over to other previews and messes up their display
+
+ if(m_sceneImageItem) {
+ this->scene()->removeItem(m_sceneImageItem);
+ m_sceneImageItem = 0;
+ }
+
+ QFont font;
+ font.setPixelSize(14);
+ font.setBold(false);
+
+ slotZoomToOneHundredPercent(); // 100% zoom if we are showing the text
+
+ m_noPreviewText = this->scene()->addText(i18n("No Preview for this engine"),font);
+ m_noPreviewText->setPos(-this->width()/3, -this->height()/4); // this mostly centers the text in the viewport
+
+ return;
+
+ }
+ else {
+
+ // fill with gray first to clear out what existed from previous preview
+ m_brushPreviewPainter->fill(0,0,
+ m_layer->image()->width(),
+ m_layer->image()->height(),
+ KoColor(palette().color(QPalette::Background) , m_colorSpace));
+
+ m_brushPreviewPainter->setPaintColor(KoColor(palette().color(QPalette::Text), m_colorSpace));
+ }
+}
+
+void KisPresetLivePreviewView::setupAndPaintStroke()
+{
+ // limit the brush stroke size. larger brush strokes just don't look good and are CPU intensive
+ // we are making a proxy preset and setting it to the painter...otherwise setting the brush size of the original preset
+ // will fire off signals that make this run in an infinite loop
+ qreal previewSize = qBound(1.0, m_currentPreset->settings()->paintOpSize(), 150.0 ); // constrain current brush size to these values
+ KisPaintOpPresetSP proxy_preset = m_currentPreset->clone();
+ proxy_preset->settings()->setPaintOpSize(previewSize);
+ m_brushPreviewPainter->setPaintOpPreset(proxy_preset, m_layer, m_image);
+
+
+ // we only need to change the zoom amount if we are changing the brush size
+ if (m_currentBrushSize != m_currentPreset->settings()->paintOpSize()) {
+ m_currentBrushSize = m_currentPreset->settings()->paintOpSize();
+ zoomToBrushSize();
+ }
+
+
+
+ // slope-intercept is good for mapping two values.
+ // find the slope of the line (slope-intercept form)
+ float slope = (m_maxScale-m_maxStrokeScale) / (m_minScale-m_minStrokeScale); // y2-y1 / x2-x1
+ float yIntercept = m_maxStrokeScale - slope * m_minStrokeScale; // y1 − m * x1
+
+ float strokeScaleAmount = m_scaleFactor * slope + yIntercept; // y = mx + b
+ strokeScaleAmount = qBound(m_minStrokeScale, strokeScaleAmount, m_maxStrokeScale);
+
+
+ // points for drawing an S curve
+ // we are going to paint the stroke right in the middle of the canvas to make sure
+ // everything is captured for big brush strokes
+ m_curvePointPI1.setPos(QPointF(m_canvasCenterPoint.x() - (this->width()*strokeScaleAmount),
+ m_canvasCenterPoint.y() + (this->height()*strokeScaleAmount)));
+ m_curvePointPI1.setPressure(0.0);
+
+ m_curvePointPI2.setPos(QPointF(m_canvasCenterPoint.x() + (this->width()*strokeScaleAmount),
+ m_canvasCenterPoint.y()));
+
+ m_curvePointPI2.setPressure(1.0);
+
+ m_brushPreviewPainter->paintBezierCurve(m_curvePointPI1,
+ QPointF(m_canvasCenterPoint.x(),
+ m_canvasCenterPoint.y()-this->height()),
+ QPointF(m_canvasCenterPoint.x(),
+ m_canvasCenterPoint.y()+this->height()),
+ m_curvePointPI2, &m_currentDistance);
+
+}
+
+void KisPresetLivePreviewView::zoomToBrushSize()
+{
+ // find the slope of the line (slope-intercept form)
+ float slope = (m_maxScale-m_minScale) / (m_maxBrushVal-m_minBrushVal); // y2-y1 / x2-x1
+ float yIntercept = m_minScale - slope * m_minBrushVal; // y1 − m * x1
+
+
+ // finally calculate our zoom level
+ float thresholdValue = qBound(m_minBrushVal, m_currentBrushSize, m_maxBrushVal);
+ m_scaleFactor = thresholdValue * slope + yIntercept; // y = mx + b
+
+ resetMatrix();
+ this->scale(m_scaleFactor,m_scaleFactor);
+
+ // reset position of image preview in case we moved it
+ if(m_sceneImageItem) {
+ m_sceneImageItem->setPos(-m_canvasSize.width()/2, -m_canvasSize.height()/2 );
+ }
+}
+