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// Std
22#include <memory>
23
24// Qt
25#include <QMenu>
26#include <QToolButton>
27#include <QButtonGroup>
28#include <QVBoxLayout>
29#include <QHBoxLayout>
30#include <QSizePolicy>
31#include <KisSignalMapper.h>
32
33// KDE
34#include <klocalizedstring.h>
35
36// Calligra
37#include <KoIcon.h>
38#include <KoUnit.h>
39#include <KoLineStyleSelector.h>
40#include <KoUnitDoubleSpinBox.h>
41#include <KoMarkerSelector.h>
42#include <KoColorPopupAction.h>
43#include <KoMarker.h>
44#include <KoShapeStroke.h>
45#include <KoPathShape.h>
46#include <KoMarkerCollection.h>
48#include <KoCanvasBase.h>
49#include <KoCanvasController.h>
52#include <KoSelection.h>
53#include <KoShapeController.h>
55#include <KoShapeStrokeModel.h>
57#include "ui_KoStrokeConfigWidget.h"
58#include <KoFlakeUtils.h>
59#include <KoFillConfigWidget.h>
63
64// Krita
66
67class CapNJoinMenu : public QMenu
68{
69public:
70 CapNJoinMenu(QWidget *parent = 0);
71 QSize sizeHint() const override;
72
74 QButtonGroup *capGroup {0};
75 QButtonGroup *joinGroup {0};
76};
77
79 : QMenu(parent)
80{
81 QGridLayout *mainLayout = new QGridLayout(this);
82 mainLayout->setContentsMargins(2, 2, 2, 2);
83
84 // The cap group
85 capGroup = new QButtonGroup(this);
86 capGroup->setExclusive(true);
87
88 QToolButton *button = 0;
89
90 button = new QToolButton(this);
91 button->setIcon(koIcon("stroke-cap-butt"));
92 button->setCheckable(true);
93 button->setToolTip(i18n("Butt cap"));
94 capGroup->addButton(button, Qt::FlatCap);
95 mainLayout->addWidget(button, 2, 0);
96
97 button = new QToolButton(this);
98 button->setIcon(koIcon("stroke-cap-round"));
99 button->setCheckable(true);
100 button->setToolTip(i18n("Round cap"));
101 capGroup->addButton(button, Qt::RoundCap);
102 mainLayout->addWidget(button, 2, 1);
103
104 button = new QToolButton(this);
105 button->setIcon(koIcon("stroke-cap-square"));
106 button->setCheckable(true);
107 button->setToolTip(i18n("Square cap"));
108 capGroup->addButton(button, Qt::SquareCap);
109 mainLayout->addWidget(button, 2, 2, Qt::AlignLeft);
110
111 // The join group
112 joinGroup = new QButtonGroup(this);
113 joinGroup->setExclusive(true);
114
115 button = new QToolButton(this);
116 button->setIcon(koIcon("stroke-join-miter"));
117 button->setCheckable(true);
118 button->setToolTip(i18n("Miter join"));
119 joinGroup->addButton(button, Qt::MiterJoin);
120 mainLayout->addWidget(button, 3, 0);
121
122 button = new QToolButton(this);
123 button->setIcon(koIcon("stroke-join-round"));
124 button->setCheckable(true);
125 button->setToolTip(i18n("Round join"));
126 joinGroup->addButton(button, Qt::RoundJoin);
127 mainLayout->addWidget(button, 3, 1);
128
129 button = new QToolButton(this);
130 button->setIcon(koIcon("stroke-join-bevel"));
131 button->setCheckable(true);
132 button->setToolTip(i18n("Bevel join"));
133 joinGroup->addButton(button, Qt::BevelJoin);
134 mainLayout->addWidget(button, 3, 2, Qt::AlignLeft);
135
136 // Miter limit
140 miterLimit->setMinMaxStep(0.0, 240.0, 0.01);
142 miterLimit->setToolTip(i18n("Miter limit"));
143 mainLayout->addWidget(miterLimit, 4, 0, 1, 3);
144
145 mainLayout->setSizeConstraint(QLayout::SetMinAndMaxSize);
146}
147
149{
150 return layout()->sizeHint();
151}
152
153
154class Q_DECL_HIDDEN KoStrokeConfigWidget::Private
155{
156public:
158 : selectionChangedCompressor(200, KisSignalCompressor::FIRST_ACTIVE)
159 {
160 }
161
162 KoLineStyleSelector *lineStyle {0};
164 KoMarkerSelector *startMarkerSelector {0};
165 KoMarkerSelector *midMarkerSelector {0};
166 KoMarkerSelector *endMarkerSelector {0};
167
168 CapNJoinMenu *capNJoinMenu {0};
169
170 QWidget*spacer {0};
171
172 KoCanvasBase *canvas {0};
173
174 bool active {true};
175 bool allowLocalUnitManagement {false};
176
177 KoFillConfigWidget *fillConfigWidget {0};
178 bool noSelectionTrackingMode {false};
179
183
184 std::vector<KisAcyclicSignalConnector::Blocker> deactivationLocks;
185
186 QScopedPointer<Ui_KoStrokeConfigWidget> ui;
187};
188
189
191 : QWidget(parent)
192 , d(new Private())
193{
194 // configure GUI
195 d->ui.reset(new Ui_KoStrokeConfigWidget());
196 d->ui->setupUi(this);
197
198 setObjectName("Stroke widget");
199
200 { // connect the canvas
201 d->shapeChangedAcyclicConnector.connectBackwardVoid(
203 &d->selectionChangedCompressor, SLOT(start()));
204
205 d->shapeChangedAcyclicConnector.connectBackwardVoid(
206 canvas->selectedShapesProxy(), SIGNAL(selectionContentChanged()),
207 &d->selectionChangedCompressor, SLOT(start()));
208
209 connect(&d->selectionChangedCompressor, SIGNAL(timeout()), this, SLOT(selectionChanged()));
210
211 d->resourceManagerAcyclicConnector.connectBackwardResourcePair(
212 canvas->resourceManager(), SIGNAL(canvasResourceChanged(int,QVariant)),
213 this, SLOT(canvasResourceChanged(int,QVariant)));
214
215 d->canvas = canvas;
216 }
217
218 {
219
220 d->fillConfigWidget = new KoFillConfigWidget(canvas, KoFlake::StrokeFill, true, this);
221 d->fillConfigWidget->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::MinimumExpanding);
222 d->ui->fillConfigWidgetLayout->addWidget(d->fillConfigWidget);
223 connect(d->fillConfigWidget, SIGNAL(sigFillChanged()), SIGNAL(sigStrokeChanged()));
224 }
225
226 d->ui->thicknessLabel->setAlignment(Qt::AlignRight | Qt::AlignVCenter);
227 d->ui->thicknessLabel->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed);
228
229 // set min/max/step and value in points, then set actual unit
230 d->ui->lineWidth->preventDecimalsChangeFromUnitManager(true);
231 d->ui->lineWidth->setUnit(KoUnit(KoUnit::Point));
232 // if someone wants 0, just set to "none" on UI
233 // note: when initialized, there's probably no document opened or even if some documents are opened, the resolution
234 // of document may not be the same...
235 // min/max/step are then defined in Pt - values here are considered @600dpi; 0.10px = 0.03Pt / 1000px = 240.00pt
236 d->ui->lineWidth->setMinMaxStep(0.03, 240.0, 0.01);
237 d->ui->lineWidth->setDecimals(2);
238 d->ui->lineWidth->setToolTip(i18n("Set line width of actual selection"));
239
240 d->ui->capNJoinButton->setMinimumHeight(25);
241 d->capNJoinMenu = new CapNJoinMenu(this);
242 d->ui->capNJoinButton->setMenu(d->capNJoinMenu);
243 d->ui->capNJoinButton->setText("...");
244 d->ui->capNJoinButton->setPopupMode(QToolButton::InstantPopup);
245
246
247 {
248 // Line style
249 d->ui->strokeStyleLabel->setText(i18n("Line Style:"));
250 d->ui->strokeStyleLabel->setSizePolicy(QSizePolicy::Minimum, QSizePolicy::Minimum);
251
252 d->ui->lineStyle->setToolTip(i18nc("@info:tooltip", "Line style"));
253 d->ui->lineStyle->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Minimum);
254 d->ui->lineStyle->setLineStyle(Qt::SolidLine, QVector<qreal>());
255 }
256
257
258 {
259 QList<KoMarker*> emptyMarkers;
260
261
262 d->startMarkerSelector = new KoMarkerSelector(KoFlake::StartMarker, this);
263 d->startMarkerSelector->setToolTip(i18nc("@info:tooltip", "Start marker"));
264 d->startMarkerSelector->updateMarkers(emptyMarkers);
265 d->startMarkerSelector->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Preferred );
266 d->ui->markerLayout->addWidget(d->startMarkerSelector);
267
268
269 d->midMarkerSelector = new KoMarkerSelector(KoFlake::MidMarker, this);
270 d->midMarkerSelector->setToolTip(i18nc("@info:tooltip", "Node marker"));
271 d->midMarkerSelector->updateMarkers(emptyMarkers);
272 d->midMarkerSelector->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Preferred );
273 d->ui->markerLayout->addWidget(d->midMarkerSelector);
274
275
276 d->endMarkerSelector = new KoMarkerSelector(KoFlake::EndMarker, this);
277 d->endMarkerSelector->setToolTip(i18nc("@info:tooltip", "End marker"));
278 d->endMarkerSelector->updateMarkers(emptyMarkers);
279 d->endMarkerSelector->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Preferred );
280
281 d->ui->markerLayout->addWidget(d->endMarkerSelector);
282 }
283
284 // Spacer
285 d->spacer = new QWidget();
286 d->spacer->setObjectName("SpecialSpacer");
287
288 d->ui->markerLayout->addWidget(d->spacer);
289
290 connect(d->ui->lineStyle, SIGNAL(currentIndexChanged(int)), this, SLOT(applyDashStyleChanges()));
291 connect(d->ui->lineWidth, SIGNAL(valueChangedPt(qreal)), this, SLOT(applyLineWidthChanges()));
292
293 connect(d->capNJoinMenu->capGroup, SIGNAL(idClicked(int)), this, SLOT(applyJoinCapChanges()));
294 connect(d->capNJoinMenu->joinGroup, SIGNAL(idClicked(int)), this, SLOT(applyJoinCapChanges()));
295 connect(d->capNJoinMenu->miterLimit, SIGNAL(valueChangedPt(qreal)), this, SLOT(applyJoinCapChanges()));
296
297 { // Map the marker signals correctly
298 KisSignalMapper *mapper = new KisSignalMapper(this);
299 connect(mapper, SIGNAL(mapped(int)), SLOT(applyMarkerChanges(int)));
300
301 connect(d->startMarkerSelector, SIGNAL(currentIndexChanged(int)), mapper, SLOT(map()));
302 connect(d->midMarkerSelector, SIGNAL(currentIndexChanged(int)), mapper, SLOT(map()));
303 connect(d->endMarkerSelector, SIGNAL(currentIndexChanged(int)), mapper, SLOT(map()));
304
305 mapper->setMapping(d->startMarkerSelector, KoFlake::StartMarker);
306 mapper->setMapping(d->midMarkerSelector, KoFlake::MidMarker);
307 mapper->setMapping(d->endMarkerSelector, KoFlake::EndMarker);
308 }
309
310 KoDocumentResourceManager *resourceManager = canvas->shapeController()->resourceManager();
311 if (resourceManager) {
313 if (collection) {
314 updateMarkers(collection->markers());
315 }
316 }
317
318 d->selectionChangedCompressor.start();
319
320 // initialize deactivation locks
321 d->deactivationLocks.push_back(KisAcyclicSignalConnector::Blocker(d->shapeChangedAcyclicConnector));
322 d->deactivationLocks.push_back(KisAcyclicSignalConnector::Blocker(d->resourceManagerAcyclicConnector));
323}
324
329
331{
332 d->fillConfigWidget->setNoSelectionTrackingMode(value);
333 d->noSelectionTrackingMode = value;
334 if (!d->noSelectionTrackingMode) {
335 d->selectionChangedCompressor.start();
336 }
337}
338
339// ----------------------------------------------------------------
340// getters and setters
341
342
343Qt::PenStyle KoStrokeConfigWidget::lineStyle() const
344{
345 return d->ui->lineStyle->lineStyle();
346}
347
349{
350 return d->ui->lineStyle->lineDashes();
351}
352
354{
355 return d->ui->lineWidth->value();
356}
357
359{
360 return d->capNJoinMenu->miterLimit->value();
361}
362
364{
365 return d->startMarkerSelector->marker();
366}
367
369{
370 return d->endMarkerSelector->marker();
371}
372
373Qt::PenCapStyle KoStrokeConfigWidget::capStyle() const
374{
375 return static_cast<Qt::PenCapStyle>(d->capNJoinMenu->capGroup->checkedId());
376}
377
378Qt::PenJoinStyle KoStrokeConfigWidget::joinStyle() const
379{
380 return static_cast<Qt::PenJoinStyle>(d->capNJoinMenu->joinGroup->checkedId());
381}
382
384{
385 KoShapeStrokeSP stroke(d->fillConfigWidget->createShapeStroke());
386
387 stroke->setLineWidth(lineWidth());
388 stroke->setCapStyle(capStyle());
389 stroke->setJoinStyle(joinStyle());
390 stroke->setMiterLimit(miterLimit());
391 stroke->setLineStyle(lineStyle(), lineDashes());
392
393 return stroke;
394}
395
396// ----------------------------------------------------------------
397// Other public functions
398
400{
401 d->ui->lineWidth->setEnabled(enabled);
402 d->capNJoinMenu->setEnabled(enabled);
403 d->ui->lineStyle->setEnabled(enabled);
404
405 d->startMarkerSelector->setEnabled(enabled);
406 d->midMarkerSelector->setEnabled(enabled);
407 d->endMarkerSelector->setEnabled(enabled);
408}
409
410void KoStrokeConfigWidget::setUnit(const KoUnit &unit, KoShape *representativeShape)
411{
412 if (!d->allowLocalUnitManagement) {
413 return; //the unit management is completely transferred to the unitManagers.
414 }
415
416 blockChildSignals(true);
417
424 KoUnit newUnit(unit);
425 if (representativeShape) {
426 newUnit.adjustByPixelTransform(representativeShape->absoluteTransformation());
427 }
428
429 d->ui->lineWidth->setUnit(newUnit);
430 d->capNJoinMenu->miterLimit->setUnit(newUnit);
431
432 d->ui->lineWidth->setLineStep(1.0);
433 d->capNJoinMenu->miterLimit->setLineStep(1.0);
434
435 blockChildSignals(false);
436}
437
439 KisSpinBoxUnitManager *managerMitterLimit)
440{
441 blockChildSignals(true);
442 d->allowLocalUnitManagement = false;
443 d->ui->lineWidth->setUnitManager(managerLineWidth);
444 d->capNJoinMenu->miterLimit->setUnitManager(managerMitterLimit);
445 blockChildSignals(false);
446}
447
449{
450 d->startMarkerSelector->updateMarkers(markers);
451 d->midMarkerSelector->updateMarkers(markers);
452 d->endMarkerSelector->updateMarkers(markers);
453}
454
456{
457 KIS_SAFE_ASSERT_RECOVER_NOOP(!d->deactivationLocks.empty());
458 d->deactivationLocks.clear();
459 d->fillConfigWidget->activate();
460
461 if (!d->noSelectionTrackingMode) {
462 d->selectionChangedCompressor.start();
463 } else {
465 }
466}
467
469{
470 KIS_SAFE_ASSERT_RECOVER_NOOP(d->deactivationLocks.empty());
471
472 d->deactivationLocks.push_back(KisAcyclicSignalConnector::Blocker(d->shapeChangedAcyclicConnector));
473 d->deactivationLocks.push_back(KisAcyclicSignalConnector::Blocker(d->resourceManagerAcyclicConnector));
474 d->fillConfigWidget->deactivate();
475}
476
478{
479 d->ui->lineWidth->blockSignals(block);
480 d->capNJoinMenu->capGroup->blockSignals(block);
481 d->capNJoinMenu->joinGroup->blockSignals(block);
482 d->capNJoinMenu->miterLimit->blockSignals(block);
483 d->ui->lineStyle->blockSignals(block);
484 d->startMarkerSelector->blockSignals(block);
485 d->midMarkerSelector->blockSignals(block);
486 d->endMarkerSelector->blockSignals(block);
487}
488
490{
491 d->active = active;
492}
493
494//------------------------
495
496template <typename ModifyFunction>
497auto applyChangeToStrokes(KoCanvasBase *canvas, ModifyFunction modifyFunction)
498-> decltype(modifyFunction(KoShapeStrokeSP()), void())
499{
500 KoSelection *selection = canvas->selectedShapesProxy()->selection();
501
502 if (!selection) return;
503
504 QList<KoShape*> shapes = selection->selectedEditableShapes();
505
506 KUndo2Command *command = KoFlake::modifyShapesStrokes(shapes, modifyFunction);
507
508 if (command) {
509 canvas->addCommand(command);
510 }
511}
512
514{
516 d->canvas,
517 [this] (KoShapeStrokeSP stroke) {
518 stroke->setLineStyle(lineStyle(), lineDashes());
519 });
520
521 Q_EMIT sigStrokeChanged();
522}
523
525{
527 d->canvas,
528 [this] (KoShapeStrokeSP stroke) {
529 stroke->setLineWidth(lineWidth());
530 });
531
532 Q_EMIT sigStrokeChanged();
533}
534
536{
538 d->canvas,
539 [this] (KoShapeStrokeSP stroke) {
540
541 stroke->setCapStyle(static_cast<Qt::PenCapStyle>(d->capNJoinMenu->capGroup->checkedId()));
542 stroke->setJoinStyle(static_cast<Qt::PenJoinStyle>(d->capNJoinMenu->joinGroup->checkedId()));
543 stroke->setMiterLimit(miterLimit());
544 });
545
546 Q_EMIT sigStrokeChanged();
547}
548
550{
552 if (!selection) {
553 Q_EMIT sigStrokeChanged();
554 return;
555 }
556
557 QList<KoShape*> shapes = selection->selectedEditableShapes();
558 QList<KoPathShape*> pathShapes;
559 Q_FOREACH (KoShape *shape, shapes) {
560 KoPathShape *pathShape = dynamic_cast<KoPathShape*>(shape);
561 if (pathShape) {
562 pathShapes << pathShape;
563 }
564 }
565
566 if (pathShapes.isEmpty()) {
567 Q_EMIT sigStrokeChanged();
568 return;
569 }
570
571
572 KoFlake::MarkerPosition position = KoFlake::MarkerPosition(rawPosition);
573 std::unique_ptr<KoMarker> marker;
574
575 switch (position) {
577 if (d->startMarkerSelector->marker()) {
578 marker.reset(new KoMarker(*d->startMarkerSelector->marker()));
579 }
580 break;
582 if (d->midMarkerSelector->marker()) {
583 marker.reset(new KoMarker(*d->midMarkerSelector->marker()));
584 }
585 break;
587 if (d->endMarkerSelector->marker()) {
588 marker.reset(new KoMarker(*d->endMarkerSelector->marker()));
589 }
590 break;
591 }
592
593 KUndo2Command* command = new KoPathShapeMarkerCommand(pathShapes, marker.release(), position);
594 d->canvas->addCommand(command);
595
596 Q_EMIT sigStrokeChanged();
597}
598
599// ----------------------------------------------------------------
600
602{
605 return qSharedPointerDynamicCast<KoShapeStroke>(shape->stroke());
606 }
607};
608
610{
612 return p1->lineStyle() == p2->lineStyle() &&
613 p1->lineDashes() == p2->lineDashes() &&
614 p1->dashOffset() == p2->dashOffset();
615 }
616};
617
619{
621 return p1->capStyle() == p2->capStyle() &&
622 p1->joinStyle() == p2->joinStyle() &&
623 p1->miterLimit() == p2->miterLimit();
624 }
625};
626
628{
630 return p1->lineWidth() == p2->lineWidth();
631 }
632};
633
635{
637 : m_position(position)
638 {
639 }
640
643 KoPathShape *pathShape = dynamic_cast<KoPathShape*>(shape);
644 return pathShape ? pathShape->marker(m_position) : 0;
645 }
647 if ((!p1 || !p2) && p1 != p2) return false;
648 if (!p1 && p1 == p2) return true;
649
650 return p1 == p2 || *p1 == *p2;
651 }
652
654};
655
657{
658 if (d->noSelectionTrackingMode) return;
659
661 if (!selection) return;
662
663 // we need to linearize update order, and force the child widget to update
664 // before we start doing it
665
666 QList<KoShape*> shapes = selection->selectedEditableShapes();
667
668 KoShape *shape = !shapes.isEmpty() ? shapes.first() : 0;
669
670 const KoShapeStrokeSP stroke = shape ? qSharedPointerDynamicCast<KoShapeStroke>(shape->stroke()) : KoShapeStrokeSP();
671
672 // setUnit uses blockChildSignals() so take care not to use it inside the block
673 setUnit(d->canvas->unit(), shape);
674
675 blockChildSignals(true);
676
677 // line width
678 if (stroke && KoFlake::compareShapePropertiesEqual<CheckShapeStrokeWidthPolicy>(shapes)) {
679 d->ui->lineWidth->changeValue(stroke->lineWidth());
680 } else {
681 d->ui->lineWidth->changeValue(0);
682 }
683
684
685 // caps & joins
686 if (stroke && KoFlake::compareShapePropertiesEqual<CheckShapeStrokeCapJoinPolicy>(shapes)) {
687 Qt::PenCapStyle capStyle = stroke->capStyle() >= 0 ? stroke->capStyle() : Qt::FlatCap;
688 Qt::PenJoinStyle joinStyle = stroke->joinStyle() >= 0 ? stroke->joinStyle() : Qt::MiterJoin;
689
690 {
691 QAbstractButton *button = d->capNJoinMenu->capGroup->button(capStyle);
693 button->setChecked(true);
694 }
695
696 {
697 QAbstractButton *button = d->capNJoinMenu->joinGroup->button(joinStyle);
699 button->setChecked(true);
700 }
701
702 d->capNJoinMenu->miterLimit->changeValue(stroke->miterLimit());
703 d->capNJoinMenu->miterLimit->setEnabled(joinStyle == Qt::MiterJoin);
704 } else {
705 d->capNJoinMenu->capGroup->button(Qt::FlatCap)->setChecked(true);
706 d->capNJoinMenu->joinGroup->button(Qt::MiterJoin)->setChecked(true);
707 d->capNJoinMenu->miterLimit->changeValue(0.0);
708 d->capNJoinMenu->miterLimit->setEnabled(true);
709 }
710
711
712 // dashes style
713 if (stroke && KoFlake::compareShapePropertiesEqual<CheckShapeStrokeDashesPolicy>(shapes)) {
714 d->ui->lineStyle->setLineStyle(stroke->lineStyle(), stroke->lineDashes());
715 } else {
716 d->ui->lineStyle->setLineStyle(Qt::SolidLine, QVector<qreal>());
717 }
718
719 // markers
720 KoPathShape *pathShape = dynamic_cast<KoPathShape *>(shape);
721 if (pathShape) {
723 d->startMarkerSelector->setMarker(pathShape->marker(KoFlake::StartMarker));
724 }
726 d->midMarkerSelector->setMarker(pathShape->marker(KoFlake::MidMarker));
727 }
729 d->endMarkerSelector->setMarker(pathShape->marker(KoFlake::EndMarker));
730 }
731 }
732
733 const bool lineOptionsVisible = (d->fillConfigWidget->selectedFillIndex() != 0);
734
735 // This switch statement is to help the tab widget "pages" to be closer to the correct size
736 // if we don't do this the internal widgets get rendered, then the tab page has to get resized to
737 // fill up the space, then the internal widgets have to resize yet again...causing flicker
738 switch(d->fillConfigWidget->selectedFillIndex()) {
739 case 0: // no fill
740 this->setMinimumHeight(130);
741 break;
742 case 1: // solid fill
743 this->setMinimumHeight(200);
744 break;
745 case 2: // gradient fill
746 this->setMinimumHeight(350);
747 case 3: // pattern fill
748 break;
749 }
750
751
752 d->ui->thicknessLineBreak->setVisible(lineOptionsVisible);
753 d->ui->lineWidth->setVisible(lineOptionsVisible);
754 d->ui->capNJoinButton->setVisible(lineOptionsVisible);
755 d->ui->lineStyle->setVisible(lineOptionsVisible);
756 d->startMarkerSelector->setVisible(lineOptionsVisible);
757 d->midMarkerSelector->setVisible(lineOptionsVisible);
758 d->endMarkerSelector->setVisible(lineOptionsVisible);
759 d->ui->thicknessLabel->setVisible(lineOptionsVisible);
760 d->ui->strokeStyleLabel->setVisible(lineOptionsVisible);
761
762
763
764 blockChildSignals(false);
765
766 updateStyleControlsAvailability(!shapes.isEmpty());
767
768}
769
771{
772 switch (key) {
774 // we request the whole selection to reload because the
775 // unit of the stroke width depends on the selected shape
776 d->selectionChangedCompressor.start();
777 break;
779 if (d->noSelectionTrackingMode) {
780 d->ui->lineWidth->changeValue(d->canvas->unit().fromUserValue(value.toReal()));
781 }
782 break;
783 }
784}
785
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())
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:885
QTransform absoluteTransformation() const
Definition KoShape.cpp:330
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