kis_tool_select_elliptical.cc 10.8 KB
Newer Older
1
/*
2
 *  kis_tool_select_elliptical.cc -- part of Krita
3
 *
4
 *  Copyright (c) 2004 Boudewijn Rempt (boud@valdyas.org)
5
 *  Copyright (c) 2007 Sven Langkamp <sven.langkamp@gmail.com>
6 7 8 9 10 11 12 13 14 15 16 17 18
 *
 *  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
19
 *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
20 21
 */

22 23
#include "kis_tool_select_elliptical.h"

24 25 26
#include <QApplication>
#include <QPainter>
#include <QPen>
27
#include <QLayout>
28
#include <QVBoxLayout>
29 30

#include <kdebug.h>
31
#include <klocale.h>
32

33 34 35 36 37
#include <KoPointerEvent.h>
#include <KoShapeController.h>
#include <KoPathShape.h>
#include <KoShapeRegistry.h>
#include <KoShapeFactory.h>
38

39 40
#include "kis_cursor.h"
#include "kis_image.h"
41
#include "kis_painter.h"
42
#include "kis_paintop_registry.h"
43
#include "kis_layer.h"
44
#include "kis_selection.h"
45
#include "kis_selection_options.h"
46
#include "kis_selected_transaction.h"
47
#include "kis_canvas2.h"
Sven Langkamp's avatar
Sven Langkamp committed
48
#include "kis_pixel_selection.h"
49
#include "kis_shape_selection.h"
50

51 52
KisToolSelectElliptical::KisToolSelectElliptical(KoCanvasBase * canvas)
    : KisTool(canvas, KisCursor::load("tool_elliptical_selection_cursor.png", 6, 6))
53
{
54
    m_selecting = false;
Laurent Montel's avatar
Laurent Montel committed
55 56 57
    m_centerPos = QPointF(0, 0);
    m_startPos = QPointF(0, 0);
    m_endPos = QPointF(0, 0);
58
    m_optWidget = 0;
59
    m_selectAction = SELECTION_REPLACE;
60
    m_selectionMode = PIXEL_SELECTION;
61 62
}

63
KisToolSelectElliptical::~KisToolSelectElliptical()
64 65 66
{
}

67 68
void KisToolSelectElliptical::activate()
{
69
    super::activate();
70

71 72
    if (!m_optWidget)
        return;
73

74
    m_optWidget->slotActivated();
75
}
76

77
void KisToolSelectElliptical::paint(QPainter& gc, const KoViewConverter &converter)
78
{
79
    Q_UNUSED(converter);
80

81
    if (m_selecting) {
82 83 84 85
        gc.save();
        gc.setPen(Qt::DotLine);
        gc.drawEllipse(pixelToView(QRectF(m_startPos, m_endPos)));
        gc.restore();
86
    }
87 88 89 90
}

void KisToolSelectElliptical::clearSelection()
{
91
    if (m_canvas) {
92

93 94
//         if (currentImage() && currentImage()->floatingSelection().data() != 0) {
//             currentImage()->unsetFloatingSelection();
95
//                         controller->canvas()->update();
96
//         }
97

Laurent Montel's avatar
Laurent Montel committed
98 99
        m_startPos = QPointF(0, 0);
        m_endPos = QPointF(0, 0);
100 101
        m_selecting = false;
    }
102 103
}

104
void KisToolSelectElliptical::mousePressEvent(KoPointerEvent *e)
105
{
106
    if (m_canvas) {
107

108
        if (currentImage() && currentLayer()->paintDevice() && e->button() == Qt::LeftButton) {
109
            clearSelection();
110
            m_startPos = m_endPos = m_centerPos = convertToPixelCoord(e);
111 112 113
            m_selecting = true;
        }
    }
114 115
}

