kis_tool_select_rectangular.cc 10.6 KB
Newer Older
1

2
/*
3 4
 *  kis_tool_select_rectangular.cc -- part of Krita
 *
5 6
 *  Copyright (c) 1999 Michael Koch <koch@kde.org>
 *                2001 John Califf <jcaliff@compuzone.net>
7
 *                2002 Patrick Julien <freak@codepimps.org>
8
 *  Copyright (c) 2007 Sven Langkamp <sven.langkamp@gmail.com>
9 10 11 12 13 14 15 16 17 18 19 20 21
 *
 *  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
22
 *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
23
 */
24

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

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

34 35
#include <KoShapeController.h>
#include <KoPathShape.h>
Sven Langkamp's avatar
Sven Langkamp committed
36
#include <KoShapeManager.h>
37
#include <KoShapeRegistry.h>
38

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

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

64
KisToolSelectRectangular::~KisToolSelectRectangular()
65 66 67
{
}

68 69
void KisToolSelectRectangular::activate()
{
70
    super::activate();
71

72 73
    if (!m_optWidget)
        return;
74

75
    m_optWidget->slotActivated();
76 77
}

78
void KisToolSelectRectangular::paint(QPainter& gc, const KoViewConverter &converter)
79
{
80 81
    double sx, sy;
    converter.zoom(&sx, &sy);
82

83
    gc.scale( sx/currentImage()->xRes(), sy/currentImage()->yRes() );
84 85
    if (m_selecting) {
        QPen old = gc.pen();
86
        gc.setPen(Qt::DashLine);
87

88 89
        QRectF rectangle(m_startPos.x(), m_startPos.y(), m_endPos.x() - m_startPos.x(), m_endPos.y() - m_startPos.y());
        gc.drawRect(rectangle);
90 91 92

        gc.setPen(old);
    }
93
}
94

95
void KisToolSelectRectangular::clearSelection()
96
{
97
    if (m_canvas) {
Laurent Montel's avatar
Laurent Montel committed
98 99 100
        m_centerPos = QPointF(0, 0);
        m_startPos = QPointF(0, 0);
        m_endPos = QPointF(0, 0);
101 102
        m_selecting = false;
    }
103
}
104

