Commit 4fb3841a authored by Dmitry Kazakov's avatar Dmitry Kazakov
Browse files

A rewrite for the scratchpad

1) Now it shares all the code with the freehand tool completely. No
duplication.
2) Threading for stroke is possible even here.
3) Airbrushing works.
4) The scratchpad has the same zoom-level as the image
The bug can be closed when the branch is merged to master
CCBUG:273867
parent 284345b8
......@@ -162,6 +162,7 @@ set(kritaui_LIB_SRCS
widgets/kis_progress_widget.cpp
widgets/kis_selection_options.cc
widgets/kis_scratch_pad.cpp
widgets/kis_scratch_pad_event_filter.cpp
widgets/kis_preset_selector_strip.cpp
widgets/kis_tree_view_popup.cc
widgets/kis_slider_spin_box.cpp
......
......@@ -68,12 +68,12 @@ public: // KisAbstractCanvasWidget
*/
QColor borderColor() const;
protected:
/**
* Returns one check of the background checkerboard pattern.
*/
QImage checkImage(qint32 checkSize = -1);
static QImage checkImage(qint32 checkSize = -1);
protected:
KisCanvas2 *canvas() const;
KisCoordinatesConverter* coordinatesConverter();
......
......@@ -23,6 +23,8 @@
#include <QImage>
#include <kis_types.h>
#define BORDER_SIZE(scale) (ceil(scale * 2))
class KisImagePatch
{
......
......@@ -50,7 +50,6 @@
(scX < (value) - EPSILON && scY < (value) - EPSILON)
#define SCALE_MORE_OR_EQUAL_TO(scX, scY, value) \
(scX > (value) - EPSILON && scY > (value) - EPSILON)
#define BORDER_SIZE(scale) (ceil(scale * 2))
inline void copyQImageBuffer(uchar* dst, const uchar* src , qint32 deltaX, qint32 width)
{
......
......@@ -63,6 +63,11 @@ KisCanvasResourceProvider::~KisCanvasResourceProvider()
disconnect(); // in case Qt gets confused
}
KoResourceManager* KisCanvasResourceProvider::resourceManager()
{
return m_resourceManager;
}
void KisCanvasResourceProvider::setResourceManager(KoResourceManager *resourceManager)
{
m_resourceManager = resourceManager;
......@@ -266,6 +271,22 @@ void KisCanvasResourceProvider::slotSetDisplayProfile(const KoColorProfile * pro
emit sigDisplayProfileChanged(profile);
}
void KisCanvasResourceProvider::slotOnScreenResolutionChanged()
{
KisImageWSP image = m_view->image();
KisCanvas2 *canvas = m_view->canvasBase();
if(!image || !canvas) return;
qreal zoomX, zoomY;
canvas->coordinatesConverter()->zoom(&zoomX, &zoomY);
qreal scaleX = zoomX / image->xRes();
qreal scaleY = zoomY / image->yRes();
emit sigOnScreenResolutionChanged(scaleX, scaleY);
}
void KisCanvasResourceProvider::slotResourceChanged(int key, const QVariant & res)
{
if(key == KoCanvasResource::ForegroundColor || key == KoCanvasResource::BackgroundColor) {
......
......@@ -70,6 +70,7 @@ public:
~KisCanvasResourceProvider();
void setResourceManager(KoResourceManager *resourceManager);
KoResourceManager* resourceManager();
KoCanvasBase * canvas() const;
......@@ -131,9 +132,12 @@ public slots:
* Set the image size in pixels. The resource provider will store
* the image size in postscript points.
*/
// FIXME: this slot doesn't catch the case when image resolution is changed
void slotImageSizeChanged();
void slotSetDisplayProfile(const KoColorProfile * profile);
void slotOnScreenResolutionChanged();
// This is a flag to handle a bug:
// If pop up palette is visible and a new colour is selected, the new colour
// will be added when the user clicks on the canvas to hide the palette
......@@ -157,6 +161,7 @@ signals:
void sigGeneratorConfigurationChanged(KisFilterConfiguration * generatorConfiguration);
void sigFGColorUsed(const KoColor&);
void sigCompositeOpChanged(const QString &);
void sigOnScreenResolutionChanged(qreal scaleX, qreal scaleY);
private:
......
......@@ -314,7 +314,6 @@ void KisPaintopBox::setCurrentPaintop(const KoID& paintop, KisPaintOpPresetSP pr
preset->settings()->setNode(m_resourceProvider->currentNode());
m_presetsPopup->setPaintOpSettingsWidget(m_optionWidget);
m_presetsPopup->setPreset(preset);
m_presetsChooserPopup->setPresetFilter(paintop);
Q_ASSERT(m_optionWidget && m_presetWidget);
......
......@@ -728,6 +728,12 @@ void KisView2::connectCurrentImage()
}
connect(image(), SIGNAL(sigSizeChanged(qint32, qint32)), m_d->resourceProvider, SLOT(slotImageSizeChanged()));
connect(image(), SIGNAL(sigResolutionChanged(double, double)),
m_d->resourceProvider, SLOT(slotOnScreenResolutionChanged()));
connect(zoomManager()->zoomController(), SIGNAL(zoomChanged(KoZoomMode::Mode, qreal)),
m_d->resourceProvider, SLOT(slotOnScreenResolutionChanged()));
connect(image(), SIGNAL(sigSizeChanged(qint32, qint32)), this, SLOT(slotImageSizeChanged()));
connect(image(), SIGNAL(sigResolutionChanged(double, double)), this, SLOT(slotImageSizeChanged()));
connect(image()->undoAdapter(), SIGNAL(selectionChanged()), selectionManager(), SLOT(selectionChanged()));
......
......@@ -62,16 +62,15 @@ int main(int argc, char** argv)
KisPaintOpPresetSP preset = new KisPaintOpPreset(fileName);
preset->load();
if (preset->valid()) {
scratchpad->setPreset(preset);
// scratchpad->setPreset(preset);
}
}
}
const KoColorProfile* profile = KoColorSpaceRegistry::instance()->rgb8()->profile();
scratchpad->setColorSpace(KoColorSpaceRegistry::instance()->rgb16());
scratchpad->setDisplayProfile(profile);
scratchpad->setCanvasColor(Qt::white);
scratchpad->setPaintColor(Qt::black);
// scratchpad->setColorSpace(KoColorSpaceRegistry::instance()->rgb16());
// scratchpad->setDisplayProfile(profile);
// scratchpad->setCanvasColor(Qt::white);
scratchpad->show();
return app.exec();
}
......@@ -110,6 +110,10 @@ void KisToolFreehandHelper::initPaint(KoPointerEvent *event,
undoAdapter,
resourceManager);
if(overrideNode) {
m_d->resources->setCurrentNode(overrideNode);
}
bool indirectPainting = m_d->resources->needsIndirectPainting();
KisStrokeStrategy *stroke =
......
......@@ -82,10 +82,8 @@ KisPaintOpPresetsPopup::KisPaintOpPresetsPopup(KisCanvasResourceProvider * resou
m_d->layout = new QGridLayout(m_d->uiWdgPaintOpPresetSettings.frmOptionWidgetContainer);
m_d->layout->setSizeConstraint(QLayout::SetFixedSize);
m_d->uiWdgPaintOpPresetSettings.scratchPad->setCanvasColor(Qt::white);
m_d->uiWdgPaintOpPresetSettings.scratchPad->setColorSpace(KoColorSpaceRegistry::instance()->rgb8());
m_d->uiWdgPaintOpPresetSettings.scratchPad->setCutoutOverlay(QRect(25, 25, 200, 200));
m_d->uiWdgPaintOpPresetSettings.scratchPad->setCanvasResourceProvider(resourceProvider);
m_d->uiWdgPaintOpPresetSettings.scratchPad->setupScratchPad(resourceProvider, Qt::white);
m_d->uiWdgPaintOpPresetSettings.scratchPad->setCutoutOverlayRect(QRect(25, 25, 200, 200));
m_d->uiWdgPaintOpPresetSettings.fillLayer->setIcon(KIcon("newlayer"));
m_d->uiWdgPaintOpPresetSettings.fillLayer->hide();
m_d->uiWdgPaintOpPresetSettings.fillGradient->setIcon(KIcon("krita_tool_gradient"));
......@@ -93,22 +91,16 @@ KisPaintOpPresetsPopup::KisPaintOpPresetsPopup(KisCanvasResourceProvider * resou
m_d->uiWdgPaintOpPresetSettings.eraseScratchPad->setIcon(KIcon("edit-clear"));
connect(m_d->uiWdgPaintOpPresetSettings.eraseScratchPad, SIGNAL(clicked()),
m_d->uiWdgPaintOpPresetSettings.scratchPad, SLOT(clear()));
connect(m_d->resourceProvider, SIGNAL(sigFGColorChanged(const KoColor &)),
m_d->uiWdgPaintOpPresetSettings.scratchPad, SLOT(setPaintColor(const KoColor &)));
connect(m_d->resourceProvider, SIGNAL(sigBGColorChanged(const KoColor &)),
m_d->uiWdgPaintOpPresetSettings.scratchPad, SLOT(setBackgroundColor(const KoColor &)));
m_d->uiWdgPaintOpPresetSettings.scratchPad, SLOT(fillDefault()));
connect(m_d->uiWdgPaintOpPresetSettings.fillLayer, SIGNAL(clicked()),
this, SLOT(fillScratchPadLayer()));
m_d->uiWdgPaintOpPresetSettings.scratchPad, SLOT(fillLayer()));
connect(m_d->uiWdgPaintOpPresetSettings.fillGradient, SIGNAL(clicked()),
this, SLOT(fillScratchPadGradient()));
m_d->uiWdgPaintOpPresetSettings.scratchPad, SLOT(fillGradient()));
connect(m_d->uiWdgPaintOpPresetSettings.fillSolid, SIGNAL(clicked()),
this, SLOT(fillScratchPadSolid()));
m_d->uiWdgPaintOpPresetSettings.scratchPad, SLOT(fillBackground()));
m_d->settingsWidget = 0;
setSizePolicy(QSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed));
......@@ -218,31 +210,11 @@ QString KisPaintOpPresetsPopup::getPresetName() const
return m_d->uiWdgPaintOpPresetSettings.txtPreset->text();
}
void KisPaintOpPresetsPopup::setPreset(KisPaintOpPresetSP preset)
{
m_d->uiWdgPaintOpPresetSettings.scratchPad->setPreset(preset);
}
QImage KisPaintOpPresetsPopup::cutOutOverlay()
{
return m_d->uiWdgPaintOpPresetSettings.scratchPad->cutoutOverlay();
}
void KisPaintOpPresetsPopup::fillScratchPadGradient()
{
m_d->uiWdgPaintOpPresetSettings.scratchPad->fillGradient(m_d->resourceProvider->currentGradient());
}
void KisPaintOpPresetsPopup::fillScratchPadSolid()
{
m_d->uiWdgPaintOpPresetSettings.scratchPad->fillSolid(m_d->resourceProvider->bgColor());
}
void KisPaintOpPresetsPopup::fillScratchPadLayer()
{
//TODO
}
void KisPaintOpPresetsPopup::contextMenuEvent(QContextMenuEvent *e) {
QMenu menu(this);
......@@ -276,7 +248,6 @@ void KisPaintOpPresetsPopup::hideScratchPad()
m_d->uiWdgPaintOpPresetSettings.scratchPad->setVisible(false);
}
void KisPaintOpPresetsPopup::showScratchPad()
{
m_d->uiWdgPaintOpPresetSettings.scratchPad->setVisible(true);
......@@ -305,6 +276,7 @@ QString KisPaintOpPresetsPopup::currentPaintOp()
void KisPaintOpPresetsPopup::setPresetImage(const QImage& image)
{
m_d->uiWdgPaintOpPresetSettings.scratchPad->setPresetImage(image);
m_d->uiWdgPaintOpPresetSettings.scratchPad->paintPresetImage();
}
void KisPaintOpPresetsPopup::hideEvent(QHideEvent *event)
......
......@@ -60,10 +60,6 @@ public:
*/
QString getPresetName() const;
///Set preset for the scratchpad
///@param preset that will be used in the scratchpad
void setPreset(KisPaintOpPresetSP preset);
///Image for preset preview
///@return image cut out from the scratchpad
QImage cutOutOverlay();
......@@ -96,9 +92,6 @@ signals:
void signalResourceSelected(KoResource* resource);
private slots:
void fillScratchPadGradient();
void fillScratchPadSolid();
void fillScratchPadLayer();
void slotCheckPresetValidity();
......
This diff is collapsed.
......@@ -19,28 +19,31 @@
#ifndef KIS_SCRATCH_PAD_H
#define KIS_SCRATCH_PAD_H
#include <QFrame>
#include <QImage>
#include <QColor>
#include <QCursor>
#include <QPoint>
#include <QWidget>
#include <QRect>
#include <KoColorProfile.h>
#include <KoColor.h>
#include <KoCompositeOp.h>
#include <KoPointerEvent.h>
#include <kis_paintop_preset.h>
#include <kis_types.h>
#include <kis_paint_information.h>
#include <kis_painter.h>
#include <kis_paint_layer.h>
#include <krita_export.h>
class KisUndoAdapter;
class QColor;
class KoColorProfile;
class KoPointerEvent;
class KisCanvasResourceProvider;
class KisUpdateScheduler;
class KisUndoStore;
class KisPostExecutionUndoAdapter;
class KisScratchPadEventFilter;
class KisPaintingInformationBuilder;
class KisToolFreehandHelper;
class KisNodeGraphListener;
/**
* A scratchpad is a painting canvas with only one zoomlevel and based on
......@@ -53,101 +56,74 @@ class KRITAUI_EXPORT KisScratchPad : public QWidget
Q_OBJECT
public:
enum BackgroundMode {
TILED,
STRETCHED,
CENTERED,
GRADIENT,
SOLID_COLOR
};
void setupScratchPad(KisCanvasResourceProvider* resourceProvider,
const QColor &defaultColor);
KisScratchPad(QWidget *parent = 0);
virtual ~KisScratchPad();
/// set the specified rect as the area taken for @see cutoutOverlay
void setCutoutOverlay(const QRect&rc);
void setCutoutOverlayRect(const QRect&rc);
/// return the contents of the area under the cutoutOverlay rect
QImage cutoutOverlay() const;
// A callback for our own node graph listener
void imageUpdated(const QRect &rect);
public slots:
void fillDefault();
void fillGradient();
void fillBackground();
void fillLayer();
/**
* Set the icon of the current preset
*/
void setPresetImage(const QImage& image);
/**
* Paint the icon of the current preset inside the
* cutout overlay
*
* \see setPresetImage
*/
void paintPresetImage();
/// Set the current paint color as a QColor
void setPaintColor(const QColor& foregroundColor);
/// Set the current paint color as a KoColor
void setPaintColor(const KoColor& foregroundColor);
/// Set the preset to use
void setPreset(KisPaintOpPresetSP preset);
/// Set the background color for painting.
void setBackgroundColor(const KoColor& backgroundColor);
/// Set the color of the canvas
void setCanvasColor(const QColor& canvasColor);
/// Set an image for the paint paint device
void setBackgroundTile(const QImage& tile);
/// Set the colorspace for the paint device
void setColorSpace(const KoColorSpace* colorSpace);
/// Set the display profile (should be the same as for the main canvas, probably)
private slots:
void setOnScreenResolution(qreal scaleX, qreal scaleY);
void setDisplayProfile(const KoColorProfile* colorProfile);
/// Clear the paint device to the background color default pixel.
void clear();
/// fill the visible area of the paint device with the given color
void fillGradient(KoAbstractGradient* gradient);
/// fill the visible area of the paint device with a solid color
void fillSolid(const KoColor& color);
/// fill the cutoutOverlay rect with the cotent of an image, used to get the image back when selecting a preset
void setPresetImage(const QImage& image);
/// Set canvas resource provider, this has to be done otherwise the scratchpad doesn't work
void setCanvasResourceProvider(KisCanvasResourceProvider* resourceProvider);
void slotUpdateCanvas(const QRect &rect);
signals:
void colorSelected(const KoColor& color);
void sigUpdateCanvas(const QRect &rect);
protected:
virtual void contextMenuEvent ( QContextMenuEvent * event );
virtual void keyPressEvent ( QKeyEvent * event );
virtual void keyReleaseEvent ( QKeyEvent * event );
virtual void mouseDoubleClickEvent ( QMouseEvent * event );
virtual void mouseMoveEvent ( QMouseEvent * event );
virtual void mousePressEvent ( QMouseEvent * event );
virtual void mouseReleaseEvent ( QMouseEvent * event );
virtual void tabletEvent ( QTabletEvent * event );
virtual void wheelEvent ( QWheelEvent * event );
virtual void paintEvent ( QPaintEvent * event );
virtual void resizeEvent ( QResizeEvent * event );
private:
public slots:
void slotMousePress(KoPointerEvent *event);
void slotMouseRelease(KoPointerEvent *event);
void slotMouseMove(KoPointerEvent *event);
void initPainting(QEvent* event);
void paint(QEvent* event);
void endPaint(QEvent* event);
private:
void beginStroke(KoPointerEvent *event);
void doStroke(KoPointerEvent *event);
void endStroke(KoPointerEvent *event);
void pick(QMouseEvent* event);
void beginPan(KoPointerEvent *event);
void doPan(KoPointerEvent *event);
void endPan(KoPointerEvent *event);
void initPan(QMouseEvent* event);
void pan(QMouseEvent* event);
void endPan(QMouseEvent* event);
void pick(KoPointerEvent *event);
// these methods are called like in KisToolFreehand to make refactoring easier.
KisPaintOpPresetSP currentPaintOpPreset() const { return m_preset; }
KisPaintLayerSP currentNode() const { return m_paintLayer; }
void updateTransformations();
QTransform documentToWidget() const;
QTransform widgetToDocument() const;
private:
enum Mode {
PAINTING,
HOVERING,
......@@ -155,33 +131,31 @@ private:
PICKING
};
QPoint m_offset;
const KoColorSpace* m_colorSpace;
KoColor m_paintColor;
QImage m_backgroundTile;
KoColor m_backgroundColor;
QColor m_canvasColor;
KoColor m_defaultColor;
Mode m_toolMode;
KisPaintDeviceSP m_paintDevice;
KisPaintLayerSP m_paintLayer;
KisPaintOpPresetSP m_preset;
BackgroundMode m_backgroundMode;
const KoColorProfile* m_displayProfile;
QCursor m_cursor;
QPoint m_currentMousePosition;
KisDistanceInformation m_distanceInformation;
KisPaintInformation m_previousPaintInformation;
KisPainter *m_painter;
double m_dragDist;
const KoCompositeOp *m_compositeOp;
QPoint m_lastPosition;
qreal m_scale;
QRect m_cutoutOverlay;
QBrush m_checkBrush;
bool m_paintIncremental;
quint8 m_opacity;
QRegion m_incrementalDirtyRegion;
KisCanvasResourceProvider* m_resourceProvider;
KisUpdateScheduler *m_updateScheduler;
KisUndoStore *m_undoStore;
KisPostExecutionUndoAdapter *m_undoAdapter;
KisNodeGraphListener *m_nodeListener;
KisScratchPadEventFilter *m_eventFilter;
KisToolFreehandHelper *m_helper;
KisPaintingInformationBuilder *m_infoBuilder;
QTransform m_scaleTransform;
QTransform m_translateTransform;
QPointF m_panDocPoint;
int m_scaleBorderWidth;
QImage m_presetImage;
};
#endif // KIS_SCRATCH_PAD_H
/*
* Copyright (c) 2011 Dmitry Kazakov <dimula73@gmail.com>
*
* 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 "kis_scratch_pad_event_filter.h"
#include <QWidget>
KisScratchPadEventFilter::KisScratchPadEventFilter(QWidget *parent)
: QObject(parent),
m_tabletPressed(false)
{
parent->installEventFilter(this);
}
void KisScratchPadEventFilter::setWidgetToDocumentTransform(const QTransform &transform)
{
m_widgetToDocument = transform;
}
QWidget* KisScratchPadEventFilter::parentWidget()
{
return static_cast<QWidget*>(parent());
}
KoPointerEvent* KisScratchPadEventFilter::createMouseEvent(QEvent *event)
{
QMouseEvent *mouseEvent = static_cast<QMouseEvent*>(event);
return new KoPointerEvent(mouseEvent, m_widgetToDocument.map(mouseEvent->pos()));
}
KoPointerEvent* KisScratchPadEventFilter::createTabletEvent(QEvent *event)
{
QTabletEvent *tabletEvent = static_cast<QTabletEvent*>(event);
const QPointF pos = tabletEvent->hiResGlobalPos() - parentWidget()->mapToGlobal(QPoint());
KoPointerEvent *ev = new KoPointerEvent(tabletEvent, m_widgetToDocument.map(pos));
ev->setTabletButton(Qt::LeftButton);
return ev;
}
bool KisScratchPadEventFilter::eventFilter(QObject *obj, QEvent *event)
{
Q_UNUSED(obj);
bool result = true;
KoPointerEvent *ev = 0;
switch(event->type()) {
case QEvent::MouseButtonPress:
if(m_tabletPressed) break;
ev = createMouseEvent(event);
emit mousePressSignal(ev);
break;
case QEvent::MouseButtonRelease:
if(m_tabletPressed) break;
ev = createMouseEvent(event);
emit mouseReleaseSignal(ev);
break;
case QEvent::MouseMove:
if(m_tabletPressed) break;
ev = createMouseEvent(event);
emit mouseMoveSignal(ev);
break;
case QEvent::TabletPress:
if(m_tabletPressed) break;
m_tabletPressed = true;
ev = createTabletEvent(event);
emit mousePressSignal(ev);
break;
case QEvent::TabletRelease:
if(!m_tabletPressed) break;
m_tabletPressed = false;
ev = createTabletEvent(event);
emit mouseReleaseSignal(ev);
break;
case QEvent::TabletMove:
if(!m_tabletPressed) break;
ev = createTabletEvent(event);
emit mouseMoveSignal(ev);
break;
default:
result = <