116
void KisToolSelectElliptical::mouseMoveEvent(KoPointerEvent *e)
117
{
118
    if (m_canvas && m_selecting) {
119
        QRectF updateRect(m_startPos, m_endPos);
120

121
        // move (alt) or resize ellipse
Adrian Page's avatar
Adrian Page committed
122
        if (e->modifiers() & Qt::AltModifier) {
123
            QPointF trans = convertToPixelCoord(e) - m_endPos;
124 125 126
            m_startPos += trans;
            m_endPos += trans;
        } else {
127
            QPointF diag = convertToPixelCoord(e) - (e->modifiers() & Qt::ControlModifier
128 129
                    ? m_centerPos : m_startPos);
            // circle?
Adrian Page's avatar
Adrian Page committed
130
            if (e->modifiers() & Qt::ShiftModifier) {
Laurent Montel's avatar
Laurent Montel committed
131
                double size = qMax(fabs(diag.x()), fabs(diag.y()));
132 133
                double w = diag.x() < 0 ? -size : size;
                double h = diag.y() < 0 ? -size : size;
Laurent Montel's avatar
Laurent Montel committed
134
                diag = QPointF(w, h);
135 136 137
            }

            // resize around center point?
Adrian Page's avatar
Adrian Page committed
138
            if (e->modifiers() & Qt::ControlModifier) {
139 140 141 142 143 144
                m_startPos = m_centerPos - diag;
                m_endPos = m_centerPos + diag;
            } else {
                m_endPos = m_startPos + diag;
            }
        }
145 146 147 148 149

        updateRect |= QRectF(m_startPos, m_endPos);
        updateRect = updateRect.normalized();
        updateRect.adjust(-1, -1, 1, 1);
        m_canvas->updateCanvas(convertToPt(updateRect));
150

Laurent Montel's avatar
Laurent Montel committed
151
        m_centerPos = QPointF((m_startPos.x() + m_endPos.x()) / 2,
152 153
                (m_startPos.y() + m_endPos.y()) / 2);
    }
154 155
}

156
void KisToolSelectElliptical::mouseReleaseEvent(KoPointerEvent *e)
157
{
158
     if (m_canvas && m_selecting && e->button() == Qt::LeftButton) {
159 160 161 162

        if (m_startPos == m_endPos) {
            clearSelection();
        } else {
163
//             QApplication::setOverrideCursor(KisCursor::waitCursor());
164

165
            if (!currentImage())
166 167
                return;

168 169
            if (currentImage() && currentLayer()->paintDevice()) {
                KisPaintDeviceSP dev = currentLayer()->paintDevice();
170

171 172
            bool hasSelection = dev->hasSelection();
            KisSelectionSP selection = dev->selection();
Sven Langkamp's avatar
Sven Langkamp committed
173

174
            if(m_selectionMode == PIXEL_SELECTION){
Sven Langkamp's avatar
Sven Langkamp committed
175 176
                KisPixelSelectionSP pixelSelection = dev->pixelSelection();

177
                KisSelectedTransaction *t = new KisSelectedTransaction(i18n("Elliptical Selection"), dev);
178

179
                if (!hasSelection || m_selectAction == SELECTION_REPLACE)
180
                {
Sven Langkamp's avatar
Sven Langkamp committed
181
                    pixelSelection->clear();
182
                    if(m_selectAction == SELECTION_SUBTRACT)
Sven Langkamp's avatar
Sven Langkamp committed
183
                        pixelSelection->invert();
184
                }
185

186 187 188
                KisPixelSelectionSP tmpSel = KisPixelSelectionSP(new KisPixelSelection(dev));

                KisPainter painter(tmpSel);
189
                painter.setBounds( currentImage()->bounds() );
190 191 192 193 194
                painter.setPaintColor(KoColor(Qt::black, selection->colorSpace()));
                painter.setFillStyle(KisPainter::FillStyleForegroundColor);
                painter.setStrokeStyle(KisPainter::StrokeStyleNone);
                painter.setAntiAliasPolygonFill(m_optWidget->antiAliasSelection());
                painter.setOpacity(OPACITY_OPAQUE);
195
                KisPaintOp * op = KisPaintOpRegistry::instance()->paintOp("paintbrush", 0, &painter, currentImage());
196
                painter.setPaintOp(op); // And now the painter owns the op and will destroy it.
197 198 199 200
                painter.setCompositeOp(tmpSel->colorSpace()->compositeOp(COMPOSITE_OVER));

                painter.paintEllipse(QRectF(m_startPos, m_endPos), PRESSURE_DEFAULT/*e->pressure()*/,
                                     e->xTilt(), e->yTilt());
201

202 203
                switch(m_selectAction)
                {
204
                    case SELECTION_REPLACE:
205
                    case SELECTION_ADD:
206
                        dev->addSelection(tmpSel);
207 208
                        break;
                    case SELECTION_SUBTRACT:
209 210 211 212
                        dev->subtractSelection(tmpSel);
                        break;
                    case SELECTION_INTERSECT:
                        dev->intersectSelection(tmpSel);
213 214
                        break;
                    default:
215 216
                        break;
                }
Adrian Page's avatar
Adrian Page committed
217

218

219
                if(hasSelection && m_selectAction != SELECTION_REPLACE && m_selectAction != SELECTION_INTERSECT) {
220
                    QRect rect(painter.dirtyRegion().boundingRect());
221
                    dev->setDirty(rect);
222
                    dev->emitSelectionChanged(rect);
223
                } else {
224
                    dev->setDirty(currentImage()->bounds());
225
                    dev->emitSelectionChanged();
226
                }
227

228
                m_canvas->addCommand(t);
229 230 231 232 233 234 235 236
            }
            else {
                QRectF documentRect = convertToPt(QRectF(m_startPos, m_endPos));

                KoShape* shape;
                KoShapeFactory *rectFactory = KoShapeRegistry::instance()->value("KoEllipseShape");
                if(rectFactory) {
                    shape = rectFactory->createDefaultShape();
237
                    shape->setSize(documentRect.size());
238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258
                    shape->setPosition(documentRect.topLeft());
                }
                else {
                    //Fallback if the plugin wasn't found
                    KoPathShape* path = new KoPathShape();
                    path->setShapeId( KoPathShapeId );

                    QPointF rightMiddle = QPointF(documentRect.left() + documentRect.width(), documentRect.top() + documentRect.height()/2);
                    path->moveTo( rightMiddle );
                    path->arcTo( documentRect.width()/2, documentRect.height()/2, 0, 360.0 );
                    path->close();
                    path->normalize();
                    shape = path;
                }

                KisCanvas2* canvas = dynamic_cast<KisCanvas2*>(m_canvas);
                Q_ASSERT(canvas);
                KisSelectionSP selection = dev->selection();

                KisShapeSelection* shapeSelection;
                if(!selection->hasShapeSelection()) {
259
                    shapeSelection = new KisShapeSelection(currentImage());
260 261 262 263 264 265 266 267 268 269 270 271
                    QUndoCommand * cmd = m_canvas->shapeController()->addShape(shapeSelection);
                    cmd->redo();
                    selection->setShapeSelection(shapeSelection);
                }
                else {
                    shapeSelection = dynamic_cast<KisShapeSelection*>(selection->shapeSelection());
                }
                shape->setParent(shapeSelection);
                QUndoCommand * cmd = m_canvas->shapeController()->addShape(shape);
                m_canvas->addCommand(cmd);
                shapeSelection->addChild(shape);
            }
272

273
//                 QApplication::restoreOverrideCursor();
274 275 276 277
            }
        }
        m_selecting = false;
    }
278 279
}