105
void KisToolSelectRectangular::mousePressEvent(KoPointerEvent *e)
106
{
107
    if (m_canvas) {
108

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

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

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

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

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

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

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

161 162 163 164
        QRectF bound;
        bound.setTopLeft(m_startPos);
        bound.setBottomRight(m_endPos);
        m_canvas->updateCanvas(convertToPt(bound.normalized()));
165 166 167

        if (m_startPos == m_endPos) {
            clearSelection();
168 169 170 171 172
            m_selecting = false;
            return;
        }

    //                 QApplication::setOverrideCursor(KisCursor::waitCursor());
173

174
        if (!currentImage())
175
            return;
176

177 178
        if (m_endPos.y() < 0)
            m_endPos.setY(0);
179

180 181
        if (m_endPos.y() > currentImage()->height())
            m_endPos.setY(currentImage()->height());
182

183 184
        if (m_endPos.x() < 0)
            m_endPos.setX(0);
185

186 187
        if (m_endPos.x() > currentImage()->width())
            m_endPos.setX(currentImage()->width());
188

189
        if (currentImage() && currentLayer()->paintDevice()) {
Adrian Page's avatar
Adrian Page committed
190

191
            KisPaintDeviceSP dev = currentLayer()->paintDevice();
192 193 194 195 196
            bool hasSelection = dev->hasSelection();
            QRect rc(m_startPos.toPoint(), m_endPos.toPoint());
            rc = rc.normalized();

            if(m_selectionMode == PIXEL_SELECTION){
197
                KisSelectedTransaction *t = new KisSelectedTransaction(i18n("Rectangular Selection"), dev);
198
                KisPixelSelectionSP pixelSelection = dev->pixelSelection();
199 200 201

                // We don't want the border of the 'rectangle' to be included in our selection
                rc.setSize(rc.size() - QSize(1,1));
202

203
                if(! hasSelection || m_selectAction == SELECTION_REPLACE)
204
                {
205
                    pixelSelection->clear();
206
                    if(m_selectAction==SELECTION_SUBTRACT)
207
                        pixelSelection->invert();
208 209
                }

210
                KisPixelSelectionSP tmpSel = KisPixelSelectionSP(new KisPixelSelection(dev));
211 212 213
                tmpSel->select(rc);
                switch(m_selectAction)
                {
214
                    case SELECTION_REPLACE:
215
                    case SELECTION_ADD:
216
                        dev->addSelection(tmpSel);
217 218
                        break;
                    case SELECTION_SUBTRACT:
219
                        dev->subtractSelection(tmpSel);
220
                        break;
221 222 223
                    case SELECTION_INTERSECT:
                        dev->intersectSelection(tmpSel);
                        break;
224 225 226
                    default:
                        break;
                }
227 228 229 230 231 232 233 234 235
                m_canvas->addCommand(t);
            }
            else {
                QRectF documentRect = convertToPt(bound);

                KoShape* shape;
                KoShapeFactory *rectFactory = KoShapeRegistry::instance()->value("KoRectangleShape");
                if(rectFactory) {
                    shape = rectFactory->createDefaultShape();
236
                    shape->setSize(documentRect.size());
237 238 239 240 241 242 243 244 245 246 247 248 249 250
                    shape->setPosition(documentRect.topLeft());
                }
                else {
                    //Fallback if the plugin wasn't found
                    KoPathShape* path = new KoPathShape();
                    path->setShapeId( KoPathShapeId );
                    path->moveTo( documentRect.topLeft() );
                    path->lineTo( documentRect.topLeft() + QPointF(documentRect.width(), 0) );
                    path->lineTo( documentRect.bottomRight() );
                    path->lineTo( documentRect.topLeft() + QPointF(0, documentRect.height()) );
                    path->close();
                    path->normalize();
                    shape = path;
                }
251

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

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

272
            if(hasSelection && m_selectAction != SELECTION_REPLACE && m_selectAction != SELECTION_INTERSECT) {
273 274 275
                dev->setDirty(rc);
                dev->emitSelectionChanged(rc);
            } else {
276
                dev->setDirty(currentImage()->bounds());
277 278 279
                dev->emitSelectionChanged();
            }
        }
280 281
        m_selecting = false;
    }
282 283
}

284
void KisToolSelectRectangular::slotSetAction(int action) {
285
    if (action >= SELECTION_ADD && action <= SELECTION_INTERSECT)
286
        m_selectAction =(selectionAction)action;
287 288
}

289 290
void KisToolSelectRectangular::slotSetSelectionMode(int mode) {
    m_selectionMode = (selectionMode)mode;
291

292 293
}

294
QWidget* KisToolSelectRectangular::createOptionWidget()
295
{
296 297 298
    KisCanvas2* canvas = dynamic_cast<KisCanvas2*>(m_canvas);
    Q_ASSERT(canvas);
    m_optWidget = new KisSelectionOptions(canvas);
299
    Q_CHECK_PTR(m_optWidget);
Adrian Page's avatar
Adrian Page committed
300
    m_optWidget->setWindowTitle(i18n("Rectangular Selection"));
301
    m_optWidget->disableAntiAliasSelectionOption();
302

303 304 305
    connect(m_optWidget, SIGNAL(actionChanged(int)), this, SLOT(slotSetAction(int)));
    connect(m_optWidget, SIGNAL(modeChanged(int)), this, SLOT(slotSetSelectionMode(int)));

306

307 308 309 310 311
    QVBoxLayout * l = dynamic_cast<QVBoxLayout*>(m_optWidget->layout());
    Q_ASSERT(l);
    if (l) {
        l->addItem(new QSpacerItem(1, 1, QSizePolicy::Fixed, QSizePolicy::Expanding));
    }
312

313
    return m_optWidget;
314 315 316 317 318 319 320 321 322 323
}

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




324
#include "kis_tool_select_rectangular.moc"