Krita Source Code Documentation
Loading...
Searching...
No Matches
KoStrokeConfigWidget.cpp
Go to the documentation of this file.
1/* This file is part of the KDE project
2 * Made by Tomislav Lukman (tomislav.lukman@ck.tel.hr)
3 * SPDX-FileCopyrightText: 2002 Tomislav Lukman <tomislav.lukman@ck.t-com.hr>
4 * SPDX-FileCopyrightText: 2002-2003 Rob Buis <buis@kde.org>
5 * SPDX-FileCopyrightText: 2005-2006 Tim Beaulen <tbscope@gmail.com>
6 * SPDX-FileCopyrightText: 2005-2007 Thomas Zander <zander@kde.org>
7 * SPDX-FileCopyrightText: 2005-2006, 2011 Inge Wallin <inge@lysator.liu.se>
8 * SPDX-FileCopyrightText: 2005-2008 Jan Hambrecht <jaham@gmx.net>
9 * SPDX-FileCopyrightText: 2006 C. Boemann <cbo@boemann.dk>
10 * SPDX-FileCopyrightText: 2006 Peter Simonsson <psn@linux.se>
11 * SPDX-FileCopyrightText: 2006 Laurent Montel <montel@kde.org>
12 * SPDX-FileCopyrightText: 2007, 2011 Thorsten Zachmann <t.zachmann@zagge.de>
13 * SPDX-FileCopyrightText: 2011 Jean-Nicolas Artaud <jeannicolasartaud@gmail.com>
14 *
15 * SPDX-License-Identifier: LGPL-2.0-or-later
16 */
17
18// Own
20
21// Qt
22#include <QMenu>
23#include <QToolButton>
24#include <QButtonGroup>
25#include <QVBoxLayout>
26#include <QHBoxLayout>
27#include <QSizePolicy>
28#include <KisSignalMapper.h>
29
30// KDE
31#include <klocalizedstring.h>
32
33// Calligra
34#include <KoIcon.h>
35#include <KoUnit.h>
36#include <KoLineStyleSelector.h>
37#include <KoUnitDoubleSpinBox.h>
38#include <KoMarkerSelector.h>
39#include <KoColorPopupAction.h>
40#include <KoMarker.h>
41#include <KoShapeStroke.h>
42#include <KoPathShape.h>
43#include <KoMarkerCollection.h>
45#include <KoCanvasBase.h>
46#include <KoCanvasController.h>
49#include <KoSelection.h>
50#include <KoShapeController.h>
52#include <KoShapeStrokeModel.h>
54#include "ui_KoStrokeConfigWidget.h"
55#include <KoFlakeUtils.h>
56#include <KoFillConfigWidget.h>
60
61// Krita
63
64class CapNJoinMenu : public QMenu
65{
66public:
67 CapNJoinMenu(QWidget *parent = 0);
68 QSize sizeHint() const override;
69
71 QButtonGroup *capGroup {0};
72 QButtonGroup *joinGroup {0};
73};
74
76 : QMenu(parent)
77{
78 QGridLayout *mainLayout = new QGridLayout(this);
79 mainLayout->setContentsMargins(2, 2, 2, 2);
80
81 // The cap group
82 capGroup = new QButtonGroup(this);
83 capGroup->setExclusive(true);
84
85 QToolButton *button = 0;
86
87 button = new QToolButton(this);
88 button->setIcon(koIcon("stroke-cap-butt"));
89 button->setCheckable(true);
90 button->setToolTip(i18n("Butt cap"));
91 capGroup->addButton(button, Qt::FlatCap);
92 mainLayout->addWidget(button, 2, 0);
93
94 button = new QToolButton(this);
95 button->setIcon(koIcon("stroke-cap-round"));
96 button->setCheckable(true);
97 button->setToolTip(i18n("Round cap"));
98 capGroup->addButton(button, Qt::RoundCap);
99 mainLayout->addWidget(button, 2, 1);
100
101 button = new QToolButton(this);
102 button->setIcon(koIcon("stroke-cap-square"));
103 button->setCheckable(true);
104 button->setToolTip(i18n("Square cap"));
105 capGroup->addButton(button, Qt::SquareCap);
106 mainLayout->addWidget(button, 2, 2, Qt::AlignLeft);
107
108 // The join group
109 joinGroup = new QButtonGroup(this);
110 joinGroup->setExclusive(true);
111
112 button = new QToolButton(this);
113 button->setIcon(koIcon("stroke-join-miter"));
114 button->setCheckable(true);
115 button->setToolTip(i18n("Miter join"));
116 joinGroup->addButton(button, Qt::MiterJoin);
117 mainLayout->addWidget(button, 3, 0);
118
119 button = new QToolButton(this);
120 button->setIcon(koIcon("stroke-join-round"));
121 button->setCheckable(true);
122 button->setToolTip(i18n("Round join"));
123 joinGroup->addButton(button, Qt::RoundJoin);
124 mainLayout->addWidget(button, 3, 1);
125
126 button = new QToolButton(this);
127 button->setIcon(koIcon("stroke-join-bevel"));
128 button->setCheckable(true);
129 button->setToolTip(i18n("Bevel join"));
130 joinGroup->addButton(button, Qt::BevelJoin);
131 mainLayout->addWidget(button, 3, 2, Qt::AlignLeft);
132
133 // Miter limit
137 miterLimit->setMinMaxStep(0.0, 240.0, 0.01);
139 miterLimit->setToolTip(i18n("Miter limit"));
140 mainLayout->addWidget(miterLimit, 4, 0, 1, 3);
141
142 mainLayout->setSizeConstraint(QLayout::SetMinAndMaxSize);
143}
144
146{
147 return layout()->sizeHint();
148}
149
150
151class Q_DECL_HIDDEN KoStrokeConfigWidget::Private
152{
153public:
155 : selectionChangedCompressor(200, KisSignalCompressor::FIRST_ACTIVE)
156 {
157 }
158
159 KoLineStyleSelector *lineStyle {0};
161 KoMarkerSelector *startMarkerSelector {0};
162 KoMarkerSelector *midMarkerSelector {0};
163 KoMarkerSelector *endMarkerSelector {0};
164
165 CapNJoinMenu *capNJoinMenu {0};
166
167 QWidget*spacer {0};
168
169 KoCanvasBase *canvas {0};
170
171 bool active {true};
172 bool allowLocalUnitManagement {false};
173
174 KoFillConfigWidget *fillConfigWidget {0};
175 bool noSelectionTrackingMode {false};
176
180
181 std::vector<KisAcyclicSignalConnector::Blocker> deactivationLocks;
182
183 QScopedPointer<Ui_KoStrokeConfigWidget> ui;
184};
185
186
188 : QWidget(parent)
189 , d(new Private())
190{
191 // configure GUI
192 d->ui.reset(new Ui_KoStrokeConfigWidget());
193 d->ui->setupUi(this);
194
195 setObjectName("Stroke widget");
196
197 { // connect the canvas
198 d->shapeChangedAcyclicConnector.connectBackwardVoid(
200 &d->selectionChangedCompressor, SLOT(start()));
201
202 d->shapeChangedAcyclicConnector.connectBackwardVoid(
203 canvas->selectedShapesProxy(), SIGNAL(selectionContentChanged()),
204 &d->selectionChangedCompressor, SLOT(start()));
205
206 connect(&d->selectionChangedCompressor, SIGNAL(timeout()), this, SLOT(selectionChanged()));
207
208 d->resourceManagerAcyclicConnector.connectBackwardResourcePair(
209 canvas->resourceManager(), SIGNAL(canvasResourceChanged(int,QVariant)),
210 this, SLOT(canvasResourceChanged(int,QVariant)));
211
212 d->canvas = canvas;
213 }
214
215 {
216
217 d->fillConfigWidget = new KoFillConfigWidget(canvas, KoFlake::StrokeFill, true, this);
218 d->fillConfigWidget->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::MinimumExpanding);
219 d->ui->fillConfigWidgetLayout->addWidget(d->fillConfigWidget);
220 connect(d->fillConfigWidget, SIGNAL(sigFillChanged()), SIGNAL(sigStrokeChanged()));
221 }
222
223 d->ui->thicknessLabel->setAlignment(Qt::AlignRight | Qt::AlignVCenter);
224 d->ui->thicknessLabel->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed);
225
226 // set min/max/step and value in points, then set actual unit
227 d->ui->lineWidth->preventDecimalsChangeFromUnitManager(true);
228 d->ui->lineWidth->setUnit(KoUnit(KoUnit::Point));
229 // if someone wants 0, just set to "none" on UI
230 // note: when initialized, there's probably no document opened or even if some documents are opened, the resolution
231 // of document may not be the same...
232 // min/max/step are then defined in Pt - values here are considered @600dpi; 0.10px = 0.03Pt / 1000px = 240.00pt
233 d->ui->lineWidth->setMinMaxStep(0.03, 240.0, 0.01);
234 d->ui->lineWidth->setDecimals(2);
235 d->ui->lineWidth->setToolTip(i18n("Set line width of actual selection"));
236
237 d->ui->capNJoinButton->setMinimumHeight(25);
238 d->capNJoinMenu = new CapNJoinMenu(this);
239 d->ui->capNJoinButton->setMenu(d->capNJoinMenu);
240 d->ui->capNJoinButton->setText("...");
241 d->ui->capNJoinButton->setPopupMode(QToolButton::InstantPopup);
242
243
244 {
245 // Line style
246 d->ui->strokeStyleLabel->setText(i18n("Line Style:"));
247 d->ui->strokeStyleLabel->setSizePolicy(QSizePolicy::Minimum, QSizePolicy::Minimum);
248
249 d->ui->lineStyle->setToolTip(i18nc("@info:tooltip", "Line style"));
250 d->ui->lineStyle->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Minimum);
251 d->ui->lineStyle->setLineStyle(Qt::SolidLine, QVector<qreal>());
252 }
253
254
255 {
256 QList<KoMarker*> emptyMarkers;
257
258
259 d->startMarkerSelector = new KoMarkerSelector(KoFlake::StartMarker, this);
260 d->startMarkerSelector->setToolTip(i18nc("@info:tooltip", "Start marker"));
261 d->startMarkerSelector->updateMarkers(emptyMarkers);
262 d->startMarkerSelector->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Preferred );
263 d->ui->markerLayout->addWidget(d->startMarkerSelector);
264
265
266 d->midMarkerSelector = new KoMarkerSelector(KoFlake::MidMarker, this);
267 d->midMarkerSelector->setToolTip(i18nc("@info:tooltip", "Node marker"));
268 d->midMarkerSelector->updateMarkers(emptyMarkers);
269 d->midMarkerSelector->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Preferred );
270 d->ui->markerLayout->addWidget(d->midMarkerSelector);
271
272
273 d->endMarkerSelector = new KoMarkerSelector(KoFlake::EndMarker, this);
274 d->endMarkerSelector->setToolTip(i18nc("@info:tooltip", "End marker"));
275 d->endMarkerSelector->updateMarkers(emptyMarkers);
276 d->endMarkerSelector->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Preferred );
277
278 d->ui->markerLayout->addWidget(d->endMarkerSelector);
279 }
280
281 // Spacer
282 d->spacer = new QWidget();
283 d->spacer->setObjectName("SpecialSpacer");
284
285 d->ui->markerLayout->addWidget(d->spacer);
286
287 connect(d->ui->lineStyle, SIGNAL(currentIndexChanged(int)), this, SLOT(applyDashStyleChanges()));
288 connect(d->ui->lineWidth, SIGNAL(valueChangedPt(qreal)), this, SLOT(applyLineWidthChanges()));
289
290 connect(d->capNJoinMenu->capGroup, SIGNAL(idClicked(int)), this, SLOT(applyJoinCapChanges()));
291 connect(d->capNJoinMenu->joinGroup, SIGNAL(idClicked(int)), this, SLOT(applyJoinCapChanges()));
292 connect(d->capNJoinMenu->miterLimit, SIGNAL(valueChangedPt(qreal)), this, SLOT(applyJoinCapChanges()));
293
294 { // Map the marker signals correctly
295 KisSignalMapper *mapper = new KisSignalMapper(this);
296 connect(mapper, SIGNAL(mapped(int)), SLOT(applyMarkerChanges(int)));
297
298 connect(d->startMarkerSelector, SIGNAL(currentIndexChanged(int)), mapper, SLOT(map()));
299 connect(d->midMarkerSelector, SIGNAL(currentIndexChanged(int)), mapper, SLOT(map()));
300 connect(d->endMarkerSelector, SIGNAL(currentIndexChanged(int)), mapper, SLOT(map()));
301
302 mapper->setMapping(d->startMarkerSelector, KoFlake::StartMarker);
303 mapper->setMapping(d->midMarkerSelector, KoFlake::MidMarker);
304 mapper->setMapping(d->endMarkerSelector, KoFlake::EndMarker);
305 }
306
307 KoDocumentResourceManager *resourceManager = canvas->shapeController()->resourceManager();
308 if (resourceManager) {
310 if (collection) {
311 updateMarkers(collection->markers());
312 }
313 }
314
315 d->selectionChangedCompressor.start();
316
317 // initialize deactivation locks
318 d->deactivationLocks.push_back(KisAcyclicSignalConnector::Blocker(d->shapeChangedAcyclicConnector));
319 d->deactivationLocks.push_back(KisAcyclicSignalConnector::Blocker(d->resourceManagerAcyclicConnector));
320}
321
326
328{
329 d->fillConfigWidget->setNoSelectionTrackingMode(value);
330 d->noSelectionTrackingMode = value;
331 if (!d->noSelectionTrackingMode) {
332 d->selectionChangedCompressor.start();
333 }
334}
335
336// ----------------------------------------------------------------
337// getters and setters
338
339
340Qt::PenStyle KoStrokeConfigWidget::lineStyle() const
341{
342 return d->ui->lineStyle->lineStyle();
343}
344
346{
347 return d->ui->lineStyle->lineDashes();
348}
349
351{
352 return d->ui->lineWidth->value();
353}
354
356{
357 return d->capNJoinMenu->miterLimit->value();
358}
359
361{
362 return d->startMarkerSelector->marker();
363}
364
366{
367 return d->endMarkerSelector->marker();
368}
369
370Qt::PenCapStyle KoStrokeConfigWidget::capStyle() const
371{
372 return static_cast<Qt::PenCapStyle>(d->capNJoinMenu->capGroup->checkedId());
373}
374
375Qt::PenJoinStyle KoStrokeConfigWidget::joinStyle() const
376{
377 return static_cast<Qt::PenJoinStyle>(d->capNJoinMenu->joinGroup->checkedId());
378}
379
381{
382 KoShapeStrokeSP stroke(d->fillConfigWidget->createShapeStroke());
383
384 stroke->setLineWidth(lineWidth());
385 stroke->setCapStyle(capStyle());
386 stroke->setJoinStyle(joinStyle());
387 stroke->setMiterLimit(miterLimit());
388 stroke->setLineStyle(lineStyle(), lineDashes());
389
390 return stroke;
391}
392
393// ----------------------------------------------------------------
394// Other public functions
395
397{
398 d->ui->lineWidth->setEnabled(enabled);
399 d->capNJoinMenu->setEnabled(enabled);
400 d->ui->lineStyle->setEnabled(enabled);
401
402 d->startMarkerSelector->setEnabled(enabled);
403 d->midMarkerSelector->setEnabled(enabled);
404 d->endMarkerSelector->setEnabled(enabled);
405}
406
407void KoStrokeConfigWidget::setUnit(const KoUnit &unit, KoShape *representativeShape)
408{
409 if (!d->allowLocalUnitManagement) {
410 return; //the unit management is completely transferred to the unitManagers.
411 }
412
413 blockChildSignals(true);
414
421 KoUnit newUnit(unit);
422 if (representativeShape) {
423 newUnit.adjustByPixelTransform(representativeShape->absoluteTransformation());
424 }
425
426 d->ui->lineWidth->setUnit(newUnit);
427 d->capNJoinMenu->miterLimit->setUnit(newUnit);
428
429 d->ui->lineWidth->setLineStep(1.0);
430 d->capNJoinMenu->miterLimit->setLineStep(1.0);
431
432 blockChildSignals(false);
433}
434
436 KisSpinBoxUnitManager *managerMitterLimit)
437{
438 blockChildSignals(true);
439 d->allowLocalUnitManagement = false;
440 d->ui->lineWidth->setUnitManager(managerLineWidth);
441 d->capNJoinMenu->miterLimit->setUnitManager(managerMitterLimit);
442 blockChildSignals(false);
443}
444
446{
447 d->startMarkerSelector->updateMarkers(markers);
448 d->midMarkerSelector->updateMarkers(markers);
449 d->endMarkerSelector->updateMarkers(markers);
450}
451
453{
454 KIS_SAFE_ASSERT_RECOVER_NOOP(!d->deactivationLocks.empty());
455 d->deactivationLocks.clear();
456 d->fillConfigWidget->activate();
457
458 if (!d->noSelectionTrackingMode) {
459 d->selectionChangedCompressor.start();
460 } else {
462 }
463}
464
466{
467 KIS_SAFE_ASSERT_RECOVER_NOOP(d->deactivationLocks.empty());
468
469 d->deactivationLocks.push_back(KisAcyclicSignalConnector::Blocker(d->shapeChangedAcyclicConnector));
470 d->deactivationLocks.push_back(KisAcyclicSignalConnector::Blocker(d->resourceManagerAcyclicConnector));
471 d->fillConfigWidget->deactivate();
472}
473
475{
476 d->ui->lineWidth->blockSignals(block);
477 d->capNJoinMenu->capGroup->blockSignals(block);
478 d->capNJoinMenu->joinGroup->blockSignals(block);
479 d->capNJoinMenu->miterLimit->blockSignals(block);
480 d->ui->lineStyle->blockSignals(block);
481 d->startMarkerSelector->blockSignals(block);
482 d->midMarkerSelector->blockSignals(block);
483 d->endMarkerSelector->blockSignals(block);
484}
485
487{
488 d->active = active;
489}
490
491//------------------------
492
493template <typename ModifyFunction>
494auto applyChangeToStrokes(KoCanvasBase *canvas, ModifyFunction modifyFunction)
495-> decltype(modifyFunction(KoShapeStrokeSP()), void())
496{
497 KoSelection *selection = canvas->selectedShapesProxy()->selection();
498
499 if (!selection) return;
500
501 QList<KoShape*> shapes = selection->selectedEditableShapes();
502
503 KUndo2Command *command = KoFlake::modifyShapesStrokes(shapes, modifyFunction);
504
505 if (command) {
506 canvas->addCommand(command);
507 }
508}
509
511{
513 d->canvas,
514 [this] (KoShapeStrokeSP stroke) {
515 stroke->setLineStyle(lineStyle(), lineDashes());
516 });
517
518 Q_EMIT sigStrokeChanged();
519}
520
522{
524 d->canvas,
525 [this] (KoShapeStrokeSP stroke) {
526 stroke->setLineWidth(lineWidth());
527 });
528
529 Q_EMIT sigStrokeChanged();
530}
531
533{
535 d->canvas,
536 [this] (KoShapeStrokeSP stroke) {
537
538 stroke->setCapStyle(static_cast<Qt::PenCapStyle>(d->capNJoinMenu->capGroup->checkedId()));
539 stroke->setJoinStyle(static_cast<Qt::PenJoinStyle>(d->capNJoinMenu->joinGroup->checkedId()));
540 stroke->setMiterLimit(miterLimit());
541 });
542
543 Q_EMIT sigStrokeChanged();
544}
545
547{
549 if (!selection) {
550 Q_EMIT sigStrokeChanged();
551 return;
552 }
553
554 QList<KoShape*> shapes = selection->selectedEditableShapes();
555 QList<KoPathShape*> pathShapes;
556 Q_FOREACH (KoShape *shape, shapes) {
557 KoPathShape *pathShape = dynamic_cast<KoPathShape*>(shape);
558 if (pathShape) {
559 pathShapes << pathShape;
560 }
561 }
562
563 if (pathShapes.isEmpty()) {
564 Q_EMIT sigStrokeChanged();
565 return;
566 }
567
568
569 KoFlake::MarkerPosition position = KoFlake::MarkerPosition(rawPosition);
570 QScopedPointer<KoMarker> marker;
571
572 switch (position) {
574 if (d->startMarkerSelector->marker()) {
575 marker.reset(new KoMarker(*d->startMarkerSelector->marker()));
576 }
577 break;
579 if (d->midMarkerSelector->marker()) {
580 marker.reset(new KoMarker(*d->midMarkerSelector->marker()));
581 }
582 break;
584 if (d->endMarkerSelector->marker()) {
585 marker.reset(new KoMarker(*d->endMarkerSelector->marker()));
586 }
587 break;
588 }
589
590 KUndo2Command* command = new KoPathShapeMarkerCommand(pathShapes, marker.take(), position);
591 d->canvas->addCommand(command);
592
593 Q_EMIT sigStrokeChanged();
594}
595
596// ----------------------------------------------------------------
597
599{
602 return qSharedPointerDynamicCast<KoShapeStroke>(shape->stroke());
603 }
604};
605
607{
609 return p1->lineStyle() == p2->lineStyle() &&
610 p1->lineDashes() == p2->lineDashes() &&
611 p1->dashOffset() == p2->dashOffset();
612 }
613};
614
616{
618 return p1->capStyle() == p2->capStyle() &&
619 p1->joinStyle() == p2->joinStyle() &&
620 p1->miterLimit() == p2->miterLimit();
621 }
622};
623
625{
627 return p1->lineWidth() == p2->lineWidth();
628 }
629};
630
632{
634 : m_position(position)
635 {
636 }
637
640 KoPathShape *pathShape = dynamic_cast<KoPathShape*>(shape);
641 return pathShape ? pathShape->marker(m_position) : 0;
642 }
644 if ((!p1 || !p2) && p1 != p2) return false;
645 if (!p1 && p1 == p2) return true;
646
647 return p1 == p2 || *p1 == *p2;
648 }
649
651};
652
654{
655 if (d->noSelectionTrackingMode) return;
656
658 if (!selection) return;
659
660 // we need to linearize update order, and force the child widget to update
661 // before we start doing it
662
663 QList<KoShape*> shapes = selection->selectedEditableShapes();
664
665 KoShape *shape = !shapes.isEmpty() ? shapes.first() : 0;
666
667 const KoShapeStrokeSP stroke = shape ? qSharedPointerDynamicCast<KoShapeStroke>(shape->stroke()) : KoShapeStrokeSP();
668
669 // setUnit uses blockChildSignals() so take care not to use it inside the block
670 setUnit(d->canvas->unit(), shape);
671
672 blockChildSignals(true);
673
674 // line width
675 if (stroke && KoFlake::compareShapePropertiesEqual<CheckShapeStrokeWidthPolicy>(shapes)) {
676 d->ui->lineWidth->changeValue(stroke->lineWidth());
677 } else {
678 d->ui->lineWidth->changeValue(0);
679 }
680
681
682 // caps & joins
683 if (stroke && KoFlake::compareShapePropertiesEqual<CheckShapeStrokeCapJoinPolicy>(shapes)) {
684 Qt::PenCapStyle capStyle = stroke->capStyle() >= 0 ? stroke->capStyle() : Qt::FlatCap;
685 Qt::PenJoinStyle joinStyle = stroke->joinStyle() >= 0 ? stroke->joinStyle() : Qt::MiterJoin;
686
687 {
688 QAbstractButton *button = d->capNJoinMenu->capGroup->button(capStyle);
690 button->setChecked(true);
691 }
692
693 {
694 QAbstractButton *button = d->capNJoinMenu->joinGroup->button(joinStyle);
696 button->setChecked(true);
697 }
698
699 d->capNJoinMenu->miterLimit->changeValue(stroke->miterLimit());
700 d->capNJoinMenu->miterLimit->setEnabled(joinStyle == Qt::MiterJoin);
701 } else {
702 d->capNJoinMenu->capGroup->button(Qt::FlatCap)->setChecked(true);
703 d->capNJoinMenu->joinGroup->button(Qt::MiterJoin)->setChecked(true);
704 d->capNJoinMenu->miterLimit->changeValue(0.0);
705 d->capNJoinMenu->miterLimit->setEnabled(true);
706 }
707
708
709 // dashes style
710 if (stroke && KoFlake::compareShapePropertiesEqual<CheckShapeStrokeDashesPolicy>(shapes)) {
711 d->ui->lineStyle->setLineStyle(stroke->lineStyle(), stroke->lineDashes());
712 } else {
713 d->ui->lineStyle->setLineStyle(Qt::SolidLine, QVector<qreal>());
714 }
715
716 // markers
717 KoPathShape *pathShape = dynamic_cast<KoPathShape *>(shape);
718 if (pathShape) {
720 d->startMarkerSelector->setMarker(pathShape->marker(KoFlake::StartMarker));
721 }
723 d->midMarkerSelector->setMarker(pathShape->marker(KoFlake::MidMarker));
724 }
726 d->endMarkerSelector->setMarker(pathShape->marker(KoFlake::EndMarker));
727 }
728 }
729
730 const bool lineOptionsVisible = (d->fillConfigWidget->selectedFillIndex() != 0);
731
732 // This switch statement is to help the tab widget "pages" to be closer to the correct size
733 // if we don't do this the internal widgets get rendered, then the tab page has to get resized to
734 // fill up the space, then the internal widgets have to resize yet again...causing flicker
735 switch(d->fillConfigWidget->selectedFillIndex()) {
736 case 0: // no fill
737 this->setMinimumHeight(130);
738 break;
739 case 1: // solid fill
740 this->setMinimumHeight(200);
741 break;
742 case 2: // gradient fill
743 this->setMinimumHeight(350);
744 case 3: // pattern fill
745 break;
746 }
747
748
749 d->ui->thicknessLineBreak->setVisible(lineOptionsVisible);
750 d->ui->lineWidth->setVisible(lineOptionsVisible);
751 d->ui->capNJoinButton->setVisible(lineOptionsVisible);
752 d->ui->lineStyle->setVisible(lineOptionsVisible);
753 d->startMarkerSelector->setVisible(lineOptionsVisible);
754 d->midMarkerSelector->setVisible(lineOptionsVisible);
755 d->endMarkerSelector->setVisible(lineOptionsVisible);
756 d->ui->thicknessLabel->setVisible(lineOptionsVisible);
757 d->ui->strokeStyleLabel->setVisible(lineOptionsVisible);
758
759
760
761 blockChildSignals(false);
762
763 updateStyleControlsAvailability(!shapes.isEmpty());
764
765}
766
768{
769 switch (key) {
771 // we request the whole selection to reload because the
772 // unit of the stroke width depends on the selected shape
773 d->selectionChangedCompressor.start();
774 break;
776 if (d->noSelectionTrackingMode) {
777 d->ui->lineWidth->changeValue(d->canvas->unit().fromUserValue(value.toReal()));
778 }
779 break;
780 }
781}
782
float value(const T *src, size_t ch)
QPointF p2
QPointF p1
QSharedPointer< KoShapeStroke > KoShapeStrokeSP
auto applyChangeToStrokes(KoCanvasBase *canvas, ModifyFunction modifyFunction) -> decltype(modifyFunction(KoShapeStrokeSP()), void())
connect(this, SIGNAL(optionsChanged()), this, SLOT(saveOptions()))
CapNJoinMenu(QWidget *parent=0)
QSize sizeHint() const override
QButtonGroup * capGroup
KisDoubleParseUnitSpinBox * miterLimit
QButtonGroup * joinGroup
std::unique_lock< KisAcyclicSignalConnector > Blocker
KisSelectedShapesProxy selectedShapesProxy
KoUnit unit() const override
void addCommand(KUndo2Command *command) override
The KisDoubleParseUnitSpinBox class is an evolution of the.
void setMinMaxStep(double min, double max, double step)
Set minimum, maximum value and the step size (in current unit)
virtual void setUnit(const KoUnit &unit)
KoSelection * selection() override
The KisSignalMapper class bundles signals from identifiable senders.
void setMapping(QObject *sender, int id)
The KisSpinBoxUnitManager class is an abstract interface for the unitspinboxes classes to manage diff...
QPointer< KoShapeController > shapeController
QPointer< KoCanvasResourceProvider > resourceManager
virtual KoSelectedShapesProxy * selectedShapesProxy() const =0
selectedShapesProxy() is a special interface for keeping a persistent connections to selectionChanged...
@ MarkerCollection
The collection holding all markers.
A widget for configuring the fill of a shape.
QList< QExplicitlySharedDataPointer< KoMarker > > markers
The position of a path point within a path shape.
Definition KoPathShape.h:63
KoMarker * marker(KoFlake::MarkerPosition pos) const
const QList< KoShape * > selectedEditableShapes() const
virtual KoShapeStrokeModelSP stroke() const
Definition KoShape.cpp:1067
QTransform absoluteTransformation() const
Definition KoShape.cpp:382
A widget for configuring the stroke of a shape.
void updateMarkers(const QList< KoMarker * > &markers)
void setUnitManagers(KisSpinBoxUnitManager *managerLineWidth, KisSpinBoxUnitManager *managerMitterLimit)
Qt::PenCapStyle capStyle() const
void setNoSelectionTrackingMode(bool value)
KisAcyclicSignalConnector shapeChangedAcyclicConnector
void applyMarkerChanges(int rawPosition)
apply marker changes to the selected shape
QScopedPointer< Ui_KoStrokeConfigWidget > ui
void updateStyleControlsAvailability(bool enabled)
KisSignalCompressor selectionChangedCompressor
Qt::PenJoinStyle joinStyle() const
void selectionChanged()
selection has changed
KoMarker * startMarker() const
void blockChildSignals(bool block)
std::vector< KisAcyclicSignalConnector::Blocker > deactivationLocks
KisDoubleParseUnitSpinBox * lineWidth
KoStrokeConfigWidget(KoCanvasBase *canvas, QWidget *parent)
void applyDashStyleChanges()
apply line changes to the selected shapes
KoLineStyleSelector * lineStyle
void canvasResourceChanged(int key, const QVariant &value)
QVector< qreal > lineDashes() const
void setUnit(const KoUnit &unit, KoShape *representativeShape)
KoShapeStrokeSP createShapeStroke()
KisAcyclicSignalConnector resourceManagerAcyclicConnector
qreal fromUserValue(qreal value) const
Definition KoUnit.cpp:201
@ Point
Postscript point, 1/72th of an Inco.
Definition KoUnit.h:76
void adjustByPixelTransform(const QTransform &t)
Definition KoUnit.cpp:392
#define KIS_SAFE_ASSERT_RECOVER_RETURN(cond)
Definition kis_assert.h:128
#define KIS_SAFE_ASSERT_RECOVER_NOOP(cond)
Definition kis_assert.h:130
#define koIcon(name)
Use these macros for icons without any issues.
Definition kis_icon.h:25
typedef void(QOPENGLF_APIENTRYP PFNGLINVALIDATEBUFFERDATAPROC)(GLuint buffer)
QString button(const QWheelEvent &ev)
@ Unit
The unit of this canvas.
auto modifyShapesStrokes(QList< KoShape * > shapes, ModifyFunction modifyFunction) -> decltype(modifyFunction(KoShapeStrokeSP()),(KUndo2Command *)(0))
MarkerPosition
Definition KoFlake.h:41
@ EndMarker
Definition KoFlake.h:44
@ StartMarker
Definition KoFlake.h:42
@ MidMarker
Definition KoFlake.h:43
bool compareShapePropertiesEqual(const QList< KoShape * > shapes, const Policy &policy)
@ StrokeFill
Definition KoFlake.h:30
KoFlake::MarkerPosition m_position
PointerType getProperty(KoShape *shape) const
CheckShapeMarkerPolicy(KoFlake::MarkerPosition position)
bool compareTo(PointerType p1, PointerType p2) const
static bool compareTo(PointerType p1, PointerType p2)
static bool compareTo(PointerType p1, PointerType p2)
static PointerType getProperty(KoShape *shape)
static bool compareTo(PointerType p1, PointerType p2)
The undo / redo command for setting the shape marker.
KisCanvas2 * canvas