diff --git a/libs/image/kis_signal_compressor.h b/libs/image/kis_signal_compressor.h --- a/libs/image/kis_signal_compressor.h +++ b/libs/image/kis_signal_compressor.h @@ -36,7 +36,7 @@ * * FIRST_ACTIVE emits the timeout() event immediately and sets a timer of * duration \p delay. If the compressor is triggered during this time, it will - * fire another signal at the end of the delay period. Further events are + * wait until the end of the delay period to fire the signal. Further events are * ignored until the timer elapses. Think of it as a queue with size 1, and * where the leading element is popped every \p delay ms. * diff --git a/plugins/tools/basictools/kis_tool_line.h b/plugins/tools/basictools/kis_tool_line.h --- a/plugins/tools/basictools/kis_tool_line.h +++ b/plugins/tools/basictools/kis_tool_line.h @@ -71,19 +71,21 @@ private Q_SLOTS: void updateStroke(); void setUseSensors(bool value); - void setShowOutline(bool value); + void setShowPreview(bool value); + void setShowGuideline(bool value); private: void paintLine(QPainter& gc, const QRect& rc); QPointF straightLine(QPointF point); - void updatePreview(); + void updateGuideline(); + void updatePreviewTimer(bool showGuide); virtual QWidget* createOptionWidget(); void endStroke(); void cancelStroke(); private: - bool m_showOutline; + bool m_showGuideline; QPointF m_startPoint; QPointF m_endPoint; @@ -93,7 +95,8 @@ QCheckBox *m_chkUseSensors; - QCheckBox *m_chkShowOutline; + QCheckBox *m_chkShowPreview; + QCheckBox *m_chkShowGuideline; QScopedPointer m_infoBuilder; QScopedPointer m_helper; diff --git a/plugins/tools/basictools/kis_tool_line.cc b/plugins/tools/basictools/kis_tool_line.cc --- a/plugins/tools/basictools/kis_tool_line.cc +++ b/plugins/tools/basictools/kis_tool_line.cc @@ -60,11 +60,11 @@ KisToolLine::KisToolLine(KoCanvasBase * canvas) : KisToolPaint(canvas, KisCursor::load("tool_line_cursor.png", 6, 6)), - m_showOutline(false), + m_showGuideline(true), m_strokeIsRunning(false), m_infoBuilder(new KisConverterPaintingInformationBuilder(getCoordinatesConverter(canvas))), m_helper(new KisToolLineHelper(m_infoBuilder.data(), kundo2_i18n("Draw Line"))), - m_strokeUpdateCompressor(500, KisSignalCompressor::FIRST_ACTIVE), + m_strokeUpdateCompressor(500, KisSignalCompressor::POSTPONE), m_longStrokeUpdateCompressor(1000, KisSignalCompressor::FIRST_INACTIVE) { setObjectName("tool_line"); @@ -110,17 +110,22 @@ m_chkUseSensors = new QCheckBox(i18n("Use sensors")); addOptionWidgetOption(m_chkUseSensors); - m_chkShowOutline = new QCheckBox(i18n("Preview")); - addOptionWidgetOption(m_chkShowOutline); + m_chkShowPreview = new QCheckBox(i18n("Show Preview")); + addOptionWidgetOption(m_chkShowPreview); + + m_chkShowGuideline = new QCheckBox(i18n("Show Guideline")); + addOptionWidgetOption(m_chkShowGuideline); // hook up connections for value changing connect(m_chkUseSensors, SIGNAL(clicked(bool)), this, SLOT(setUseSensors(bool)) ); - connect(m_chkShowOutline, SIGNAL(clicked(bool)), this, SLOT(setShowOutline(bool)) ); + connect(m_chkShowPreview, SIGNAL(clicked(bool)), this, SLOT(setShowPreview(bool)) ); + connect(m_chkShowGuideline, SIGNAL(clicked(bool)), this, SLOT(setShowGuideline(bool)) ); // read values in from configuration m_chkUseSensors->setChecked(configGroup.readEntry("useSensors", true)); - m_chkShowOutline->setChecked(configGroup.readEntry("showOutline", false)); + m_chkShowPreview->setChecked(configGroup.readEntry("showPreview", true)); + m_chkShowGuideline->setChecked(configGroup.readEntry("showGuideline", true)); return widget; } @@ -130,9 +135,15 @@ configGroup.writeEntry("useSensors", value); } -void KisToolLine::setShowOutline(bool value) +void KisToolLine::setShowGuideline(bool value) { - configGroup.writeEntry("showOutline", value); + m_showGuideline = value; + configGroup.writeEntry("showGuideline", value); +} + +void KisToolLine::setShowPreview(bool value) +{ + configGroup.writeEntry("showPreview", value); } void KisToolLine::requestStrokeCancellation() @@ -142,9 +153,24 @@ void KisToolLine::requestStrokeEnd() { - endStroke(); + // Terminate any in-progress strokes + if (nodePaintAbility() == PAINT && m_helper->isRunning()) { + endStroke(); + } +} + +void KisToolLine::updatePreviewTimer(bool showGuideline) +{ + // If the user disables the guideline, we will want to try to draw some + // preview lines even if they're slow, so set the timer to FIRST_ACTIVE. + if (showGuideline) { + m_strokeUpdateCompressor.setMode(KisSignalCompressor::POSTPONE); + } else { + m_strokeUpdateCompressor.setMode(KisSignalCompressor::FIRST_ACTIVE); + } } + void KisToolLine::paint(QPainter& gc, const KoViewConverter &converter) { Q_UNUSED(converter); @@ -165,7 +191,9 @@ setMode(KisTool::PAINT_MODE); - m_showOutline = m_chkShowOutline->isChecked() || nodeAbility != PAINT; + // Always show guideline on vector layers + m_showGuideline = m_chkShowGuideline->isChecked() || nodeAbility != PAINT; + updatePreviewTimer(m_showGuideline); m_helper->setEnabled(nodeAbility == PAINT); m_helper->setUseSensors(m_chkUseSensors->isChecked()); m_helper->start(event); @@ -193,8 +221,8 @@ CHECK_MODE_SANITY_OR_RETURN(KisTool::PAINT_MODE); if (!m_strokeIsRunning) return; - // First ensure the old temp line is deleted - updatePreview(); + // First ensure the old guideline is deleted + updateGuideline(); QPointF pos = convertToPixelCoordAndSnap(event); @@ -209,17 +237,25 @@ } else { m_helper->addPoint(event, pos); } + m_endPoint = pos; - if ((pixelToView(m_lastUpdatedPoint) - pixelToView(pos)).manhattanLength() > 10) { - m_longStrokeUpdateCompressor.stop(); - m_strokeUpdateCompressor.start(); - m_lastUpdatedPoint = pos; - } else { - m_longStrokeUpdateCompressor.start(); + // Draw preview if requested + if (m_chkShowPreview->isChecked()) { + // If the cursor has moved a significant amount, immediately clear the + // current preview and redraw. Otherwise, do slow redraws periodically. + auto updateDistance = (pixelToView(m_lastUpdatedPoint) - pixelToView(pos)).manhattanLength(); + if (updateDistance > 10) { + m_helper->clearPaint(); + m_longStrokeUpdateCompressor.stop(); + m_strokeUpdateCompressor.start(); + m_lastUpdatedPoint = pos; + } else if (updateDistance > 1) { + m_longStrokeUpdateCompressor.start(); + } } - m_endPoint = pos; - updatePreview(); + + updateGuideline(); KisToolPaint::requestUpdateOutline(event->point, event); } @@ -229,20 +265,15 @@ CHECK_MODE_SANITY_OR_RETURN(KisTool::PAINT_MODE); setMode(KisTool::HOVER_MODE); - updatePreview(); - + updateGuideline(); endStroke(); } void KisToolLine::endStroke() { NodePaintAbility nodeAbility = nodePaintAbility(); - if (!m_strokeIsRunning || - (nodeAbility == PAINT && !m_helper->isRunning())|| - m_startPoint == m_endPoint || - nodeAbility == NONE) { - + if (!m_strokeIsRunning || m_startPoint == m_endPoint || nodeAbility == NONE) { return; } @@ -314,7 +345,7 @@ } -void KisToolLine::updatePreview() +void KisToolLine::updateGuideline() { if (canvas()) { QRectF bound(m_startPoint, m_endPoint); @@ -328,7 +359,7 @@ QPointF viewStartPos = pixelToView(m_startPoint); QPointF viewStartEnd = pixelToView(m_endPoint); - if (m_showOutline && canvas()) { + if (m_showGuideline && canvas()) { QPainterPath path; path.moveTo(viewStartPos); path.lineTo(viewStartEnd); diff --git a/plugins/tools/basictools/kis_tool_line_helper.h b/plugins/tools/basictools/kis_tool_line_helper.h --- a/plugins/tools/basictools/kis_tool_line_helper.h +++ b/plugins/tools/basictools/kis_tool_line_helper.h @@ -45,6 +45,7 @@ void translatePoints(const QPointF &offset); void end(); void cancel(); + void clearPaint(); using KisToolFreehandHelper::isRunning; diff --git a/plugins/tools/basictools/kis_tool_line_helper.cpp b/plugins/tools/basictools/kis_tool_line_helper.cpp --- a/plugins/tools/basictools/kis_tool_line_helper.cpp +++ b/plugins/tools/basictools/kis_tool_line_helper.cpp @@ -161,3 +161,11 @@ cancelPaint(); m_d->linePoints.clear(); } + + +void KisToolLineHelper::clearPaint() +{ + if (!m_d->enabled) return; + + cancelPaint(); +}