diff --git a/libs/widgets/KoShadowConfigWidget.cpp b/libs/widgets/KoShadowConfigWidget.cpp index c75a8fb1fa..6e7ff4b785 100644 --- a/libs/widgets/KoShadowConfigWidget.cpp +++ b/libs/widgets/KoShadowConfigWidget.cpp @@ -1,241 +1,241 @@ /* This file is part of the KDE project * Copyright (C) 2012 C. Boemann * Copyright (C) 2008 Jan Hambrecht * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This library 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 * Library General Public License for more details. * * You should have received a copy of the GNU Library General Public License * along with this library; see the file COPYING.LIB. If not, write to * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, * Boston, MA 02110-1301, USA. */ #include "KoShadowConfigWidget.h" #include "ui_KoShadowConfigWidget.h" #include #include #include #include #include #include #include #include #include #include #include #include class Q_DECL_HIDDEN KoShadowConfigWidget::Private { public: Private() { } Ui_KoShadowConfigWidget widget; KoColorPopupAction *actionShadowColor; KoCanvasBase *canvas; }; KoShadowConfigWidget::KoShadowConfigWidget(QWidget *parent) : QWidget(parent) , d(new Private()) { d->widget.setupUi(this); d->widget.shadowOffset->setValue(8.0); d->widget.shadowBlur->setValue(8.0); d->widget.shadowBlur->setMinimum(0.0); d->widget.shadowAngle->setValue(315.0); d->widget.shadowAngle->setMinimum(0.0); d->widget.shadowAngle->setMaximum(360.0); d->widget.shadowVisible->setChecked(false); visibilityChanged(); d->actionShadowColor = new KoColorPopupAction(this); d->actionShadowColor->setCurrentColor(QColor(0, 0, 0, 192)); // some reasonable default for shadow d->actionShadowColor->setIcon(koIcon("format-stroke-color")); d->actionShadowColor->setToolTip(i18n("Change the color of the shadow")); d->widget.shadowColor->setDefaultAction(d->actionShadowColor); connect(d->widget.shadowVisible, SIGNAL(toggled(bool)), this, SLOT(applyChanges())); connect(d->widget.shadowVisible, SIGNAL(toggled(bool)), this, SLOT(visibilityChanged())); connect(d->actionShadowColor, SIGNAL(colorChanged(const KoColor&)), this, SLOT(applyChanges())); connect(d->widget.shadowAngle, SIGNAL(valueChanged(int)), this, SLOT(applyChanges())); connect(d->widget.shadowOffset, SIGNAL(valueChangedPt(qreal)), this, SLOT(applyChanges())); connect(d->widget.shadowBlur, SIGNAL(valueChangedPt(qreal)), this, SLOT(applyChanges())); } KoShadowConfigWidget::~KoShadowConfigWidget() { delete d; } void KoShadowConfigWidget::setShadowColor(const QColor &color) { d->widget.shadowColor->blockSignals(true); d->actionShadowColor->blockSignals(true); d->actionShadowColor->setCurrentColor( color ); d->actionShadowColor->blockSignals(false); d->widget.shadowColor->blockSignals(false); } QColor KoShadowConfigWidget::shadowColor() const { return d->actionShadowColor->currentColor(); } void KoShadowConfigWidget::setShadowOffset(const QPointF &offset) { qreal length = sqrt(offset.x()*offset.x() + offset.y()*offset.y()); qreal angle = atan2(-offset.y(), offset.x()); if (angle < 0.0) { angle += 2*M_PI; } d->widget.shadowAngle->blockSignals(true); d->widget.shadowAngle->setValue(-90 - angle * 180.0 / M_PI); d->widget.shadowAngle->blockSignals(false); d->widget.shadowOffset->blockSignals(true); d->widget.shadowOffset->changeValue(length); d->widget.shadowOffset->blockSignals(false); } QPointF KoShadowConfigWidget::shadowOffset() const { QPointF offset(d->widget.shadowOffset->value(), 0); QTransform m; m.rotate(d->widget.shadowAngle->value() + 90); return m.map(offset); } void KoShadowConfigWidget::setShadowBlur(const qreal &blur) { d->widget.shadowBlur->blockSignals(true); d->widget.shadowBlur->changeValue(blur); d->widget.shadowBlur->blockSignals(false); } qreal KoShadowConfigWidget::shadowBlur() const { return d->widget.shadowBlur->value(); } void KoShadowConfigWidget::setShadowVisible(bool visible) { d->widget.shadowVisible->blockSignals(true); d->widget.shadowVisible->setChecked(visible); d->widget.shadowVisible->blockSignals(false); visibilityChanged(); } bool KoShadowConfigWidget::shadowVisible() const { return d->widget.shadowVisible->isChecked(); } void KoShadowConfigWidget::visibilityChanged() { d->widget.shadowAngle->setEnabled( d->widget.shadowVisible->isChecked() ); d->widget.shadowBlur->setEnabled( d->widget.shadowVisible->isChecked() ); d->widget.shadowColor->setEnabled( d->widget.shadowVisible->isChecked() ); d->widget.shadowOffset->setEnabled( d->widget.shadowVisible->isChecked() ); } void KoShadowConfigWidget::applyChanges() { if (d->canvas) { KoSelection *selection = d->canvas->shapeManager()->selection(); KoShape * shape = selection->firstSelectedShape(KoFlake::TopLevelSelection); if (! shape) { return; } KoShapeShadow *newShadow = new KoShapeShadow(); newShadow->setVisible(shadowVisible()); newShadow->setColor(shadowColor()); newShadow->setOffset(shadowOffset()); newShadow->setBlur(shadowBlur()); d->canvas->addCommand(new KoShapeShadowCommand(selection->selectedShapes(KoFlake::TopLevelSelection), newShadow)); } } void KoShadowConfigWidget::selectionChanged() { if (! d->canvas) { return; } KoSelection *selection = d->canvas->shapeManager()->selection(); KoShape * shape = selection->firstSelectedShape(KoFlake::TopLevelSelection); setEnabled(shape != 0); if (! shape) { setShadowVisible(false); return; } KoShapeShadow * shadow = shape->shadow(); if (! shadow) { setShadowVisible(false); return; } setShadowVisible(shadow->isVisible()); setShadowOffset(shadow->offset()); setShadowColor(shadow->color()); setShadowBlur(shadow->blur()); } void KoShadowConfigWidget::setCanvas(KoCanvasBase *canvas) { d->canvas = canvas; connect(canvas->shapeManager(), SIGNAL(selectionChanged()), this, SLOT(selectionChanged())); connect(canvas->shapeManager(), SIGNAL(selectionContentChanged()), this, SLOT(selectionChanged())); setUnit(canvas->unit()); connect( d->canvas->resourceManager(), SIGNAL( canvasResourceChanged( int, const QVariant& ) ), this, SLOT( resourceChanged( int, const QVariant& ) ) ); } -void KoShadowConfigWidget::setUnitManager(KisSpinBoxUnitManager* managerBlur, KisSpinBoxUnitManager *managerOffset) +void KoShadowConfigWidget::setUnitManagers(KisSpinBoxUnitManager* managerBlur, KisSpinBoxUnitManager *managerOffset) { d->widget.shadowOffset->blockSignals(true); d->widget.shadowBlur->blockSignals(true); d->widget.shadowOffset->setUnitManager(managerOffset); d->widget.shadowBlur->setUnitManager(managerBlur); d->widget.shadowOffset->blockSignals(false); d->widget.shadowBlur->blockSignals(false); } void KoShadowConfigWidget::setUnit(const KoUnit &unit) { d->widget.shadowOffset->blockSignals(true); d->widget.shadowBlur->blockSignals(true); d->widget.shadowOffset->setUnit(unit); d->widget.shadowBlur->setUnit(unit); d->widget.shadowOffset->blockSignals(false); d->widget.shadowBlur->blockSignals(false); } void KoShadowConfigWidget::resourceChanged( int key, const QVariant & res ) { if( key == KoCanvasResourceManager::Unit ) { setUnit(res.value()); } } diff --git a/libs/widgets/KoShadowConfigWidget.h b/libs/widgets/KoShadowConfigWidget.h index 3c11d62858..3786268ecf 100644 --- a/libs/widgets/KoShadowConfigWidget.h +++ b/libs/widgets/KoShadowConfigWidget.h @@ -1,80 +1,80 @@ /* This file is part of the KDE project * Copyright (C) 2012 C. Boemann * Copyright (C) 2008 Jan Hambrecht * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This library 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 * Library General Public License for more details. * * You should have received a copy of the GNU Library General Public License * along with this library; see the file COPYING.LIB. If not, write to * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, * Boston, MA 02110-1301, USA. */ #ifndef KOSHADOWCONFIGWIDGET_H #define KOSHADOWCONFIGWIDGET_H #include "kritawidgets_export.h" #include class KoUnit; class KoCanvasBase; class KisSpinBoxUnitManager; /// A widget for configuring the shadow of a shape class KRITAWIDGETS_EXPORT KoShadowConfigWidget : public QWidget { Q_OBJECT public: explicit KoShadowConfigWidget(QWidget *parent); ~KoShadowConfigWidget(); /// Sets the shadow color void setShadowColor(const QColor &color); /// Returns the shadow color QColor shadowColor() const; /// Sets the shadow offset void setShadowOffset(const QPointF &offset); /// Returns the shadow offset QPointF shadowOffset() const; /// Sets the shadow blur radius void setShadowBlur(const qreal &blur); /// Returns the shadow blur radius qreal shadowBlur() const; /// Sets if the shadow is visible void setShadowVisible(bool visible); /// Returns if shadow is visible bool shadowVisible() const; public Q_SLOTS: - void setUnitManager(KisSpinBoxUnitManager* managerBlur, KisSpinBoxUnitManager* managerOffset); + void setUnitManagers(KisSpinBoxUnitManager* managerBlur, KisSpinBoxUnitManager* managerOffset); void setUnit( const KoUnit &unit ); void setCanvas(KoCanvasBase *canvas); private Q_SLOTS: void visibilityChanged(); void applyChanges(); void selectionChanged(); void resourceChanged( int key, const QVariant & res ); private: class Private; Private *const d; }; #endif // KOSHADOWCONFIGWIDGET_H diff --git a/libs/widgets/KoStrokeConfigWidget.cpp b/libs/widgets/KoStrokeConfigWidget.cpp index c2308b0539..36d656f954 100644 --- a/libs/widgets/KoStrokeConfigWidget.cpp +++ b/libs/widgets/KoStrokeConfigWidget.cpp @@ -1,552 +1,571 @@ /* This file is part of the KDE project * Made by Tomislav Lukman (tomislav.lukman@ck.tel.hr) * Copyright (C) 2002 Tomislav Lukman * Copyright (C) 2002-2003 Rob Buis * Copyright (C) 2005-2006 Tim Beaulen * Copyright (C) 2005-2007 Thomas Zander * Copyright (C) 2005-2006, 2011 Inge Wallin * Copyright (C) 2005-2008 Jan Hambrecht * Copyright (C) 2006 C. Boemann * Copyright (C) 2006 Peter Simonsson * Copyright (C) 2006 Laurent Montel * Copyright (C) 2007,2011 Thorsten Zachmann * Copyright (C) 2011 Jean-Nicolas Artaud * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This library 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 * Library General Public License for more details. * * You should have received a copy of the GNU Library General Public License * along with this library; see the file COPYING.LIB. If not, write to * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, * Boston, MA 02110-1301, USA. */ // Own #include "KoStrokeConfigWidget.h" // Qt #include #include #include #include #include #include #include // KDE #include // Calligra #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include // Krita #include "kis_double_parse_unit_spin_box.h" class CapNJoinMenu : public QMenu { public: CapNJoinMenu(QWidget *parent = 0); virtual QSize sizeHint() const; KisDoubleParseUnitSpinBox *miterLimit; QButtonGroup *capGroup; QButtonGroup *joinGroup; }; CapNJoinMenu::CapNJoinMenu(QWidget *parent) : QMenu(parent) { QGridLayout *mainLayout = new QGridLayout(); mainLayout->setMargin(2); // The cap group capGroup = new QButtonGroup(this); capGroup->setExclusive(true); QToolButton *button = 0; button = new QToolButton(this); button->setIcon(koIcon("stroke-cap-butt")); button->setCheckable(true); button->setToolTip(i18n("Butt cap")); capGroup->addButton(button, Qt::FlatCap); mainLayout->addWidget(button, 2, 0); button = new QToolButton(this); button->setIcon(koIcon("stroke-cap-round")); button->setCheckable(true); button->setToolTip(i18n("Round cap")); capGroup->addButton(button, Qt::RoundCap); mainLayout->addWidget(button, 2, 1); button = new QToolButton(this); button->setIcon(koIcon("stroke-cap-square")); button->setCheckable(true); button->setToolTip(i18n("Square cap")); capGroup->addButton(button, Qt::SquareCap); mainLayout->addWidget(button, 2, 2, Qt::AlignLeft); // The join group joinGroup = new QButtonGroup(this); joinGroup->setExclusive(true); button = new QToolButton(this); button->setIcon(koIcon("stroke-join-miter")); button->setCheckable(true); button->setToolTip(i18n("Miter join")); joinGroup->addButton(button, Qt::MiterJoin); mainLayout->addWidget(button, 3, 0); button = new QToolButton(this); button->setIcon(koIcon("stroke-join-round")); button->setCheckable(true); button->setToolTip(i18n("Round join")); joinGroup->addButton(button, Qt::RoundJoin); mainLayout->addWidget(button, 3, 1); button = new QToolButton(this); button->setIcon(koIcon("stroke-join-bevel")); button->setCheckable(true); button->setToolTip(i18n("Bevel join")); joinGroup->addButton(button, Qt::BevelJoin); mainLayout->addWidget(button, 3, 2, Qt::AlignLeft); // Miter limit // set min/max/step and value in points, then set actual unit miterLimit = new KisDoubleParseUnitSpinBox(this); miterLimit->setMinMaxStep(0.0, 1000.0, 0.5); miterLimit->setDecimals(2); miterLimit->setUnit(KoUnit(KoUnit::Point)); miterLimit->setToolTip(i18n("Miter limit")); mainLayout->addWidget(miterLimit, 4, 0, 1, 3); mainLayout->setSizeConstraint(QLayout::SetMinAndMaxSize); setLayout(mainLayout); } QSize CapNJoinMenu::sizeHint() const { return layout()->sizeHint(); } class Q_DECL_HIDDEN KoStrokeConfigWidget::Private { public: Private() : canvas(0), - active(true) + active(true), + letUnitBeSet(true) { } KoLineStyleSelector *lineStyle; KisDoubleParseUnitSpinBox *lineWidth; KoMarkerSelector *startMarkerSelector; KoMarkerSelector *endMarkerSelector; CapNJoinMenu *capNJoinMenu; QToolButton *colorButton; KoColorPopupAction *colorAction; QWidget *spacer; KoCanvasBase *canvas; bool active; + bool letUnitBeSet; }; KoStrokeConfigWidget::KoStrokeConfigWidget(QWidget * parent) : QWidget(parent) , d(new Private()) { setObjectName("Stroke widget"); QVBoxLayout *mainLayout = new QVBoxLayout(this); mainLayout->setMargin(0); QHBoxLayout *firstLineLayout = new QHBoxLayout(); // Start marker QList markers; d->startMarkerSelector = new KoMarkerSelector(KoMarkerData::MarkerStart, this); d->startMarkerSelector->updateMarkers(markers); d->startMarkerSelector->setMaximumWidth(50); firstLineLayout->addWidget(d->startMarkerSelector); // Line style d->lineStyle = new KoLineStyleSelector(this); d->lineStyle->setMinimumWidth(70); firstLineLayout->addWidget(d->lineStyle); // End marker d->endMarkerSelector = new KoMarkerSelector(KoMarkerData::MarkerEnd, this); d->endMarkerSelector->updateMarkers(markers); d->endMarkerSelector->setMaximumWidth(50); firstLineLayout->addWidget(d->endMarkerSelector); QHBoxLayout *secondLineLayout = new QHBoxLayout(); // Line width QLabel *l = new QLabel(this); l->setText(i18n("Thickness:")); l->setAlignment(Qt::AlignRight | Qt::AlignVCenter); l->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed); secondLineLayout->addWidget(l); // set min/max/step and value in points, then set actual unit d->lineWidth = new KisDoubleParseUnitSpinBox(this); d->lineWidth->setMinMaxStep(0.0, 1000.0, 0.5); d->lineWidth->setDecimals(2); d->lineWidth->setUnit(KoUnit(KoUnit::Point)); d->lineWidth->setToolTip(i18n("Set line width of actual selection")); secondLineLayout->addWidget(d->lineWidth); QToolButton *capNJoinButton = new QToolButton(this); capNJoinButton->setMinimumHeight(25); d->capNJoinMenu = new CapNJoinMenu(this); capNJoinButton->setMenu(d->capNJoinMenu); capNJoinButton->setText("..."); capNJoinButton->setPopupMode(QToolButton::InstantPopup); secondLineLayout->addWidget(capNJoinButton); d->colorButton = new QToolButton(this); secondLineLayout->addWidget(d->colorButton); d->colorAction = new KoColorPopupAction(this); d->colorAction->setIcon(koIcon("format-stroke-color")); d->colorAction->setToolTip(i18n("Change the color of the line/border")); d->colorButton->setDefaultAction(d->colorAction); mainLayout->addLayout(firstLineLayout); mainLayout->addLayout(secondLineLayout); // Spacer d->spacer = new QWidget(); d->spacer->setObjectName("SpecialSpacer"); mainLayout->addWidget(d->spacer); // set sensitive defaults d->lineStyle->setLineStyle(Qt::SolidLine); d->lineWidth->changeValue(1); d->colorAction->setCurrentColor(Qt::black); // Make the signals visible on the outside of this widget. connect(d->lineStyle, SIGNAL(currentIndexChanged(int)), this, SLOT(applyChanges())); connect(d->lineWidth, SIGNAL(valueChangedPt(qreal)), this, SLOT(applyChanges())); connect(d->colorAction, SIGNAL(colorChanged(const KoColor &)), this, SLOT(applyChanges())); connect(d->capNJoinMenu->capGroup, SIGNAL(buttonClicked(int)), this, SLOT(applyChanges())); connect(d->capNJoinMenu->joinGroup, SIGNAL(buttonClicked(int)), this, SLOT(applyChanges())); connect(d->capNJoinMenu->miterLimit, SIGNAL(valueChangedPt(qreal)), this, SLOT(applyChanges())); connect(d->startMarkerSelector, SIGNAL(currentIndexChanged(int)), this, SLOT(startMarkerChanged())); connect(d->endMarkerSelector, SIGNAL(currentIndexChanged(int)), this, SLOT(endMarkerChanged())); } KoStrokeConfigWidget::~KoStrokeConfigWidget() { delete d; } // ---------------------------------------------------------------- // getters and setters Qt::PenStyle KoStrokeConfigWidget::lineStyle() const { return d->lineStyle->lineStyle(); } QVector KoStrokeConfigWidget::lineDashes() const { return d->lineStyle->lineDashes(); } qreal KoStrokeConfigWidget::lineWidth() const { return d->lineWidth->value(); } QColor KoStrokeConfigWidget::color() const { return d->colorAction->currentColor(); } qreal KoStrokeConfigWidget::miterLimit() const { return d->capNJoinMenu->miterLimit->value(); } KoMarker *KoStrokeConfigWidget::startMarker() const { return d->startMarkerSelector->marker(); } KoMarker *KoStrokeConfigWidget::endMarker() const { return d->endMarkerSelector->marker(); } Qt::PenCapStyle KoStrokeConfigWidget::capStyle() const { return static_cast(d->capNJoinMenu->capGroup->checkedId()); } Qt::PenJoinStyle KoStrokeConfigWidget::joinStyle() const { return static_cast(d->capNJoinMenu->joinGroup->checkedId()); } KoShapeStroke* KoStrokeConfigWidget::createShapeStroke() const { KoShapeStroke *stroke = new KoShapeStroke(); stroke->setColor(color()); stroke->setLineWidth(lineWidth()); stroke->setCapStyle(capStyle()); stroke->setJoinStyle(joinStyle()); stroke->setMiterLimit(miterLimit()); stroke->setLineStyle(lineStyle(), lineDashes()); return stroke; } // ---------------------------------------------------------------- // Other public functions void KoStrokeConfigWidget::updateControls(KoShapeStrokeModel *stroke, KoMarker *startMarker, KoMarker *endMarker) { blockChildSignals(true); const KoShapeStroke *lineStroke = dynamic_cast(stroke); if (lineStroke) { d->lineWidth->changeValue(lineStroke->lineWidth()); QAbstractButton *button = d->capNJoinMenu->capGroup->button(lineStroke->capStyle()); if (button) { button->setChecked(true); } button = d->capNJoinMenu->joinGroup->button(lineStroke->joinStyle()); if (button) { button->setChecked(true); } d->capNJoinMenu->miterLimit->changeValue(lineStroke->miterLimit()); d->capNJoinMenu->miterLimit->setEnabled(lineStroke->joinStyle() == Qt::MiterJoin); d->lineStyle->setLineStyle(lineStroke->lineStyle(), lineStroke->lineDashes()); d->colorAction->setCurrentColor(lineStroke->color()); } else { d->lineWidth->changeValue(0.0); d->capNJoinMenu->capGroup->button(Qt::FlatCap)->setChecked(true); d->capNJoinMenu->joinGroup->button(Qt::MiterJoin)->setChecked(true); d->capNJoinMenu->miterLimit->changeValue(0.0); d->capNJoinMenu->miterLimit->setEnabled(true); d->lineStyle->setLineStyle(Qt::NoPen, QVector()); } d->startMarkerSelector->setMarker(startMarker); d->endMarkerSelector->setMarker(endMarker); blockChildSignals(false); } void KoStrokeConfigWidget::setUnit(const KoUnit &unit) { + if (!d->letUnitBeSet) { + return; //the unit management is completly transferd to the unitManagers. + } + blockChildSignals(true); KoCanvasController* canvasController = KoToolManager::instance()->activeCanvasController(); KoSelection *selection = canvasController->canvas()->shapeManager()->selection(); KoShape * shape = selection->firstSelectedShape(); /** * KoStrokeShape knows nothing about the transformations applied * to the shape, which doesn't prevent the shape to apply them and * display the stroke differently. So just take that into account * and show the user correct values using the multiplier in KoUnit. */ KoUnit newUnit(unit); if (shape) { newUnit.adjustByPixelTransform(shape->absoluteTransformation(0)); } d->lineWidth->setUnit(newUnit); d->capNJoinMenu->miterLimit->setUnit(newUnit); blockChildSignals(false); } void KoStrokeConfigWidget::updateMarkers(const QList &markers) { d->startMarkerSelector->updateMarkers(markers); d->endMarkerSelector->updateMarkers(markers); } void KoStrokeConfigWidget::blockChildSignals(bool block) { d->colorAction->blockSignals(block); d->lineWidth->blockSignals(block); d->capNJoinMenu->capGroup->blockSignals(block); d->capNJoinMenu->joinGroup->blockSignals(block); d->capNJoinMenu->miterLimit->blockSignals(block); d->lineStyle->blockSignals(block); d->startMarkerSelector->blockSignals(block); d->endMarkerSelector->blockSignals(block); } void KoStrokeConfigWidget::setActive(bool active) { d->active = active; } +void KoStrokeConfigWidget::setUnitManagers(KisSpinBoxUnitManager* managerLineWidth, + KisSpinBoxUnitManager *managerMitterLimit) +{ + blockChildSignals(true); + + d->letUnitBeSet = false; + + d->lineWidth->setUnitManager(managerLineWidth); + d->capNJoinMenu->miterLimit->setUnitManager(managerMitterLimit); + + blockChildSignals(false); +} + //------------------------ void KoStrokeConfigWidget::applyChanges() { KoCanvasController* canvasController = KoToolManager::instance()->activeCanvasController(); KoSelection *selection = canvasController->canvas()->shapeManager()->selection(); //FIXME d->canvas->resourceManager()->setActiveStroke( d->stroke ); if (!selection || !selection->count()) { return; } KoShapeStroke *newStroke = new KoShapeStroke(); KoShapeStroke *oldStroke = dynamic_cast( selection->firstSelectedShape()->stroke() ); if (oldStroke) { newStroke->setLineBrush(oldStroke->lineBrush()); } newStroke->setColor(color()); newStroke->setLineWidth(lineWidth()); newStroke->setCapStyle(static_cast(d->capNJoinMenu->capGroup->checkedId())); newStroke->setJoinStyle(static_cast(d->capNJoinMenu->joinGroup->checkedId())); newStroke->setMiterLimit(miterLimit()); newStroke->setLineStyle(lineStyle(), lineDashes()); if (d->active) { KoShapeStrokeCommand *cmd = new KoShapeStrokeCommand(selection->selectedShapes(), newStroke); canvasController->canvas()->addCommand(cmd); } } void KoStrokeConfigWidget::applyMarkerChanges(KoMarkerData::MarkerPosition position) { KoMarker *marker = 0; if (position == KoMarkerData::MarkerStart) { marker = startMarker(); } else if (position == KoMarkerData::MarkerEnd) { marker = endMarker(); } KoCanvasController* canvasController = KoToolManager::instance()->activeCanvasController(); KoSelection *selection = canvasController->canvas()->shapeManager()->selection(); if (! selection || !selection->count()) { return; } QList shapeList = selection->selectedShapes(); QList pathShapeList; for (QList::iterator itShape = shapeList.begin(); itShape != shapeList.end(); ++itShape) { KoPathShape* pathShape = dynamic_cast(*itShape); if (pathShape) { pathShapeList << pathShape; } } if (pathShapeList.size()) { KoPathShapeMarkerCommand* cmdMarker = new KoPathShapeMarkerCommand(pathShapeList, marker, position); canvasController->canvas()->addCommand(cmdMarker); } } void KoStrokeConfigWidget::startMarkerChanged() { applyMarkerChanges(KoMarkerData::MarkerStart); } void KoStrokeConfigWidget::endMarkerChanged() { applyMarkerChanges(KoMarkerData::MarkerEnd); } // ---------------------------------------------------------------- void KoStrokeConfigWidget::selectionChanged() { // see a comment in setUnit() setUnit(d->canvas->unit()); KoCanvasController* canvasController = KoToolManager::instance()->activeCanvasController(); KoSelection *selection = canvasController->canvas()->shapeManager()->selection(); KoShape * shape = selection->firstSelectedShape(); if (shape && shape->stroke()) { KoPathShape *pathShape = dynamic_cast(shape); if (pathShape) { updateControls(shape->stroke(), pathShape->marker(KoMarkerData::MarkerStart), pathShape->marker(KoMarkerData::MarkerEnd)); } else { updateControls(shape->stroke(), 0 ,0); } } } void KoStrokeConfigWidget::setCanvas( KoCanvasBase *canvas ) { if (canvas) { connect(canvas->shapeManager()->selection(), SIGNAL(selectionChanged()), this, SLOT(selectionChanged())); connect(canvas->shapeManager(), SIGNAL(selectionContentChanged()), this, SLOT(selectionChanged())); connect(canvas->resourceManager(), SIGNAL(canvasResourceChanged(int, const QVariant&)), this, SLOT(canvasResourceChanged(int, const QVariant &))); setUnit(canvas->unit()); KoDocumentResourceManager *resourceManager = canvas->shapeController()->resourceManager(); if (resourceManager) { KoMarkerCollection *collection = resourceManager->resource(KoDocumentResourceManager::MarkerCollection).value(); if (collection) { updateMarkers(collection->markers()); } } } d->canvas = canvas; } void KoStrokeConfigWidget::canvasResourceChanged(int key, const QVariant &value) { switch (key) { case KoCanvasResourceManager::Unit: setUnit(value.value()); break; } } diff --git a/libs/widgets/KoStrokeConfigWidget.h b/libs/widgets/KoStrokeConfigWidget.h index 129a074c19..18b8b27f08 100644 --- a/libs/widgets/KoStrokeConfigWidget.h +++ b/libs/widgets/KoStrokeConfigWidget.h @@ -1,104 +1,108 @@ /* This file is part of the KDE project * Made by Tomislav Lukman (tomislav.lukman@ck.tel.hr) * Copyright (C) 2002 Tomislav Lukman * Copyright (C) 2002 Rob Buis * Copyright (C) 2004 Laurent Montel * Copyright (C) 2005-2006 Tim Beaulen * Copyright (C) 2005 Inge Wallin * Copyright (C) 2005, 2011 Thomas Zander * Copyright (C) 2005-2008 Jan Hambrecht * Copyright (C) 2006 C. Boemann * Copyright (C) 2011 Jean-Nicolas Artaud * Copyright (C) 2011 Thorsten Zachmann * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This library 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 * Library General Public License for more details. * * You should have received a copy of the GNU Library General Public License * along with this library; see the file COPYING.LIB. If not, write to * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, * Boston, MA 02110-1301, USA. */ #ifndef STROKECONFIGWIDGET_H #define STROKECONFIGWIDGET_H #include "kritawidgets_export.h" #include #include class KoUnit; class KoShapeStrokeModel; class KoMarker; class KoCanvasBase; class KoShapeStroke; +class KisSpinBoxUnitManager; + /// A widget for configuring the stroke of a shape class KRITAWIDGETS_EXPORT KoStrokeConfigWidget : public QWidget { Q_OBJECT public: explicit KoStrokeConfigWidget(QWidget *parent); ~KoStrokeConfigWidget(); // Getters Qt::PenStyle lineStyle() const; QVector lineDashes() const; qreal lineWidth() const; QColor color() const; qreal miterLimit() const; KoMarker *startMarker() const; KoMarker *endMarker() const; Qt::PenCapStyle capStyle() const; Qt::PenJoinStyle joinStyle() const; /** * Creates KoShapeStroke object filled with the options * configured by the widget. The caller is in charge of * deletion of the returned object */ KoShapeStroke* createShapeStroke() const; void setCanvas(KoCanvasBase *canvas); void setActive(bool active); + void setUnitManagers(KisSpinBoxUnitManager* managerLineWidth, KisSpinBoxUnitManager* managerMitterLimit); + private Q_SLOTS: void updateControls(KoShapeStrokeModel *stroke, KoMarker *startMarker, KoMarker *endMarker); void updateMarkers(const QList &markers); /// start marker has changed void startMarkerChanged(); /// end marker has changed void endMarkerChanged(); void canvasResourceChanged(int key, const QVariant &value); /// selection has changed void selectionChanged(); /// apply line changes to the selected shape void applyChanges(); private: void setUnit(const KoUnit &unit); /// apply marker changes to the selected shape void applyMarkerChanges(KoMarkerData::MarkerPosition position); void blockChildSignals(bool block); private: class Private; Private * const d; }; #endif // SHADOWCONFIGWIDGET_H diff --git a/plugins/tools/defaulttool/defaulttool/DefaultTool.cpp b/plugins/tools/defaulttool/defaulttool/DefaultTool.cpp index 48b7a8fc9f..3b9486bc76 100644 --- a/plugins/tools/defaulttool/defaulttool/DefaultTool.cpp +++ b/plugins/tools/defaulttool/defaulttool/DefaultTool.cpp @@ -1,1241 +1,1245 @@ /* This file is part of the KDE project Copyright (C) 2006-2008 Thorsten Zachmann Copyright (C) 2006-2010 Thomas Zander Copyright (C) 2008-2009 Jan Hambrecht Copyright (C) 2008 C. Boemann This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This library 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 Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with this library; see the file COPYING.LIB. If not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, * Boston, MA 02110-1301, USA. */ #include "DefaultTool.h" #include "DefaultToolWidget.h" #include "DefaultToolArrangeWidget.h" #include "SelectionDecorator.h" #include "ShapeMoveStrategy.h" #include "ShapeRotateStrategy.h" #include "ShapeShearStrategy.h" #include "ShapeResizeStrategy.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "kis_action_registry.h" #include "kis_document_aware_spin_box_unit_manager.h" #include #include #include #include #include #include #include #define HANDLE_DISTANCE 10 class NopInteractionStrategy : public KoInteractionStrategy { public: explicit NopInteractionStrategy(KoToolBase *parent) : KoInteractionStrategy(parent) { } virtual KUndo2Command *createCommand() { return 0; } virtual void handleMouseMove(const QPointF & /*mouseLocation*/, Qt::KeyboardModifiers /*modifiers*/) {} virtual void finishInteraction(Qt::KeyboardModifiers /*modifiers*/) {} }; class SelectionHandler : public KoToolSelection { public: SelectionHandler(DefaultTool *parent) : KoToolSelection(parent) , m_selection(parent->koSelection()) { Q_ASSERT(m_selection); } bool hasSelection() { return m_selection->count(); } private: KoSelection *m_selection; }; DefaultTool::DefaultTool(KoCanvasBase *canvas) : KoInteractionTool(canvas) , m_lastHandle(KoFlake::NoHandle) , m_hotPosition(KoFlake::TopLeftCorner) , m_mouseWasInsideHandles(false) , m_moveCommand(0) , m_selectionHandler(new SelectionHandler(this)) , m_customEventStrategy(0) { setupActions(); QPixmap rotatePixmap, shearPixmap; rotatePixmap.load(":/cursor_rotate.png"); Q_ASSERT(!rotatePixmap.isNull()); shearPixmap.load(":/cursor_shear.png"); Q_ASSERT(!shearPixmap.isNull()); m_rotateCursors[0] = QCursor(rotatePixmap.transformed(QTransform().rotate(45))); m_rotateCursors[1] = QCursor(rotatePixmap.transformed(QTransform().rotate(90))); m_rotateCursors[2] = QCursor(rotatePixmap.transformed(QTransform().rotate(135))); m_rotateCursors[3] = QCursor(rotatePixmap.transformed(QTransform().rotate(180))); m_rotateCursors[4] = QCursor(rotatePixmap.transformed(QTransform().rotate(225))); m_rotateCursors[5] = QCursor(rotatePixmap.transformed(QTransform().rotate(270))); m_rotateCursors[6] = QCursor(rotatePixmap.transformed(QTransform().rotate(315))); m_rotateCursors[7] = QCursor(rotatePixmap); /* m_rotateCursors[0] = QCursor(Qt::RotateNCursor); m_rotateCursors[1] = QCursor(Qt::RotateNECursor); m_rotateCursors[2] = QCursor(Qt::RotateECursor); m_rotateCursors[3] = QCursor(Qt::RotateSECursor); m_rotateCursors[4] = QCursor(Qt::RotateSCursor); m_rotateCursors[5] = QCursor(Qt::RotateSWCursor); m_rotateCursors[6] = QCursor(Qt::RotateWCursor); m_rotateCursors[7] = QCursor(Qt::RotateNWCursor); */ m_shearCursors[0] = QCursor(shearPixmap); m_shearCursors[1] = QCursor(shearPixmap.transformed(QTransform().rotate(45))); m_shearCursors[2] = QCursor(shearPixmap.transformed(QTransform().rotate(90))); m_shearCursors[3] = QCursor(shearPixmap.transformed(QTransform().rotate(135))); m_shearCursors[4] = QCursor(shearPixmap.transformed(QTransform().rotate(180))); m_shearCursors[5] = QCursor(shearPixmap.transformed(QTransform().rotate(225))); m_shearCursors[6] = QCursor(shearPixmap.transformed(QTransform().rotate(270))); m_shearCursors[7] = QCursor(shearPixmap.transformed(QTransform().rotate(315))); m_sizeCursors[0] = Qt::SizeVerCursor; m_sizeCursors[1] = Qt::SizeBDiagCursor; m_sizeCursors[2] = Qt::SizeHorCursor; m_sizeCursors[3] = Qt::SizeFDiagCursor; m_sizeCursors[4] = Qt::SizeVerCursor; m_sizeCursors[5] = Qt::SizeBDiagCursor; m_sizeCursors[6] = Qt::SizeHorCursor; m_sizeCursors[7] = Qt::SizeFDiagCursor; KoShapeManager *manager = canvas->shapeManager(); connect(manager, SIGNAL(selectionChanged()), this, SLOT(updateActions())); } DefaultTool::~DefaultTool() { } bool DefaultTool::wantsAutoScroll() const { return true; } void DefaultTool::setupActions() { KisActionRegistry *actionRegistry = KisActionRegistry::instance(); QAction *actionBringToFront = actionRegistry->makeQAction("object_order_front", this); addAction("object_order_front", actionBringToFront); connect(actionBringToFront, SIGNAL(triggered()), this, SLOT(selectionBringToFront())); QAction *actionRaise = actionRegistry->makeQAction("object_order_raise", this); addAction("object_order_raise", actionRaise); connect(actionRaise, SIGNAL(triggered()), this, SLOT(selectionMoveUp())); QAction *actionLower = actionRegistry->makeQAction("object_order_lower", this); addAction("object_order_lower", actionLower); connect(actionLower, SIGNAL(triggered()), this, SLOT(selectionMoveDown())); QAction *actionSendToBack = actionRegistry->makeQAction("object_order_back", this); addAction("object_order_back", actionSendToBack); connect(actionSendToBack, SIGNAL(triggered()), this, SLOT(selectionSendToBack())); QAction *actionAlignLeft = actionRegistry->makeQAction("object_align_horizontal_left", this); addAction("object_align_horizontal_left", actionAlignLeft); connect(actionAlignLeft, SIGNAL(triggered()), this, SLOT(selectionAlignHorizontalLeft())); QAction *actionAlignCenter = actionRegistry->makeQAction("object_align_horizontal_center", this); addAction("object_align_horizontal_center", actionAlignCenter); connect(actionAlignCenter, SIGNAL(triggered()), this, SLOT(selectionAlignHorizontalCenter())); QAction *actionAlignRight = actionRegistry->makeQAction("object_align_horizontal_right", this); addAction("object_align_horizontal_right", actionAlignRight); connect(actionAlignRight, SIGNAL(triggered()), this, SLOT(selectionAlignHorizontalRight())); QAction *actionAlignTop = actionRegistry->makeQAction("object_align_vertical_top", this); addAction("object_align_vertical_top", actionAlignTop); connect(actionAlignTop, SIGNAL(triggered()), this, SLOT(selectionAlignVerticalTop())); QAction *actionAlignMiddle = actionRegistry->makeQAction("object_align_vertical_center", this); addAction("object_align_vertical_center", actionAlignMiddle); connect(actionAlignMiddle, SIGNAL(triggered()), this, SLOT(selectionAlignVerticalCenter())); QAction *actionAlignBottom = actionRegistry->makeQAction("object_align_vertical_bottom", this); addAction("object_align_vertical_bottom", actionAlignBottom); connect(actionAlignBottom, SIGNAL(triggered()), this, SLOT(selectionAlignVerticalBottom())); QAction *actionGroupBottom = actionRegistry->makeQAction("object_group", this); addAction("object_group", actionGroupBottom); connect(actionGroupBottom, SIGNAL(triggered()), this, SLOT(selectionGroup())); QAction *actionUngroupBottom = actionRegistry->makeQAction("object_ungroup", this); addAction("object_ungroup", actionUngroupBottom); connect(actionUngroupBottom, SIGNAL(triggered()), this, SLOT(selectionUngroup())); } qreal DefaultTool::rotationOfHandle(KoFlake::SelectionHandle handle, bool useEdgeRotation) { QPointF selectionCenter = koSelection()->absolutePosition(); QPointF direction; switch (handle) { case KoFlake::TopMiddleHandle: if (useEdgeRotation) { direction = koSelection()->absolutePosition(KoFlake::TopRightCorner) - koSelection()->absolutePosition(KoFlake::TopLeftCorner); } else { QPointF handlePosition = koSelection()->absolutePosition(KoFlake::TopLeftCorner); handlePosition += 0.5 * (koSelection()->absolutePosition(KoFlake::TopRightCorner) - handlePosition); direction = handlePosition - selectionCenter; } break; case KoFlake::TopRightHandle: direction = (QVector2D(koSelection()->absolutePosition(KoFlake::TopRightCorner) - koSelection()->absolutePosition(KoFlake::TopLeftCorner)).normalized() + QVector2D(koSelection()->absolutePosition(KoFlake::TopRightCorner) - koSelection()->absolutePosition(KoFlake::BottomRightCorner)).normalized()).toPointF(); break; case KoFlake::RightMiddleHandle: if (useEdgeRotation) { direction = koSelection()->absolutePosition(KoFlake::BottomRightCorner) - koSelection()->absolutePosition(KoFlake::TopRightCorner); } else { QPointF handlePosition = koSelection()->absolutePosition(KoFlake::TopRightCorner); handlePosition += 0.5 * (koSelection()->absolutePosition(KoFlake::BottomRightCorner) - handlePosition); direction = handlePosition - selectionCenter; } break; case KoFlake::BottomRightHandle: direction = (QVector2D(koSelection()->absolutePosition(KoFlake::BottomRightCorner) - koSelection()->absolutePosition(KoFlake::BottomLeftCorner)).normalized() + QVector2D(koSelection()->absolutePosition(KoFlake::BottomRightCorner) - koSelection()->absolutePosition(KoFlake::TopRightCorner)).normalized()).toPointF(); break; case KoFlake::BottomMiddleHandle: if (useEdgeRotation) { direction = koSelection()->absolutePosition(KoFlake::BottomLeftCorner) - koSelection()->absolutePosition(KoFlake::BottomRightCorner); } else { QPointF handlePosition = koSelection()->absolutePosition(KoFlake::BottomLeftCorner); handlePosition += 0.5 * (koSelection()->absolutePosition(KoFlake::BottomRightCorner) - handlePosition); direction = handlePosition - selectionCenter; } break; case KoFlake::BottomLeftHandle: direction = koSelection()->absolutePosition(KoFlake::BottomLeftCorner) - selectionCenter; direction = (QVector2D(koSelection()->absolutePosition(KoFlake::BottomLeftCorner) - koSelection()->absolutePosition(KoFlake::BottomRightCorner)).normalized() + QVector2D(koSelection()->absolutePosition(KoFlake::BottomLeftCorner) - koSelection()->absolutePosition(KoFlake::TopLeftCorner)).normalized()).toPointF(); break; case KoFlake::LeftMiddleHandle: if (useEdgeRotation) { direction = koSelection()->absolutePosition(KoFlake::TopLeftCorner) - koSelection()->absolutePosition(KoFlake::BottomLeftCorner); } else { QPointF handlePosition = koSelection()->absolutePosition(KoFlake::TopLeftCorner); handlePosition += 0.5 * (koSelection()->absolutePosition(KoFlake::BottomLeftCorner) - handlePosition); direction = handlePosition - selectionCenter; } break; case KoFlake::TopLeftHandle: direction = koSelection()->absolutePosition(KoFlake::TopLeftCorner) - selectionCenter; direction = (QVector2D(koSelection()->absolutePosition(KoFlake::TopLeftCorner) - koSelection()->absolutePosition(KoFlake::TopRightCorner)).normalized() + QVector2D(koSelection()->absolutePosition(KoFlake::TopLeftCorner) - koSelection()->absolutePosition(KoFlake::BottomLeftCorner)).normalized()).toPointF(); break; case KoFlake::NoHandle: return 0.0; break; } qreal rotation = atan2(direction.y(), direction.x()) * 180.0 / M_PI; switch (handle) { case KoFlake::TopMiddleHandle: if (useEdgeRotation) { rotation -= 0.0; } else { rotation -= 270.0; } break; case KoFlake::TopRightHandle: rotation -= 315.0; break; case KoFlake::RightMiddleHandle: if (useEdgeRotation) { rotation -= 90.0; } else { rotation -= 0.0; } break; case KoFlake::BottomRightHandle: rotation -= 45.0; break; case KoFlake::BottomMiddleHandle: if (useEdgeRotation) { rotation -= 180.0; } else { rotation -= 90.0; } break; case KoFlake::BottomLeftHandle: rotation -= 135.0; break; case KoFlake::LeftMiddleHandle: if (useEdgeRotation) { rotation -= 270.0; } else { rotation -= 180.0; } break; case KoFlake::TopLeftHandle: rotation -= 225.0; break; case KoFlake::NoHandle: break; } if (rotation < 0.0) { rotation += 360.0; } return rotation; } void DefaultTool::updateCursor() { QCursor cursor = Qt::ArrowCursor; QString statusText; if (koSelection()->count() > 0) { // has a selection bool editable = editableShapesCount(koSelection()->selectedShapes(KoFlake::StrippedSelection)); if (!m_mouseWasInsideHandles) { m_angle = rotationOfHandle(m_lastHandle, true); int rotOctant = 8 + int(8.5 + m_angle / 45); bool rotateHandle = false; bool shearHandle = false; switch (m_lastHandle) { case KoFlake::TopMiddleHandle: cursor = m_shearCursors[(0 + rotOctant) % 8]; shearHandle = true; break; case KoFlake::TopRightHandle: cursor = m_rotateCursors[(1 + rotOctant) % 8]; rotateHandle = true; break; case KoFlake::RightMiddleHandle: cursor = m_shearCursors[(2 + rotOctant) % 8]; shearHandle = true; break; case KoFlake::BottomRightHandle: cursor = m_rotateCursors[(3 + rotOctant) % 8]; rotateHandle = true; break; case KoFlake::BottomMiddleHandle: cursor = m_shearCursors[(4 + rotOctant) % 8]; shearHandle = true; break; case KoFlake::BottomLeftHandle: cursor = m_rotateCursors[(5 + rotOctant) % 8]; rotateHandle = true; break; case KoFlake::LeftMiddleHandle: cursor = m_shearCursors[(6 + rotOctant) % 8]; shearHandle = true; break; case KoFlake::TopLeftHandle: cursor = m_rotateCursors[(7 + rotOctant) % 8]; rotateHandle = true; break; case KoFlake::NoHandle: cursor = Qt::ArrowCursor; break; } if (rotateHandle) { statusText = i18n("Left click rotates around center, right click around highlighted position."); } if (shearHandle) { statusText = i18n("Click and drag to shear selection."); } } else { statusText = i18n("Click and drag to resize selection."); m_angle = rotationOfHandle(m_lastHandle, false); int rotOctant = 8 + int(8.5 + m_angle / 45); bool cornerHandle = false; switch (m_lastHandle) { case KoFlake::TopMiddleHandle: cursor = m_sizeCursors[(0 + rotOctant) % 8]; break; case KoFlake::TopRightHandle: cursor = m_sizeCursors[(1 + rotOctant) % 8]; cornerHandle = true; break; case KoFlake::RightMiddleHandle: cursor = m_sizeCursors[(2 + rotOctant) % 8]; break; case KoFlake::BottomRightHandle: cursor = m_sizeCursors[(3 + rotOctant) % 8]; cornerHandle = true; break; case KoFlake::BottomMiddleHandle: cursor = m_sizeCursors[(4 + rotOctant) % 8]; break; case KoFlake::BottomLeftHandle: cursor = m_sizeCursors[(5 + rotOctant) % 8]; cornerHandle = true; break; case KoFlake::LeftMiddleHandle: cursor = m_sizeCursors[(6 + rotOctant) % 8]; break; case KoFlake::TopLeftHandle: cursor = m_sizeCursors[(7 + rotOctant) % 8]; cornerHandle = true; break; case KoFlake::NoHandle: cursor = Qt::SizeAllCursor; statusText = i18n("Click and drag to move selection."); break; } if (cornerHandle) { statusText = i18n("Click and drag to resize selection. Middle click to set highlighted position."); } } if (!editable) { cursor = Qt::ArrowCursor; } } else { // there used to be guides... :'''( } useCursor(cursor); if (currentStrategy() == 0) { emit statusTextChanged(statusText); } } void DefaultTool::paint(QPainter &painter, const KoViewConverter &converter) { KoInteractionTool::paint(painter, converter); if (currentStrategy() == 0 && koSelection()->count() > 0) { SelectionDecorator decorator(m_mouseWasInsideHandles ? m_lastHandle : KoFlake::NoHandle, true, true); decorator.setSelection(koSelection()); decorator.setHandleRadius(handleRadius()); decorator.setHotPosition(m_hotPosition); decorator.paint(painter, converter); } painter.save(); KoShape::applyConversion(painter, converter); canvas()->snapGuide()->paint(painter, converter); painter.restore(); } void DefaultTool::mousePressEvent(KoPointerEvent *event) { KoInteractionTool::mousePressEvent(event); updateCursor(); } void DefaultTool::mouseMoveEvent(KoPointerEvent *event) { KoInteractionTool::mouseMoveEvent(event); if (currentStrategy() == 0 && koSelection()->count() > 0) { QRectF bound = handlesSize(); if (bound.contains(event->point)) { bool inside; KoFlake::SelectionHandle newDirection = handleAt(event->point, &inside); if (inside != m_mouseWasInsideHandles || m_lastHandle != newDirection) { m_lastHandle = newDirection; m_mouseWasInsideHandles = inside; //repaintDecorations(); } } else { /*if (m_lastHandle != KoFlake::NoHandle) repaintDecorations(); */ m_lastHandle = KoFlake::NoHandle; m_mouseWasInsideHandles = false; // there used to be guides... :'''( } } else { // there used to be guides... :'''( } updateCursor(); } QRectF DefaultTool::handlesSize() { QRectF bound = koSelection()->boundingRect(); // expansion Border if (!canvas() || !canvas()->viewConverter()) { return bound; } QPointF border = canvas()->viewConverter()->viewToDocument(QPointF(HANDLE_DISTANCE, HANDLE_DISTANCE)); bound.adjust(-border.x(), -border.y(), border.x(), border.y()); return bound; } void DefaultTool::mouseReleaseEvent(KoPointerEvent *event) { KoInteractionTool::mouseReleaseEvent(event); updateCursor(); } void DefaultTool::mouseDoubleClickEvent(KoPointerEvent *event) { QList shapes; Q_FOREACH (KoShape *shape, koSelection()->selectedShapes()) { if (shape->boundingRect().contains(event->point) && // first 'cheap' check shape->outline().contains(event->point)) { // this is more expensive but weeds out the almost hits shapes.append(shape); } } if (shapes.count() == 0) { // nothing in the selection was clicked on. KoShape *shape = canvas()->shapeManager()->shapeAt(event->point, KoFlake::ShapeOnTop); if (shape) { shapes.append(shape); } // there used to be guides... :'''( } QList shapes2; foreach (KoShape *shape, shapes) { QSet delegates = shape->toolDelegates(); if (delegates.isEmpty()) { shapes2.append(shape); } else { foreach (KoShape *delegatedShape, delegates) { shapes2.append(delegatedShape); } } } KoToolManager::instance()->switchToolRequested( KoToolManager::instance()->preferredToolForSelection(shapes2)); } bool DefaultTool::moveSelection(int direction, Qt::KeyboardModifiers modifiers) { qreal x = 0.0, y = 0.0; if (direction == Qt::Key_Left) { x = -5; } else if (direction == Qt::Key_Right) { x = 5; } else if (direction == Qt::Key_Up) { y = -5; } else if (direction == Qt::Key_Down) { y = 5; } if (x != 0.0 || y != 0.0) { // actually move if ((modifiers & Qt::ShiftModifier) != 0) { x *= 10; y *= 10; } else if ((modifiers & Qt::AltModifier) != 0) { // more precise x /= 5; y /= 5; } QList prevPos; QList newPos; QList shapes; Q_FOREACH (KoShape *shape, koSelection()->selectedShapes(KoFlake::TopLevelSelection)) { if (shape->isGeometryProtected()) { continue; } shapes.append(shape); QPointF p = shape->position(); prevPos.append(p); p.setX(p.x() + x); p.setY(p.y() + y); newPos.append(p); } if (shapes.count() > 0) { // use a timeout to make sure we don't reuse a command possibly deleted by the commandHistory if (m_lastUsedMoveCommand.msecsTo(QTime::currentTime()) > 5000) { m_moveCommand = 0; } if (m_moveCommand) { // alter previous instead of creating new one. m_moveCommand->setNewPositions(newPos); m_moveCommand->redo(); } else { m_moveCommand = new KoShapeMoveCommand(shapes, prevPos, newPos); canvas()->addCommand(m_moveCommand); } m_lastUsedMoveCommand = QTime::currentTime(); return true; } } return false; } void DefaultTool::keyPressEvent(QKeyEvent *event) { KoInteractionTool::keyPressEvent(event); if (currentStrategy() == 0) { switch (event->key()) { case Qt::Key_Left: case Qt::Key_Right: case Qt::Key_Up: case Qt::Key_Down: if (moveSelection(event->key(), event->modifiers())) { event->accept(); } break; case Qt::Key_1: case Qt::Key_2: case Qt::Key_3: case Qt::Key_4: case Qt::Key_5: canvas()->resourceManager()->setResource(HotPosition, event->key() - Qt::Key_1); event->accept(); break; default: return; } } } void DefaultTool::customMoveEvent(KoPointerEvent *event) { if (!koSelection()->count()) { event->ignore(); return; } int move = qMax(qAbs(event->x()), qAbs(event->y())); int zoom = qAbs(event->z()); int rotate = qAbs(event->rotationZ()); const int threshold = 2; if (move < threshold && zoom < threshold && rotate < threshold) { if (m_customEventStrategy) { m_customEventStrategy->finishInteraction(event->modifiers()); KUndo2Command *command = m_customEventStrategy->createCommand(); if (command) { canvas()->addCommand(command); } delete m_customEventStrategy; m_customEventStrategy = 0; repaintDecorations(); } event->accept(); return; } // check if the z-movement is dominant if (zoom > move && zoom > rotate) { // zoom if (!m_customEventStrategy) { m_customEventStrategy = new ShapeResizeStrategy(this, event->point, KoFlake::TopLeftHandle); } } else if (move > zoom && move > rotate) { // check if x-/y-movement is dominant // move if (!m_customEventStrategy) { m_customEventStrategy = new ShapeMoveStrategy(this, event->point); } } else if (rotate > zoom && rotate > move) { // rotation is dominant // rotate if (!m_customEventStrategy) { m_customEventStrategy = new ShapeRotateStrategy(this, event->point, event->buttons()); } } if (m_customEventStrategy) { m_customEventStrategy->handleCustomEvent(event); } event->accept(); } void DefaultTool::repaintDecorations() { Q_ASSERT(koSelection()); if (koSelection()->count() > 0) { canvas()->updateCanvas(handlesSize()); } } void DefaultTool::copy() const { QList shapes = canvas()->shapeManager()->selection()->selectedShapes(KoFlake::TopLevelSelection); if (!shapes.empty()) { KoShapeOdfSaveHelper saveHelper(shapes); KoDrag drag; drag.setOdf(KoOdf::mimeType(KoOdf::Text), saveHelper); drag.addToClipboard(); } } void DefaultTool::deleteSelection() { QList shapes; foreach (KoShape *s, canvas()->shapeManager()->selection()->selectedShapes(KoFlake::TopLevelSelection)) { if (s->isGeometryProtected()) { continue; } shapes << s; } if (!shapes.empty()) { canvas()->addCommand(canvas()->shapeController()->removeShapes(shapes)); } } bool DefaultTool::paste() { // we no longer have to do anything as tool Proxy will do it for us return false; } QStringList DefaultTool::supportedPasteMimeTypes() const { QStringList list; list << KoOdf::mimeType(KoOdf::Text); return list; } KoSelection *DefaultTool::koSelection() { Q_ASSERT(canvas()); Q_ASSERT(canvas()->shapeManager()); return canvas()->shapeManager()->selection(); } KoFlake::SelectionHandle DefaultTool::handleAt(const QPointF &point, bool *innerHandleMeaning) { // check for handles in this order; meaning that when handles overlap the one on top is chosen static const KoFlake::SelectionHandle handleOrder[] = { KoFlake::BottomRightHandle, KoFlake::TopLeftHandle, KoFlake::BottomLeftHandle, KoFlake::TopRightHandle, KoFlake::BottomMiddleHandle, KoFlake::RightMiddleHandle, KoFlake::LeftMiddleHandle, KoFlake::TopMiddleHandle, KoFlake::NoHandle }; if (koSelection()->count() == 0) { return KoFlake::NoHandle; } recalcSelectionBox(); const KoViewConverter *converter = canvas()->viewConverter(); if (!converter) { return KoFlake::NoHandle; } if (innerHandleMeaning != 0) { QPainterPath path; path.addPolygon(m_selectionOutline); *innerHandleMeaning = path.contains(point) || path.intersects(handlePaintRect(point)); } for (int i = 0; i < KoFlake::NoHandle; ++i) { KoFlake::SelectionHandle handle = handleOrder[i]; QPointF pt = converter->documentToView(point) - converter->documentToView(m_selectionBox[handle]); // if just inside the outline if (qAbs(pt.x()) < HANDLE_DISTANCE && qAbs(pt.y()) < HANDLE_DISTANCE) { if (innerHandleMeaning != 0) { if (qAbs(pt.x()) < 4 && qAbs(pt.y()) < 4) { *innerHandleMeaning = true; } } return handle; } } return KoFlake::NoHandle; } void DefaultTool::recalcSelectionBox() { if (koSelection()->count() == 0) { return; } if (koSelection()->count() > 1) { QTransform matrix = koSelection()->absoluteTransformation(0); m_selectionOutline = matrix.map(QPolygonF(QRectF(QPointF(0, 0), koSelection()->size()))); m_angle = 0.0; //koSelection()->rotation(); } else { QTransform matrix = koSelection()->firstSelectedShape()->absoluteTransformation(0); m_selectionOutline = matrix.map(QPolygonF(QRectF(QPointF(0, 0), koSelection()->firstSelectedShape()->size()))); m_angle = 0.0; //koSelection()->firstSelectedShape()->rotation(); } QPolygonF outline = m_selectionOutline; //shorter name in the following :) m_selectionBox[KoFlake::TopMiddleHandle] = (outline.value(0) + outline.value(1)) / 2; m_selectionBox[KoFlake::TopRightHandle] = outline.value(1); m_selectionBox[KoFlake::RightMiddleHandle] = (outline.value(1) + outline.value(2)) / 2; m_selectionBox[KoFlake::BottomRightHandle] = outline.value(2); m_selectionBox[KoFlake::BottomMiddleHandle] = (outline.value(2) + outline.value(3)) / 2; m_selectionBox[KoFlake::BottomLeftHandle] = outline.value(3); m_selectionBox[KoFlake::LeftMiddleHandle] = (outline.value(3) + outline.value(0)) / 2; m_selectionBox[KoFlake::TopLeftHandle] = outline.value(0); if (koSelection()->count() == 1) { #if 0 // TODO detect mirroring KoShape *s = koSelection()->firstSelectedShape(); if (s->scaleX() < 0) { // vertically mirrored: swap left / right qSwap(m_selectionBox[KoFlake::TopLeftHandle], m_selectionBox[KoFlake::TopRightHandle]); qSwap(m_selectionBox[KoFlake::LeftMiddleHandle], m_selectionBox[KoFlake::RightMiddleHandle]); qSwap(m_selectionBox[KoFlake::BottomLeftHandle], m_selectionBox[KoFlake::BottomRightHandle]); } if (s->scaleY() < 0) { // vertically mirrored: swap top / bottom qSwap(m_selectionBox[KoFlake::TopLeftHandle], m_selectionBox[KoFlake::BottomLeftHandle]); qSwap(m_selectionBox[KoFlake::TopMiddleHandle], m_selectionBox[KoFlake::BottomMiddleHandle]); qSwap(m_selectionBox[KoFlake::TopRightHandle], m_selectionBox[KoFlake::BottomRightHandle]); } #endif } } void DefaultTool::activate(ToolActivation, const QSet &) { m_mouseWasInsideHandles = false; m_lastHandle = KoFlake::NoHandle; useCursor(Qt::ArrowCursor); repaintDecorations(); updateActions(); } void DefaultTool::selectionAlignHorizontalLeft() { selectionAlign(KoShapeAlignCommand::HorizontalLeftAlignment); } void DefaultTool::selectionAlignHorizontalCenter() { selectionAlign(KoShapeAlignCommand::HorizontalCenterAlignment); } void DefaultTool::selectionAlignHorizontalRight() { selectionAlign(KoShapeAlignCommand::HorizontalRightAlignment); } void DefaultTool::selectionAlignVerticalTop() { selectionAlign(KoShapeAlignCommand::VerticalTopAlignment); } void DefaultTool::selectionAlignVerticalCenter() { selectionAlign(KoShapeAlignCommand::VerticalCenterAlignment); } void DefaultTool::selectionAlignVerticalBottom() { selectionAlign(KoShapeAlignCommand::VerticalBottomAlignment); } void DefaultTool::selectionGroup() { KoSelection *selection = koSelection(); if (!selection) { return; } QList selectedShapes = selection->selectedShapes(KoFlake::TopLevelSelection); QList groupedShapes; // only group shapes with an unselected parent foreach (KoShape *shape, selectedShapes) { if (!selectedShapes.contains(shape->parent()) && shape->isEditable()) { groupedShapes << shape; } } KoShapeGroup *group = new KoShapeGroup(); // TODO what if only one shape is left? KUndo2Command *cmd = new KUndo2Command(kundo2_i18n("Group shapes")); canvas()->shapeController()->addShapeDirect(group, cmd); KoShapeGroupCommand::createCommand(group, groupedShapes, cmd); canvas()->addCommand(cmd); // update selection so we can ungroup immediately again selection->deselectAll(); selection->select(group); } void DefaultTool::selectionUngroup() { KoSelection *selection = canvas()->shapeManager()->selection(); if (!selection) { return; } QList selectedShapes = selection->selectedShapes(KoFlake::TopLevelSelection); QList containerSet; // only ungroup shape groups with an unselected parent foreach (KoShape *shape, selectedShapes) { if (!selectedShapes.contains(shape->parent()) && shape->isEditable()) { containerSet << shape; } } KUndo2Command *cmd = 0; // add a ungroup command for each found shape container to the macro command Q_FOREACH (KoShape *shape, containerSet) { KoShapeGroup *group = dynamic_cast(shape); if (group) { cmd = cmd ? cmd : new KUndo2Command(kundo2_i18n("Ungroup shapes")); new KoShapeUngroupCommand(group, group->shapes(), group->parent() ? QList() : canvas()->shapeManager()->topLevelShapes(), cmd); canvas()->shapeController()->removeShape(group, cmd); } } if (cmd) { canvas()->addCommand(cmd); } } void DefaultTool::selectionAlign(KoShapeAlignCommand::Align align) { KoSelection *selection = canvas()->shapeManager()->selection(); if (!selection) { return; } QList selectedShapes = selection->selectedShapes(KoFlake::TopLevelSelection); if (selectedShapes.count() < 1) { return; } QList editableShapes = filterEditableShapes(selectedShapes); // TODO add an option to the widget so that one can align to the page // with multiple selected shapes too QRectF bb; // single selected shape is automatically aligned to document rect if (editableShapes.count() == 1) { if (!canvas()->resourceManager()->hasResource(KoCanvasResourceManager::PageSize)) { return; } bb = QRectF(QPointF(0, 0), canvas()->resourceManager()->sizeResource(KoCanvasResourceManager::PageSize)); } else { Q_FOREACH (KoShape *shape, editableShapes) { bb |= shape->boundingRect(); } } KoShapeAlignCommand *cmd = new KoShapeAlignCommand(editableShapes, align, bb); canvas()->addCommand(cmd); selection->updateSizeAndPosition(); } void DefaultTool::selectionBringToFront() { selectionReorder(KoShapeReorderCommand::BringToFront); } void DefaultTool::selectionMoveUp() { selectionReorder(KoShapeReorderCommand::RaiseShape); } void DefaultTool::selectionMoveDown() { selectionReorder(KoShapeReorderCommand::LowerShape); } void DefaultTool::selectionSendToBack() { selectionReorder(KoShapeReorderCommand::SendToBack); } void DefaultTool::selectionReorder(KoShapeReorderCommand::MoveShapeType order) { KoSelection *selection = canvas()->shapeManager()->selection(); if (!selection) { return; } QList selectedShapes = selection->selectedShapes(KoFlake::TopLevelSelection); if (selectedShapes.count() < 1) { return; } QList editableShapes = filterEditableShapes(selectedShapes); if (editableShapes.count() < 1) { return; } KUndo2Command *cmd = KoShapeReorderCommand::createCommand(editableShapes, canvas()->shapeManager(), order); if (cmd) { canvas()->addCommand(cmd); } } QList > DefaultTool::createOptionWidgets() { QList > widgets; DefaultToolArrangeWidget *defaultArrange = new DefaultToolArrangeWidget(this); defaultArrange->setWindowTitle(i18n("Arrange")); widgets.append(defaultArrange); DefaultToolWidget *defaultTool = new DefaultToolWidget(this); defaultTool->setWindowTitle(i18n("Geometry")); widgets.append(defaultTool); + KoStrokeConfigWidget *strokeWidget = new KoStrokeConfigWidget(0); + KisDocumentAwareSpinBoxUnitManager* managerLineWidth = new KisDocumentAwareSpinBoxUnitManager(strokeWidget); + KisDocumentAwareSpinBoxUnitManager* managerMitterLimit = new KisDocumentAwareSpinBoxUnitManager(strokeWidget); + strokeWidget->setUnitManagers(managerLineWidth, managerMitterLimit); strokeWidget->setWindowTitle(i18n("Line")); strokeWidget->setCanvas(canvas()); widgets.append(strokeWidget); KoFillConfigWidget *fillWidget = new KoFillConfigWidget(0); fillWidget->setWindowTitle(i18n("Fill")); fillWidget->setCanvas(canvas()); widgets.append(fillWidget); KoShadowConfigWidget *shadowWidget = new KoShadowConfigWidget(0); KisDocumentAwareSpinBoxUnitManager* managerBlur = new KisDocumentAwareSpinBoxUnitManager(shadowWidget); //let the shadow widget be aware of document relative units. KisDocumentAwareSpinBoxUnitManager* managerOffset = new KisDocumentAwareSpinBoxUnitManager(shadowWidget); //let the shadow widget be aware of document relative units. - shadowWidget->setUnitManager(managerBlur, managerOffset); + shadowWidget->setUnitManagers(managerBlur, managerOffset); shadowWidget->setWindowTitle(i18n("Shadow")); shadowWidget->setCanvas(canvas()); widgets.append(shadowWidget); return widgets; } void DefaultTool::canvasResourceChanged(int key, const QVariant &res) { if (key == HotPosition) { m_hotPosition = static_cast(res.toInt()); repaintDecorations(); } } KoInteractionStrategy *DefaultTool::createStrategy(KoPointerEvent *event) { // reset the move by keys when a new strategy is created otherwise we might change the // command after a new command was added. This happend when you where faster than the timer. m_moveCommand = 0; KoShapeManager *shapeManager = canvas()->shapeManager(); KoSelection *select = shapeManager->selection(); bool insideSelection; KoFlake::SelectionHandle handle = handleAt(event->point, &insideSelection); bool editableShape = editableShapesCount(select->selectedShapes()); if (event->buttons() & Qt::MidButton) { // change the hot selection position when middle clicking on a handle KoFlake::Position newHotPosition = m_hotPosition; switch (handle) { case KoFlake::TopLeftHandle: newHotPosition = KoFlake::TopLeftCorner; break; case KoFlake::TopRightHandle: newHotPosition = KoFlake::TopRightCorner; break; case KoFlake::BottomLeftHandle: newHotPosition = KoFlake::BottomLeftCorner; break; case KoFlake::BottomRightHandle: newHotPosition = KoFlake::BottomRightCorner; break; default: { // check if we had hit the center point const KoViewConverter *converter = canvas()->viewConverter(); QPointF pt = converter->documentToView(event->point - select->absolutePosition()); if (qAbs(pt.x()) < HANDLE_DISTANCE && qAbs(pt.y()) < HANDLE_DISTANCE) { newHotPosition = KoFlake::CenteredPosition; } break; } } if (m_hotPosition != newHotPosition) { canvas()->resourceManager()->setResource(HotPosition, newHotPosition); } return 0; } bool selectMultiple = event->modifiers() & Qt::ControlModifier; bool selectNextInStack = event->modifiers() & Qt::ShiftModifier; if (editableShape) { // manipulation of selected shapes goes first if (handle != KoFlake::NoHandle) { if (event->buttons() == Qt::LeftButton) { // resizing or shearing only with left mouse button if (insideSelection) { return new ShapeResizeStrategy(this, event->point, handle); } if (handle == KoFlake::TopMiddleHandle || handle == KoFlake::RightMiddleHandle || handle == KoFlake::BottomMiddleHandle || handle == KoFlake::LeftMiddleHandle) { return new ShapeShearStrategy(this, event->point, handle); } } // rotating is allowed for rigth mouse button too if (handle == KoFlake::TopLeftHandle || handle == KoFlake::TopRightHandle || handle == KoFlake::BottomLeftHandle || handle == KoFlake::BottomRightHandle) { return new ShapeRotateStrategy(this, event->point, event->buttons()); } } if (!(selectMultiple || selectNextInStack) && event->buttons() == Qt::LeftButton) { const QPainterPath outlinePath = select->transformation().map(select->outline()); if (outlinePath.contains(event->point) || outlinePath.intersects(handlePaintRect(event->point))) { return new ShapeMoveStrategy(this, event->point); } } } if ((event->buttons() & Qt::LeftButton) == 0) { return 0; // Nothing to do for middle/right mouse button } KoShape *shape = shapeManager->shapeAt(event->point, selectNextInStack ? KoFlake::NextUnselected : KoFlake::ShapeOnTop); if (!shape && handle == KoFlake::NoHandle) { if (!selectMultiple) { repaintDecorations(); select->deselectAll(); } return new KoShapeRubberSelectStrategy(this, event->point); } if (select->isSelected(shape)) { if (selectMultiple) { repaintDecorations(); select->deselect(shape); } } else if (handle == KoFlake::NoHandle) { // clicked on shape which is not selected repaintDecorations(); if (!selectMultiple) { shapeManager->selection()->deselectAll(); } select->select(shape, selectNextInStack ? false : true); repaintDecorations(); // tablet selection isn't precise and may lead to a move, preventing that if (event->isTabletEvent()) { return new NopInteractionStrategy(this); } return new ShapeMoveStrategy(this, event->point); } return 0; } void DefaultTool::updateActions() { KoSelection *selection(koSelection()); if (!selection) { action("object_order_front")->setEnabled(false); action("object_order_raise")->setEnabled(false); action("object_order_lower")->setEnabled(false); action("object_order_back")->setEnabled(false); action("object_align_horizontal_left")->setEnabled(false); action("object_align_horizontal_center")->setEnabled(false); action("object_align_horizontal_right")->setEnabled(false); action("object_align_vertical_top")->setEnabled(false); action("object_align_vertical_center")->setEnabled(false); action("object_align_vertical_bottom")->setEnabled(false); action("object_group")->setEnabled(false); action("object_ungroup")->setEnabled(false); return; } QList editableShapes = filterEditableShapes(selection->selectedShapes(KoFlake::TopLevelSelection)); bool enable = editableShapes.count() > 0; action("object_order_front")->setEnabled(enable); action("object_order_raise")->setEnabled(enable); action("object_order_lower")->setEnabled(enable); action("object_order_back")->setEnabled(enable); enable = (editableShapes.count() > 1) || (enable && canvas()->resourceManager()->hasResource(KoCanvasResourceManager::PageSize)); action("object_align_horizontal_left")->setEnabled(enable); action("object_align_horizontal_center")->setEnabled(enable); action("object_align_horizontal_right")->setEnabled(enable); action("object_align_vertical_top")->setEnabled(enable); action("object_align_vertical_center")->setEnabled(enable); action("object_align_vertical_bottom")->setEnabled(enable); action("object_group")->setEnabled(editableShapes.count() > 1); bool groupShape = false; foreach (KoShape *shape, editableShapes) { if (dynamic_cast(shape)) { groupShape = true; break; } } action("object_ungroup")->setEnabled(groupShape); emit selectionChanged(selection->count()); } KoToolSelection *DefaultTool::selection() { return m_selectionHandler; } QList DefaultTool::filterEditableShapes(const QList &shapes) { QList editableShapes; Q_FOREACH (KoShape *shape, shapes) { if (shape->isEditable()) { editableShapes.append(shape); } } return editableShapes; } uint DefaultTool::editableShapesCount(const QList &shapes) { uint count = 0; Q_FOREACH (KoShape *shape, shapes) { if (shape->isEditable()) { count++; } } return count; }