Warning, file /office/calligra/libs/widgets/KoStrokeConfigWidget.cpp was not indexed or was modified since last indexation (in which case cross-reference links may be missing, inaccurate or erroneous).
0001 /* This file is part of the KDE project 0002 * Made by Tomislav Lukman (tomislav.lukman@ck.tel.hr) 0003 * Copyright (C) 2002 Tomislav Lukman <tomislav.lukman@ck.t-com.hr> 0004 * Copyright (C) 2002-2003 Rob Buis <buis@kde.org> 0005 * Copyright (C) 2005-2006 Tim Beaulen <tbscope@gmail.com> 0006 * Copyright (C) 2005-2007 Thomas Zander <zander@kde.org> 0007 * Copyright (C) 2005-2006, 2011 Inge Wallin <inge@lysator.liu.se> 0008 * Copyright (C) 2005-2008 Jan Hambrecht <jaham@gmx.net> 0009 * Copyright (C) 2006 C. Boemann <cbo@boemann.dk> 0010 * Copyright (C) 2006 Peter Simonsson <psn@linux.se> 0011 * Copyright (C) 2006 Laurent Montel <montel@kde.org> 0012 * Copyright (C) 2007,2011 Thorsten Zachmann <t.zachmann@zagge.de> 0013 * Copyright (C) 2011 Jean-Nicolas Artaud <jeannicolasartaud@gmail.com> 0014 * 0015 * This library is free software; you can redistribute it and/or 0016 * modify it under the terms of the GNU Library General Public 0017 * License as published by the Free Software Foundation; either 0018 * version 2 of the License, or (at your option) any later version. 0019 * 0020 * This library is distributed in the hope that it will be useful, 0021 * but WITHOUT ANY WARRANTY; without even the implied warranty of 0022 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 0023 * Library General Public License for more details. 0024 * 0025 * You should have received a copy of the GNU Library General Public License 0026 * along with this library; see the file COPYING.LIB. If not, write to 0027 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, 0028 * Boston, MA 02110-1301, USA. 0029 */ 0030 0031 // Own 0032 #include "KoStrokeConfigWidget.h" 0033 0034 // Qt 0035 #include <QMenu> 0036 #include <QLabel> 0037 #include <QToolButton> 0038 #include <QButtonGroup> 0039 #include <QVBoxLayout> 0040 #include <QHBoxLayout> 0041 #include <QSizePolicy> 0042 0043 // KF5 0044 #include <klocalizedstring.h> 0045 0046 // Calligra 0047 #include <KoIcon.h> 0048 #include <KoUnit.h> 0049 #include <KoLineStyleSelector.h> 0050 #include <KoUnitDoubleSpinBox.h> 0051 #include <KoMarkerSelector.h> 0052 #include <KoColorPopupAction.h> 0053 #include <KoMarker.h> 0054 #include <KoShapeStroke.h> 0055 #include <KoPathShape.h> 0056 #include <KoMarkerCollection.h> 0057 #include <KoPathShapeMarkerCommand.h> 0058 #include <KoCanvasBase.h> 0059 #include <KoCanvasController.h> 0060 #include <KoCanvasResourceManager.h> 0061 #include <KoDocumentResourceManager.h> 0062 #include <KoToolManager.h> 0063 #include <KoSelection.h> 0064 #include <KoShapeController.h> 0065 #include <KoShapeManager.h> 0066 #include <KoShapeStrokeCommand.h> 0067 #include <KoShapeStrokeModel.h> 0068 0069 class CapNJoinMenu : public QMenu 0070 { 0071 Q_OBJECT 0072 public: 0073 CapNJoinMenu(QWidget *parent = nullptr); 0074 QSize sizeHint() const override; 0075 0076 KoUnitDoubleSpinBox *miterLimit; 0077 QButtonGroup *capGroup; 0078 QButtonGroup *joinGroup; 0079 }; 0080 0081 CapNJoinMenu::CapNJoinMenu(QWidget *parent) 0082 : QMenu(parent) 0083 { 0084 QGridLayout *mainLayout = new QGridLayout(); 0085 mainLayout->setMargin(2); 0086 0087 // The cap group 0088 capGroup = new QButtonGroup(this); 0089 capGroup->setExclusive(true); 0090 0091 QToolButton *button = nullptr; 0092 0093 button = new QToolButton(this); 0094 button->setIcon(koIcon("stroke-cap-butt")); 0095 button->setCheckable(true); 0096 button->setToolTip(i18n("Butt cap")); 0097 capGroup->addButton(button, Qt::FlatCap); 0098 mainLayout->addWidget(button, 2, 0); 0099 0100 button = new QToolButton(this); 0101 button->setIcon(koIcon("stroke-cap-round")); 0102 button->setCheckable(true); 0103 button->setToolTip(i18n("Round cap")); 0104 capGroup->addButton(button, Qt::RoundCap); 0105 mainLayout->addWidget(button, 2, 1); 0106 0107 button = new QToolButton(this); 0108 button->setIcon(koIcon("stroke-cap-square")); 0109 button->setCheckable(true); 0110 button->setToolTip(i18n("Square cap")); 0111 capGroup->addButton(button, Qt::SquareCap); 0112 mainLayout->addWidget(button, 2, 2, Qt::AlignLeft); 0113 0114 // The join group 0115 joinGroup = new QButtonGroup(this); 0116 joinGroup->setExclusive(true); 0117 0118 button = new QToolButton(this); 0119 button->setIcon(koIcon("stroke-join-miter")); 0120 button->setCheckable(true); 0121 button->setToolTip(i18n("Miter join")); 0122 joinGroup->addButton(button, Qt::MiterJoin); 0123 mainLayout->addWidget(button, 3, 0); 0124 0125 button = new QToolButton(this); 0126 button->setIcon(koIcon("stroke-join-round")); 0127 button->setCheckable(true); 0128 button->setToolTip(i18n("Round join")); 0129 joinGroup->addButton(button, Qt::RoundJoin); 0130 mainLayout->addWidget(button, 3, 1); 0131 0132 button = new QToolButton(this); 0133 button->setIcon(koIcon("stroke-join-bevel")); 0134 button->setCheckable(true); 0135 button->setToolTip(i18n("Bevel join")); 0136 joinGroup->addButton(button, Qt::BevelJoin); 0137 mainLayout->addWidget(button, 3, 2, Qt::AlignLeft); 0138 0139 // Miter limit 0140 // set min/max/step and value in points, then set actual unit 0141 miterLimit = new KoUnitDoubleSpinBox(this); 0142 miterLimit->setMinMaxStep(0.0, 1000.0, 0.5); 0143 miterLimit->setDecimals(2); 0144 miterLimit->setUnit(KoUnit(KoUnit::Point)); 0145 miterLimit->setToolTip(i18n("Miter limit")); 0146 mainLayout->addWidget(miterLimit, 4, 0, 1, 3); 0147 0148 mainLayout->setSizeConstraint(QLayout::SetMinAndMaxSize); 0149 setLayout(mainLayout); 0150 } 0151 0152 QSize CapNJoinMenu::sizeHint() const 0153 { 0154 return layout()->sizeHint(); 0155 } 0156 0157 0158 class Q_DECL_HIDDEN KoStrokeConfigWidget::Private 0159 { 0160 public: 0161 Private() 0162 : canvas(nullptr), 0163 active(true) 0164 { 0165 } 0166 0167 KoLineStyleSelector *lineStyle; 0168 KoUnitDoubleSpinBox *lineWidth; 0169 KoMarkerSelector *startMarkerSelector; 0170 KoMarkerSelector *endMarkerSelector; 0171 0172 CapNJoinMenu *capNJoinMenu; 0173 QToolButton *colorButton; 0174 KoColorPopupAction *colorAction; 0175 0176 QWidget *spacer; 0177 0178 KoCanvasBase *canvas; 0179 0180 bool active; 0181 }; 0182 0183 KoStrokeConfigWidget::KoStrokeConfigWidget(QWidget * parent) 0184 : QWidget(parent) 0185 , d(new Private()) 0186 { 0187 setObjectName("Stroke widget"); 0188 QVBoxLayout *mainLayout = new QVBoxLayout(this); 0189 mainLayout->setMargin(0); 0190 0191 QHBoxLayout *firstLineLayout = new QHBoxLayout(); 0192 0193 // Start marker 0194 QList<KoMarker*> markers; 0195 0196 d->startMarkerSelector = new KoMarkerSelector(KoMarkerData::MarkerStart, this); 0197 d->startMarkerSelector->updateMarkers(markers); 0198 d->startMarkerSelector->setMaximumWidth(50); 0199 firstLineLayout->addWidget(d->startMarkerSelector); 0200 0201 // Line style 0202 d->lineStyle = new KoLineStyleSelector(this); 0203 d->lineStyle->setMinimumWidth(70); 0204 firstLineLayout->addWidget(d->lineStyle); 0205 0206 // End marker 0207 d->endMarkerSelector = new KoMarkerSelector(KoMarkerData::MarkerEnd, this); 0208 d->endMarkerSelector->updateMarkers(markers); 0209 d->endMarkerSelector->setMaximumWidth(50); 0210 firstLineLayout->addWidget(d->endMarkerSelector); 0211 0212 QHBoxLayout *secondLineLayout = new QHBoxLayout(); 0213 0214 // Line width 0215 QLabel *l = new QLabel(this); 0216 l->setText(i18n("Thickness:")); 0217 l->setAlignment(Qt::AlignRight | Qt::AlignVCenter); 0218 l->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed); 0219 secondLineLayout->addWidget(l); 0220 0221 // set min/max/step and value in points, then set actual unit 0222 d->lineWidth = new KoUnitDoubleSpinBox(this); 0223 d->lineWidth->setMinMaxStep(0.0, 1000.0, 0.5); 0224 d->lineWidth->setDecimals(2); 0225 d->lineWidth->setUnit(KoUnit(KoUnit::Point)); 0226 d->lineWidth->setToolTip(i18n("Set line width of actual selection")); 0227 secondLineLayout->addWidget(d->lineWidth); 0228 0229 QToolButton *capNJoinButton = new QToolButton(this); 0230 capNJoinButton->setMinimumHeight(25); 0231 d->capNJoinMenu = new CapNJoinMenu(this); 0232 capNJoinButton->setMenu(d->capNJoinMenu); 0233 capNJoinButton->setText("..."); 0234 capNJoinButton->setPopupMode(QToolButton::InstantPopup); 0235 0236 secondLineLayout->addWidget(capNJoinButton); 0237 0238 d->colorButton = new QToolButton(this); 0239 secondLineLayout->addWidget(d->colorButton); 0240 d->colorAction = new KoColorPopupAction(this); 0241 d->colorAction->setIcon(koIcon("format-stroke-color")); 0242 d->colorAction->setToolTip(i18n("Change the color of the line/border")); 0243 d->colorButton->setDefaultAction(d->colorAction); 0244 0245 mainLayout->addLayout(firstLineLayout); 0246 mainLayout->addLayout(secondLineLayout); 0247 0248 // Spacer 0249 d->spacer = new QWidget(); 0250 d->spacer->setObjectName("SpecialSpacer"); 0251 mainLayout->addWidget(d->spacer); 0252 0253 0254 // set sensitive defaults 0255 d->lineStyle->setLineStyle(Qt::SolidLine); 0256 d->lineWidth->changeValue(1); 0257 d->colorAction->setCurrentColor(Qt::black); 0258 0259 // Make the signals visible on the outside of this widget. 0260 connect(d->lineStyle, SIGNAL(currentIndexChanged(int)), this, SLOT(applyChanges())); 0261 connect(d->lineWidth, SIGNAL(valueChangedPt(qreal)), this, SLOT(applyChanges())); 0262 connect(d->colorAction, SIGNAL(colorChanged(KoColor)), this, SLOT(applyChanges())); 0263 connect(d->capNJoinMenu->capGroup, SIGNAL(buttonClicked(int)), this, SLOT(applyChanges())); 0264 connect(d->capNJoinMenu->joinGroup, SIGNAL(buttonClicked(int)), this, SLOT(applyChanges())); 0265 connect(d->capNJoinMenu->miterLimit, SIGNAL(valueChangedPt(qreal)), this, SLOT(applyChanges())); 0266 connect(d->startMarkerSelector, SIGNAL(currentIndexChanged(int)), this, SLOT(startMarkerChanged())); 0267 connect(d->endMarkerSelector, SIGNAL(currentIndexChanged(int)), this, SLOT(endMarkerChanged())); 0268 } 0269 0270 KoStrokeConfigWidget::~KoStrokeConfigWidget() 0271 { 0272 delete d; 0273 } 0274 0275 // ---------------------------------------------------------------- 0276 // getters and setters 0277 0278 0279 Qt::PenStyle KoStrokeConfigWidget::lineStyle() const 0280 { 0281 return d->lineStyle->lineStyle(); 0282 } 0283 0284 QVector<qreal> KoStrokeConfigWidget::lineDashes() const 0285 { 0286 return d->lineStyle->lineDashes(); 0287 } 0288 0289 qreal KoStrokeConfigWidget::lineWidth() const 0290 { 0291 return d->lineWidth->value(); 0292 } 0293 0294 QColor KoStrokeConfigWidget::color() const 0295 { 0296 return d->colorAction->currentColor(); 0297 } 0298 0299 qreal KoStrokeConfigWidget::miterLimit() const 0300 { 0301 return d->capNJoinMenu->miterLimit->value(); 0302 } 0303 0304 KoMarker *KoStrokeConfigWidget::startMarker() const 0305 { 0306 return d->startMarkerSelector->marker(); 0307 } 0308 0309 KoMarker *KoStrokeConfigWidget::endMarker() const 0310 { 0311 return d->endMarkerSelector->marker(); 0312 } 0313 0314 Qt::PenCapStyle KoStrokeConfigWidget::capStyle() const 0315 { 0316 return static_cast<Qt::PenCapStyle>(d->capNJoinMenu->capGroup->checkedId()); 0317 } 0318 0319 Qt::PenJoinStyle KoStrokeConfigWidget::joinStyle() const 0320 { 0321 return static_cast<Qt::PenJoinStyle>(d->capNJoinMenu->joinGroup->checkedId()); 0322 } 0323 0324 KoShapeStroke* KoStrokeConfigWidget::createShapeStroke() const 0325 { 0326 KoShapeStroke *stroke = new KoShapeStroke(); 0327 0328 stroke->setColor(color()); 0329 stroke->setLineWidth(lineWidth()); 0330 stroke->setCapStyle(capStyle()); 0331 stroke->setJoinStyle(joinStyle()); 0332 stroke->setMiterLimit(miterLimit()); 0333 stroke->setLineStyle(lineStyle(), lineDashes()); 0334 0335 return stroke; 0336 } 0337 0338 // ---------------------------------------------------------------- 0339 // Other public functions 0340 0341 void KoStrokeConfigWidget::updateControls(KoShapeStrokeModel *stroke, KoMarker *startMarker, KoMarker *endMarker) 0342 { 0343 blockChildSignals(true); 0344 0345 const KoShapeStroke *lineStroke = dynamic_cast<const KoShapeStroke*>(stroke); 0346 if (lineStroke) { 0347 d->lineWidth->changeValue(lineStroke->lineWidth()); 0348 QAbstractButton *button = d->capNJoinMenu->capGroup->button(lineStroke->capStyle()); 0349 if (button) { 0350 button->setChecked(true); 0351 } 0352 button = d->capNJoinMenu->joinGroup->button(lineStroke->joinStyle()); 0353 if (button) { 0354 button->setChecked(true); 0355 } 0356 d->capNJoinMenu->miterLimit->changeValue(lineStroke->miterLimit()); 0357 d->capNJoinMenu->miterLimit->setEnabled(lineStroke->joinStyle() == Qt::MiterJoin); 0358 d->lineStyle->setLineStyle(lineStroke->lineStyle(), lineStroke->lineDashes()); 0359 d->colorAction->setCurrentColor(lineStroke->color()); 0360 } 0361 else { 0362 d->lineWidth->changeValue(0.0); 0363 d->capNJoinMenu->capGroup->button(Qt::FlatCap)->setChecked(true); 0364 d->capNJoinMenu->joinGroup->button(Qt::MiterJoin)->setChecked(true); 0365 d->capNJoinMenu->miterLimit->changeValue(0.0); 0366 d->capNJoinMenu->miterLimit->setEnabled(true); 0367 d->lineStyle->setLineStyle(Qt::NoPen, QVector<qreal>()); 0368 } 0369 0370 d->startMarkerSelector->setMarker(startMarker); 0371 d->endMarkerSelector->setMarker(endMarker); 0372 0373 blockChildSignals(false); 0374 } 0375 0376 void KoStrokeConfigWidget::setUnit(const KoUnit &unit) 0377 { 0378 blockChildSignals(true); 0379 0380 KoCanvasController* canvasController = KoToolManager::instance()->activeCanvasController(); 0381 KoSelection *selection = canvasController->canvas()->shapeManager()->selection(); 0382 KoShape * shape = selection->firstSelectedShape(); 0383 0384 /** 0385 * KoStrokeShape knows nothing about the transformations applied 0386 * to the shape, which doesn't prevent the shape to apply them and 0387 * display the stroke differently. So just take that into account 0388 * and show the user correct values using the multiplier in KoUnit. 0389 */ 0390 KoUnit newUnit(unit); 0391 if (shape) { 0392 newUnit.adjustByPixelTransform(shape->absoluteTransformation(0)); 0393 } 0394 0395 d->lineWidth->setUnit(newUnit); 0396 d->capNJoinMenu->miterLimit->setUnit(newUnit); 0397 0398 blockChildSignals(false); 0399 } 0400 0401 void KoStrokeConfigWidget::updateMarkers(const QList<KoMarker*> &markers) 0402 { 0403 d->startMarkerSelector->updateMarkers(markers); 0404 d->endMarkerSelector->updateMarkers(markers); 0405 } 0406 0407 void KoStrokeConfigWidget::blockChildSignals(bool block) 0408 { 0409 d->colorAction->blockSignals(block); 0410 d->lineWidth->blockSignals(block); 0411 d->capNJoinMenu->capGroup->blockSignals(block); 0412 d->capNJoinMenu->joinGroup->blockSignals(block); 0413 d->capNJoinMenu->miterLimit->blockSignals(block); 0414 d->lineStyle->blockSignals(block); 0415 d->startMarkerSelector->blockSignals(block); 0416 d->endMarkerSelector->blockSignals(block); 0417 } 0418 0419 void KoStrokeConfigWidget::setActive(bool active) 0420 { 0421 d->active = active; 0422 } 0423 0424 //------------------------ 0425 void KoStrokeConfigWidget::applyChanges() 0426 { 0427 KoCanvasController* canvasController = KoToolManager::instance()->activeCanvasController(); 0428 KoSelection *selection = canvasController->canvas()->shapeManager()->selection(); 0429 0430 //FIXME d->canvas->resourceManager()->setActiveStroke( d->stroke ); 0431 0432 if (!selection || !selection->count()) { 0433 return; 0434 } 0435 0436 KoShapeStroke *newStroke = new KoShapeStroke(); 0437 KoShapeStroke *oldStroke = dynamic_cast<KoShapeStroke*>( selection->firstSelectedShape()->stroke() ); 0438 if (oldStroke) { 0439 newStroke->setLineBrush(oldStroke->lineBrush()); 0440 } 0441 newStroke->setColor(color()); 0442 newStroke->setLineWidth(lineWidth()); 0443 newStroke->setCapStyle(static_cast<Qt::PenCapStyle>(d->capNJoinMenu->capGroup->checkedId())); 0444 newStroke->setJoinStyle(static_cast<Qt::PenJoinStyle>(d->capNJoinMenu->joinGroup->checkedId())); 0445 newStroke->setMiterLimit(miterLimit()); 0446 newStroke->setLineStyle(lineStyle(), lineDashes()); 0447 0448 if (d->active) { 0449 KoShapeStrokeCommand *cmd = new KoShapeStrokeCommand(selection->selectedShapes(), newStroke); 0450 canvasController->canvas()->addCommand(cmd); 0451 } 0452 } 0453 0454 void KoStrokeConfigWidget::applyMarkerChanges(KoMarkerData::MarkerPosition position) 0455 { 0456 KoMarker *marker = nullptr; 0457 if (position == KoMarkerData::MarkerStart) { 0458 marker = startMarker(); 0459 } 0460 else if (position == KoMarkerData::MarkerEnd) { 0461 marker = endMarker(); 0462 } 0463 0464 KoCanvasController* canvasController = KoToolManager::instance()->activeCanvasController(); 0465 KoSelection *selection = canvasController->canvas()->shapeManager()->selection(); 0466 0467 if (! selection || !selection->count()) { 0468 return; 0469 } 0470 0471 const QList<KoShape*> shapeList = selection->selectedShapes(); 0472 QList<KoPathShape*> pathShapeList; 0473 for (auto itShape : shapeList) { 0474 KoPathShape* pathShape = dynamic_cast<KoPathShape*>(itShape); 0475 if (pathShape) { 0476 pathShapeList << pathShape; 0477 } 0478 } 0479 0480 if (!pathShapeList.empty()) { 0481 KoPathShapeMarkerCommand* cmdMarker = new KoPathShapeMarkerCommand(pathShapeList, marker, position); 0482 canvasController->canvas()->addCommand(cmdMarker); 0483 } 0484 } 0485 0486 void KoStrokeConfigWidget::startMarkerChanged() 0487 { 0488 applyMarkerChanges(KoMarkerData::MarkerStart); 0489 } 0490 0491 void KoStrokeConfigWidget::endMarkerChanged() 0492 { 0493 applyMarkerChanges(KoMarkerData::MarkerEnd); 0494 } 0495 // ---------------------------------------------------------------- 0496 0497 0498 0499 void KoStrokeConfigWidget::selectionChanged() 0500 { 0501 // see a comment in setUnit() 0502 setUnit(d->canvas->unit()); 0503 0504 0505 KoCanvasController* canvasController = KoToolManager::instance()->activeCanvasController(); 0506 KoSelection *selection = canvasController->canvas()->shapeManager()->selection(); 0507 KoShape * shape = selection->firstSelectedShape(); 0508 if (shape && shape->stroke()) { 0509 KoPathShape *pathShape = dynamic_cast<KoPathShape *>(shape); 0510 if (pathShape) { 0511 updateControls(shape->stroke(), pathShape->marker(KoMarkerData::MarkerStart), 0512 pathShape->marker(KoMarkerData::MarkerEnd)); 0513 } 0514 else { 0515 updateControls(shape->stroke(), 0 ,0); 0516 } 0517 } 0518 } 0519 0520 void KoStrokeConfigWidget::setCanvas( KoCanvasBase *canvas ) 0521 { 0522 if (canvas) { 0523 connect(canvas->shapeManager()->selection(), SIGNAL(selectionChanged()), 0524 this, SLOT(selectionChanged())); 0525 connect(canvas->shapeManager(), SIGNAL(selectionContentChanged()), 0526 this, SLOT(selectionChanged())); 0527 connect(canvas->resourceManager(), SIGNAL(canvasResourceChanged(int,QVariant)), 0528 this, SLOT(canvasResourceChanged(int,QVariant))); 0529 setUnit(canvas->unit()); 0530 0531 KoDocumentResourceManager *resourceManager = canvas->shapeController()->resourceManager(); 0532 if (resourceManager) { 0533 KoMarkerCollection *collection = resourceManager->resource(KoDocumentResourceManager::MarkerCollection).value<KoMarkerCollection*>(); 0534 if (collection) { 0535 updateMarkers(collection->markers()); 0536 } 0537 } 0538 } 0539 0540 d->canvas = canvas; 0541 } 0542 0543 void KoStrokeConfigWidget::canvasResourceChanged(int key, const QVariant &value) 0544 { 0545 switch (key) { 0546 case KoCanvasResourceManager::Unit: 0547 setUnit(value.value<KoUnit>()); 0548 break; 0549 } 0550 } 0551 #include "KoStrokeConfigWidget.moc"