280
void KisToolSelectElliptical::slotSetAction(int action) {
281
    if (action >= SELECTION_ADD && action <= SELECTION_INTERSECT)
282
        m_selectAction =(selectionAction)action;
283 284
}

285 286 287 288
void KisToolSelectElliptical::slotSetSelectionMode(int mode) {
    m_selectionMode = (selectionMode)mode;
}

289
QWidget* KisToolSelectElliptical::createOptionWidget()
290
{
291 292 293
    KisCanvas2* canvas = dynamic_cast<KisCanvas2*>(m_canvas);
    Q_ASSERT(canvas);
    m_optWidget = new KisSelectionOptions(canvas);
294
    Q_CHECK_PTR(m_optWidget);
Adrian Page's avatar
Adrian Page committed
295
    m_optWidget->setWindowTitle(i18n("Elliptical Selection"));
296

297
    connect (m_optWidget, SIGNAL(actionChanged(int)), this, SLOT(slotSetAction(int)));
298 299
    connect(m_optWidget, SIGNAL(modeChanged(int)), this, SLOT(slotSetSelectionMode(int)));

300

301 302 303 304 305
    QVBoxLayout * l = dynamic_cast<QVBoxLayout*>(m_optWidget->layout());
    Q_ASSERT(l);
    if (l) {
        l->addItem(new QSpacerItem(1, 1, QSizePolicy::Fixed, QSizePolicy::Expanding));
    }
306

307
    return m_optWidget;
308 309 310 311 312 313 314 315
}

QWidget* KisToolSelectElliptical::optionWidget()
{
        return m_optWidget;
}


316

317
#include "kis_tool_select_elliptical.moc"