diff --git a/plugins/paintops/defaultpaintops/brush/kis_brushop.cpp b/plugins/paintops/defaultpaintops/brush/kis_brushop.cpp index 34a34b52d1..9d45f92f55 100644 --- a/plugins/paintops/defaultpaintops/brush/kis_brushop.cpp +++ b/plugins/paintops/defaultpaintops/brush/kis_brushop.cpp @@ -1,426 +1,432 @@ /* * Copyright (c) 2002 Patrick Julien * Copyright (c) 2004-2008 Boudewijn Rempt * Copyright (c) 2004 Clarence Dang * Copyright (c) 2004 Adrian Page * Copyright (c) 2004 Cyrille Berger * Copyright (c) 2010 Lukáš Tvrdý * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program 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 General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include "kis_brushop.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include "krita_utils.h" #include #include "kis_algebra_2d.h" #include #include #include #include "KisBrushOpResources.h" #include #include #include #include #include "kis_image_config.h" #include "kis_wrapped_rect.h" KisBrushOp::KisBrushOp(const KisPaintOpSettingsSP settings, KisPainter *painter, KisNodeSP node, KisImageSP image) : KisBrushBasedPaintOp(settings, painter) , m_opacityOption(node) , m_avgSpacing(50) , m_avgNumDabs(50) , m_avgUpdateTimePerDab(50) , m_idealNumRects(KisImageConfig(true).maxNumberOfThreads()) , m_minUpdatePeriod(10) , m_maxUpdatePeriod(100) { Q_UNUSED(image); Q_ASSERT(settings); /** * We do our own threading here, so we need to forbid the brushes * to do threading internally */ m_brush->setThreadingAllowed(false); m_airbrushOption.readOptionSetting(settings); m_opacityOption.readOptionSetting(settings); m_flowOption.readOptionSetting(settings); m_sizeOption.readOptionSetting(settings); m_ratioOption.readOptionSetting(settings); m_spacingOption.readOptionSetting(settings); m_rateOption.readOptionSetting(settings); m_softnessOption.readOptionSetting(settings); m_rotationOption.readOptionSetting(settings); m_scatterOption.readOptionSetting(settings); m_sharpnessOption.readOptionSetting(settings); m_opacityOption.resetAllSensors(); m_flowOption.resetAllSensors(); m_sizeOption.resetAllSensors(); m_ratioOption.resetAllSensors(); m_rateOption.resetAllSensors(); m_softnessOption.resetAllSensors(); m_sharpnessOption.resetAllSensors(); m_rotationOption.resetAllSensors(); m_scatterOption.resetAllSensors(); m_sharpnessOption.resetAllSensors(); m_rotationOption.applyFanCornersInfo(this); + m_precisionOption.setHasImprecisePositionOptions( + m_precisionOption.hasImprecisePositionOptions() | + m_scatterOption.isChecked() | + m_rotationOption.isChecked() | + m_airbrushOption.enabled); + KisBrushSP baseBrush = m_brush; auto resourcesFactory = [baseBrush, settings, painter] () { KisDabCacheUtils::DabRenderingResources *resources = new KisBrushOpResources(settings, painter); resources->brush = baseBrush->clone(); return resources; }; m_dabExecutor.reset( new KisDabRenderingExecutor( painter->device()->compositionSourceColorSpace(), resourcesFactory, painter->runnableStrokeJobsInterface(), &m_mirrorOption, &m_precisionOption)); } KisBrushOp::~KisBrushOp() { } KisSpacingInformation KisBrushOp::paintAt(const KisPaintInformation& info) { if (!painter()->device()) return KisSpacingInformation(1.0); KisBrushSP brush = m_brush; Q_ASSERT(brush); if (!brush) return KisSpacingInformation(1.0); if (!brush->canPaintFor(info)) return KisSpacingInformation(1.0); qreal scale = m_sizeOption.apply(info); scale *= KisLodTransform::lodToScale(painter()->device()); if (checkSizeTooSmall(scale)) return KisSpacingInformation(); qreal rotation = m_rotationOption.apply(info); qreal ratio = m_ratioOption.apply(info); KisDabShape shape(scale, ratio, rotation); QPointF cursorPos = m_scatterOption.apply(info, brush->maskWidth(shape, 0, 0, info), brush->maskHeight(shape, 0, 0, info)); m_opacityOption.setFlow(m_flowOption.apply(info)); quint8 dabOpacity = OPACITY_OPAQUE_U8; quint8 dabFlow = OPACITY_OPAQUE_U8; m_opacityOption.apply(info, &dabOpacity, &dabFlow); KisDabCacheUtils::DabRequestInfo request(painter()->paintColor(), cursorPos, shape, info, m_softnessOption.apply(info)); m_dabExecutor->addDab(request, qreal(dabOpacity) / 255.0, qreal(dabFlow) / 255.0); KisSpacingInformation spacingInfo = effectiveSpacing(scale, rotation, &m_airbrushOption, &m_spacingOption, info); // gather statistics about dabs m_avgSpacing(spacingInfo.scalarApprox()); return spacingInfo; } struct KisBrushOp::UpdateSharedState { // rendering data KisPainter *painter = 0; QList dabsQueue; // speed metrics QVector dabPoints; QElapsedTimer dabRenderingTimer; // final report QVector allDirtyRects; }; void KisBrushOp::addMirroringJobs(Qt::Orientation direction, QVector &rects, UpdateSharedStateSP state, QVector &jobs) { jobs.append(new KisRunnableStrokeJobData(0, KisStrokeJobData::SEQUENTIAL)); for (KisRenderedDab &dab : state->dabsQueue) { jobs.append( new KisRunnableStrokeJobData( [state, &dab, direction] () { state->painter->mirrorDab(direction, &dab); }, KisStrokeJobData::CONCURRENT)); } jobs.append(new KisRunnableStrokeJobData(0, KisStrokeJobData::SEQUENTIAL)); for (QRect &rc : rects) { state->painter->mirrorRect(direction, &rc); jobs.append( new KisRunnableStrokeJobData( [rc, state] () { state->painter->bltFixed(rc, state->dabsQueue); }, KisStrokeJobData::CONCURRENT)); } state->allDirtyRects.append(rects); } std::pair KisBrushOp::doAsyncronousUpdate(QVector &jobs) { bool someDabsAreStillInQueue = false; const bool hasPreparedDabsAtStart = m_dabExecutor->hasPreparedDabs(); if (!m_updateSharedState && hasPreparedDabsAtStart) { m_updateSharedState = toQShared(new UpdateSharedState()); UpdateSharedStateSP state = m_updateSharedState; state->painter = painter(); { const qreal dabRenderingTime = m_dabExecutor->averageDabRenderingTime(); const qreal totalRenderingTimePerDab = dabRenderingTime + m_avgUpdateTimePerDab.rollingMeanSafe(); // we limit the number of fetched dabs to fit the maximum update period and not // make visual hiccups const int dabsLimit = totalRenderingTimePerDab > 0 ? qMax(10, int(m_maxUpdatePeriod / totalRenderingTimePerDab * m_idealNumRects)) : -1; state->dabsQueue = m_dabExecutor->takeReadyDabs(painter()->hasMirroring(), dabsLimit, &someDabsAreStillInQueue); } KIS_SAFE_ASSERT_RECOVER_RETURN_VALUE(!state->dabsQueue.isEmpty(), std::make_pair(m_currentUpdatePeriod, false)); const int diameter = m_dabExecutor->averageDabSize(); const qreal spacing = m_avgSpacing.rollingMean(); const int idealNumRects = m_idealNumRects; QVector rects; // wrap the dabs if needed if (painter()->device()->defaultBounds()->wrapAroundMode()) { /** * In WA mode we do two things: * * 1) We ensure that the parallel threads do not access the same are on * the image. For normal updates that is ensured by the code in KisImage * and the scheduler. Here we should do that manually by adjusting 'rects' * so that they would not intersect in the wrapped space. * * 2) We duplicate dabs, to ensure that all the pieces of dabs are painted * inside the wrapped rect. No pieces are dabs are painted twice, because * we paint only the parts intersecting the wrap rect. */ const QRect wrapRect = painter()->device()->defaultBounds()->bounds(); QList wrappedDabs; Q_FOREACH (const KisRenderedDab &dab, state->dabsQueue) { const QVector normalizationOrigins = KisWrappedRect::normalizationOriginsForRect(dab.realBounds(), wrapRect); Q_FOREACH(const QPoint &pt, normalizationOrigins) { KisRenderedDab newDab = dab; newDab.offset = pt; rects.append(newDab.realBounds() & wrapRect); wrappedDabs.append(newDab); } } state->dabsQueue = wrappedDabs; } else { // just get all rects Q_FOREACH (const KisRenderedDab &dab, state->dabsQueue) { rects.append(dab.realBounds()); } } // split/merge rects into non-overlapping areas rects = KisPaintOpUtils::splitDabsIntoRects(rects, idealNumRects, diameter, spacing); state->allDirtyRects = rects; Q_FOREACH (const KisRenderedDab &dab, state->dabsQueue) { state->dabPoints.append(dab.realBounds().center()); } state->dabRenderingTimer.start(); Q_FOREACH (const QRect &rc, rects) { jobs.append( new KisRunnableStrokeJobData( [rc, state] () { state->painter->bltFixed(rc, state->dabsQueue); }, KisStrokeJobData::CONCURRENT)); } /** * After the dab has been rendered once, we should mirror it either one * (h __or__ v) or three (h __and__ v) times. This sequence of 'if's achieves * the goal without any extra copying. Please note that it has __no__ 'else' * branches, which is done intentionally! */ if (state->painter->hasHorizontalMirroring()) { addMirroringJobs(Qt::Horizontal, rects, state, jobs); } if (state->painter->hasVerticalMirroring()) { addMirroringJobs(Qt::Vertical, rects, state, jobs); } if (state->painter->hasHorizontalMirroring() && state->painter->hasVerticalMirroring()) { addMirroringJobs(Qt::Horizontal, rects, state, jobs); } jobs.append( new KisRunnableStrokeJobData( [state, this, someDabsAreStillInQueue] () { Q_FOREACH(const QRect &rc, state->allDirtyRects) { state->painter->addDirtyRect(rc); } state->painter->setAverageOpacity(state->dabsQueue.last().averageOpacity); const int updateRenderingTime = state->dabRenderingTimer.elapsed(); const qreal dabRenderingTime = m_dabExecutor->averageDabRenderingTime(); m_avgNumDabs(state->dabsQueue.size()); const qreal currentUpdateTimePerDab = qreal(updateRenderingTime) / state->dabsQueue.size(); m_avgUpdateTimePerDab(currentUpdateTimePerDab); /** * NOTE: using currentUpdateTimePerDab in the calculation for the next update time instead * of the average one makes rendering speed about 40% faster. It happens because the * adaptation period is shorter than if it used */ const qreal totalRenderingTimePerDab = dabRenderingTime + currentUpdateTimePerDab; const int approxDabRenderingTime = qreal(totalRenderingTimePerDab) * m_avgNumDabs.rollingMean() / m_idealNumRects; m_currentUpdatePeriod = someDabsAreStillInQueue ? m_minUpdatePeriod : qBound(m_minUpdatePeriod, int(1.5 * approxDabRenderingTime), m_maxUpdatePeriod); { // debug chunk // ENTER_FUNCTION() << ppVar(state->allDirtyRects.size()) << ppVar(state->dabsQueue.size()) << ppVar(dabRenderingTime) << ppVar(updateRenderingTime); // ENTER_FUNCTION() << ppVar(m_currentUpdatePeriod) << ppVar(someDabsAreStillInQueue); } // release all the dab devices state->dabsQueue.clear(); m_updateSharedState.clear(); }, KisStrokeJobData::SEQUENTIAL)); } else if (m_updateSharedState && hasPreparedDabsAtStart) { someDabsAreStillInQueue = true; } return std::make_pair(m_currentUpdatePeriod, someDabsAreStillInQueue); } KisSpacingInformation KisBrushOp::updateSpacingImpl(const KisPaintInformation &info) const { const qreal scale = m_sizeOption.apply(info) * KisLodTransform::lodToScale(painter()->device()); qreal rotation = m_rotationOption.apply(info); return effectiveSpacing(scale, rotation, &m_airbrushOption, &m_spacingOption, info); } KisTimingInformation KisBrushOp::updateTimingImpl(const KisPaintInformation &info) const { return KisPaintOpPluginUtils::effectiveTiming(&m_airbrushOption, &m_rateOption, info); } void KisBrushOp::paintLine(const KisPaintInformation& pi1, const KisPaintInformation& pi2, KisDistanceInformation *currentDistance) { if (m_sharpnessOption.isChecked() && m_brush && (m_brush->width() == 1) && (m_brush->height() == 1)) { if (!m_lineCacheDevice) { m_lineCacheDevice = source()->createCompositionSourceDevice(); } else { m_lineCacheDevice->clear(); } KisPainter p(m_lineCacheDevice); p.setPaintColor(painter()->paintColor()); p.drawDDALine(pi1.pos(), pi2.pos()); QRect rc = m_lineCacheDevice->extent(); painter()->bitBlt(rc.x(), rc.y(), m_lineCacheDevice, rc.x(), rc.y(), rc.width(), rc.height()); //fixes Bug 338011 painter()->renderMirrorMask(rc, m_lineCacheDevice); } else { KisPaintOp::paintLine(pi1, pi2, currentDistance); } } diff --git a/plugins/paintops/libpaintop/forms/wdgbrushchooser.ui b/plugins/paintops/libpaintop/forms/wdgbrushchooser.ui index b6909ef5ae..2c2eaf3fa5 100644 --- a/plugins/paintops/libpaintop/forms/wdgbrushchooser.ui +++ b/plugins/paintops/libpaintop/forms/wdgbrushchooser.ui @@ -1,184 +1,132 @@ WdgBrushChooser 0 0 - 504 + 545 270 0 0 0 0 QFrame::StyledPanel QFrame::Plain 0 0 0 0 0 Qt::Horizontal 40 20 QFrame::StyledPanel QFrame::Plain 0 Auto - - - - Use to set the size from which the Automatic Precision Setting should begin. The Precision will remain 5 before this value. - - - Starting Brush Size: - - - - - - - px - - - - - - - - 0 - 0 - - - - This determines every interval after which the precision should change. For example: if the delta value is set to be 15.00, after every 15 pts change in the size of brush, the precision will change. - - - Delta : - - - - - - - px - - - - - - - 0 - - - 0 0 Precision: Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter 0 0 - - KisDoubleParseSpinBox - QDoubleSpinBox -
kis_double_parse_spin_box.h
-
KisSliderSpinBox QWidget
kis_slider_spin_box.h
1
diff --git a/plugins/paintops/libpaintop/kis_brush_based_paintop.cpp b/plugins/paintops/libpaintop/kis_brush_based_paintop.cpp index 109e29b9ae..eca8aff271 100644 --- a/plugins/paintops/libpaintop/kis_brush_based_paintop.cpp +++ b/plugins/paintops/libpaintop/kis_brush_based_paintop.cpp @@ -1,181 +1,185 @@ /* * Copyright (c) 2008 Boudewijn Rempt * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program 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 General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include "kis_brush_based_paintop.h" #include "kis_properties_configuration.h" #include #include "kis_brush_option.h" #include #include #include "kis_painter.h" #include #include "kis_paintop_utils.h" #include "kis_paintop_plugin_utils.h" #include #include #include #ifdef HAVE_THREADED_TEXT_RENDERING_WORKAROUND Q_GLOBAL_STATIC(TextBrushInitializationWorkaround, s_instance) TextBrushInitializationWorkaround *TextBrushInitializationWorkaround::instance() { return s_instance; } void TextBrushInitializationWorkaround::preinitialize(KisPropertiesConfigurationSP settings) { if (KisBrushOptionProperties::isTextBrush(settings.data())) { KisBrushOptionProperties brushOption; brushOption.readOptionSetting(settings); m_brush = brushOption.brush(); m_settings = settings; } else { m_brush = 0; m_settings = 0; } } KisBrushSP TextBrushInitializationWorkaround::tryGetBrush(const KisPropertiesConfigurationSP settings) { return (settings && settings == m_settings ? m_brush : 0); } TextBrushInitializationWorkaround::TextBrushInitializationWorkaround() : m_settings(0) {} TextBrushInitializationWorkaround::~TextBrushInitializationWorkaround() {} void KisBrushBasedPaintOp::preinitializeOpStatically(KisPaintOpSettingsSP settings) { TextBrushInitializationWorkaround::instance()->preinitialize(settings); } #endif /* HAVE_THREADED_TEXT_RENDERING_WORKAROUND */ KisBrushBasedPaintOp::KisBrushBasedPaintOp(const KisPropertiesConfigurationSP settings, KisPainter* painter) : KisPaintOp(painter), m_textureProperties(painter->device()->defaultBounds()->currentLevelOfDetail()) { Q_ASSERT(settings); #ifdef HAVE_THREADED_TEXT_RENDERING_WORKAROUND m_brush = TextBrushInitializationWorkaround::instance()->tryGetBrush(settings); #endif /* HAVE_THREADED_TEXT_RENDERING_WORKAROUND */ if (!m_brush) { KisBrushOptionProperties brushOption; brushOption.readOptionSetting(settings); m_brush = brushOption.brush(); } m_brush->notifyStrokeStarted(); m_precisionOption.readOptionSetting(settings); m_dabCache = new KisDabCache(m_brush); m_dabCache->setPrecisionOption(&m_precisionOption); m_mirrorOption.readOptionSetting(settings); m_dabCache->setMirrorPostprocessing(&m_mirrorOption); m_textureProperties.fillProperties(settings); m_dabCache->setTexturePostprocessing(&m_textureProperties); + + m_precisionOption.setHasImprecisePositionOptions( + m_precisionOption.hasImprecisePositionOptions() | + m_mirrorOption.isChecked() | m_textureProperties.m_enabled); } KisBrushBasedPaintOp::~KisBrushBasedPaintOp() { delete m_dabCache; } bool KisBrushBasedPaintOp::checkSizeTooSmall(qreal scale) { scale *= m_brush->scale(); return KisPaintOpUtils::checkSizeTooSmall(scale, m_brush->width(), m_brush->height()); } KisSpacingInformation KisBrushBasedPaintOp::effectiveSpacing(qreal scale) const { // we parse dab rotation separately, so don't count it QSizeF metric = m_brush->characteristicSize(KisDabShape(scale, 1.0, 0)); return effectiveSpacing(metric.width(), metric.height(), 1.0, false, 0.0, false); } KisSpacingInformation KisBrushBasedPaintOp::effectiveSpacing(qreal scale, qreal rotation, const KisPaintInformation &pi) const { return effectiveSpacing(scale, rotation, nullptr, nullptr, pi); } KisSpacingInformation KisBrushBasedPaintOp::effectiveSpacing(qreal scale, qreal rotation, const KisPressureSpacingOption &spacingOption, const KisPaintInformation &pi) const { return effectiveSpacing(scale, rotation, nullptr, &spacingOption, pi); } KisSpacingInformation KisBrushBasedPaintOp::effectiveSpacing(qreal scale, qreal rotation, const KisAirbrushOptionProperties *airbrushOption, const KisPressureSpacingOption *spacingOption, const KisPaintInformation &pi) const { bool isotropicSpacing = spacingOption && spacingOption->isotropicSpacing(); MirrorProperties prop = m_mirrorOption.apply(pi); const bool implicitFlipped = prop.horizontalMirror != prop.verticalMirror; // we parse dab rotation separately, so don't count it QSizeF metric = m_brush->characteristicSize(KisDabShape(scale, 1.0, 0)); return KisPaintOpPluginUtils::effectiveSpacing(metric.width(), metric.height(), isotropicSpacing, rotation, implicitFlipped, m_brush->spacing(), m_brush->autoSpacingActive(), m_brush->autoSpacingCoeff(), KisLodTransform::lodToScale(painter()->device()), airbrushOption, spacingOption, pi); } KisSpacingInformation KisBrushBasedPaintOp::effectiveSpacing(qreal dabWidth, qreal dabHeight, qreal extraScale, bool isotropicSpacing, qreal rotation, bool axesFlipped) const { return KisPaintOpUtils::effectiveSpacing(dabWidth, dabHeight, extraScale, true, isotropicSpacing, rotation, axesFlipped, m_brush->spacing(), m_brush->autoSpacingActive(), m_brush->autoSpacingCoeff(), KisLodTransform::lodToScale(painter()->device())); } bool KisBrushBasedPaintOp::canPaint() const { return m_brush != 0; } diff --git a/plugins/paintops/libpaintop/kis_brush_selection_widget.cpp b/plugins/paintops/libpaintop/kis_brush_selection_widget.cpp index 0d0f2cdb03..6603bfb8d0 100644 --- a/plugins/paintops/libpaintop/kis_brush_selection_widget.cpp +++ b/plugins/paintops/libpaintop/kis_brush_selection_widget.cpp @@ -1,360 +1,324 @@ /* * Copyright (c) 2008 Boudewijn Rempt * Copyright (c) 2014 Mohit Goyal * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program 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 General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include "kis_brush_selection_widget.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include "kis_brush.h" #include "kis_auto_brush.h" #include "kis_imagepipe_brush.h" #include "kis_brush_chooser.h" #include "kis_auto_brush_widget.h" #include "kis_custom_brush_widget.h" #include "kis_clipboard_brush_widget.h" #include "kis_text_brush_chooser.h" KisBrushSelectionWidget::KisBrushSelectionWidget(QWidget * parent) : QWidget(parent), m_currentBrushWidget(0) { uiWdgBrushChooser.setupUi(this); m_buttonGroup = new QButtonGroup(this); m_buttonGroup->setExclusive(true); m_layout = new QGridLayout(uiWdgBrushChooser.settingsFrame); m_autoBrushWidget = new KisAutoBrushWidget(this, "autobrush"); connect(m_autoBrushWidget, SIGNAL(sigBrushChanged()), SIGNAL(sigBrushChanged())); addChooser(i18n("Auto"), m_autoBrushWidget, AUTOBRUSH, KoGroupButton::GroupLeft); m_predefinedBrushWidget = new KisPredefinedBrushChooser(this); connect(m_predefinedBrushWidget, SIGNAL(sigBrushChanged()), SIGNAL(sigBrushChanged())); addChooser(i18n("Predefined"), m_predefinedBrushWidget, PREDEFINEDBRUSH, KoGroupButton::GroupCenter); m_textBrushWidget = new KisTextBrushChooser(this, "textbrush", i18n("Text")); connect(m_textBrushWidget, SIGNAL(sigBrushChanged()), SIGNAL(sigBrushChanged())); addChooser(i18n("Text"), m_textBrushWidget, TEXTBRUSH, KoGroupButton::GroupRight); connect(m_buttonGroup, SIGNAL(buttonClicked(int)), this, SLOT(buttonClicked(int))); Q_FOREACH (QWidget * widget, m_chooserMap.values()) { m_mininmumSize = m_mininmumSize.expandedTo(widget->sizeHint()); } setCurrentWidget(m_autoBrushWidget); uiWdgBrushChooser.sliderPrecision->setRange(1, 5); uiWdgBrushChooser.sliderPrecision->setSingleStep(1); uiWdgBrushChooser.sliderPrecision->setPageStep(1); connect(uiWdgBrushChooser.sliderPrecision, SIGNAL(valueChanged(int)), SLOT(precisionChanged(int))); connect(uiWdgBrushChooser.autoPrecisionCheckBox, SIGNAL(stateChanged(int)), SLOT(setAutoPrecisionEnabled(int))); - connect(uiWdgBrushChooser.deltaValueSpinBox, SIGNAL(valueChanged(double)), SLOT(setDeltaValue(double))); - connect(uiWdgBrushChooser.sizeToStartFromSpinBox, SIGNAL(valueChanged(double)), SLOT(setSizeToStartFrom(double))); - uiWdgBrushChooser.sliderPrecision->setValue(4); + uiWdgBrushChooser.sliderPrecision->setValue(5); setPrecisionEnabled(false); - uiWdgBrushChooser.label->setVisible(false); - uiWdgBrushChooser.label_2->setVisible(false); - uiWdgBrushChooser.deltaValueSpinBox->setVisible(false); - uiWdgBrushChooser.sizeToStartFromSpinBox->setVisible(false); - uiWdgBrushChooser.lblPrecisionValue->setVisible(false); - uiWdgBrushChooser.label ->setToolTip(i18n("Use to set the size from which the Automatic Precision Setting should begin. \nThe Precision will remain 5 before this value.")); - uiWdgBrushChooser.label_2 ->setToolTip(i18n("Use to set the interval at which the Automatic Precision will change. \nThe Precision will decrease as brush size increases.")); m_presetIsValid = true; } KisBrushSelectionWidget::~KisBrushSelectionWidget() { } KisBrushSP KisBrushSelectionWidget::brush() const { KisBrushSP theBrush; switch (m_buttonGroup->checkedId()) { case AUTOBRUSH: theBrush = m_autoBrushWidget->brush(); break; case PREDEFINEDBRUSH: theBrush = m_predefinedBrushWidget->brush(); break; case TEXTBRUSH: theBrush = m_textBrushWidget->brush(); break; default: ; } // Fallback to auto brush if no brush selected // Can happen if there is no predefined brush found if (!theBrush) theBrush = m_autoBrushWidget->brush(); return theBrush; } - void KisBrushSelectionWidget::setAutoBrush(bool on) { m_buttonGroup->button(AUTOBRUSH)->setVisible(on); } void KisBrushSelectionWidget::setPredefinedBrushes(bool on) { m_buttonGroup->button(PREDEFINEDBRUSH)->setVisible(on); } void KisBrushSelectionWidget::setCustomBrush(bool on) { m_buttonGroup->button(CUSTOMBRUSH)->setVisible(on); } void KisBrushSelectionWidget::setClipboardBrush(bool on) { m_buttonGroup->button(CLIPBOARDBRUSH)->setVisible(on); } void KisBrushSelectionWidget::setTextBrush(bool on) { m_buttonGroup->button(TEXTBRUSH)->setVisible(on); } void KisBrushSelectionWidget::setImage(KisImageWSP image) { m_predefinedBrushWidget->setImage(image); } void KisBrushSelectionWidget::setCurrentBrush(KisBrushSP brush) { if (!brush) { return; } // XXX: clever code have brush plugins know their configuration // pane, so we don't have to have this if statement and // have an extensible set of brush types if (dynamic_cast(brush.data())) { setCurrentWidget(m_autoBrushWidget); m_autoBrushWidget->setBrush(brush); } else if (dynamic_cast(brush.data())) { setCurrentWidget(m_textBrushWidget); m_textBrushWidget->setBrush(brush); } else { setCurrentWidget(m_predefinedBrushWidget); m_predefinedBrushWidget->setBrush(brush); } } void KisBrushSelectionWidget::buttonClicked(int id) { setCurrentWidget(m_chooserMap[id]); emit sigBrushChanged(); } void KisBrushSelectionWidget::precisionChanged(int value) { QString toolTip; switch (value) { case 1: toolTip = i18n("Precision Level 1 (fastest)\n" "Subpixel precision: disabled\n" "Brush size precision: 5%\n" "\n" "Optimal for very big brushes"); break; case 2: toolTip = i18n("Precision Level 2\n" "Subpixel precision: disabled\n" "Brush size precision: 1%\n" "\n" "Optimal for big brushes"); break; case 3: toolTip = i18n("Precision Level 3\n" "Subpixel precision: disabled\n" "Brush size precision: exact"); break; case 4: toolTip = i18n("Precision Level 4 (optimal)\n" "Subpixel precision: 50%\n" "Brush size precision: exact\n" "\n" "Gives up to 50% better performance in comparison to Level 5"); break; case 5: toolTip = i18n("Precision Level 5 (best quality)\n" "Subpixel precision: exact\n" "Brush size precision: exact\n" "\n" "The slowest performance. Best quality."); break; } uiWdgBrushChooser.sliderPrecision->blockSignals(true); uiWdgBrushChooser.sliderPrecision->setValue(value); uiWdgBrushChooser.sliderPrecision->blockSignals(false); uiWdgBrushChooser.sliderPrecision->setToolTip(toolTip); m_precisionOption.setPrecisionLevel(value); emit sigPrecisionChanged(); } void KisBrushSelectionWidget::writeOptionSetting(KisPropertiesConfigurationSP settings) const { m_precisionOption.writeOptionSetting(settings); } void KisBrushSelectionWidget::readOptionSetting(const KisPropertiesConfigurationSP setting) { m_precisionOption.readOptionSetting(setting); uiWdgBrushChooser.sliderPrecision->setValue(m_precisionOption.precisionLevel()); uiWdgBrushChooser.autoPrecisionCheckBox->setChecked(m_precisionOption.autoPrecisionEnabled()); - uiWdgBrushChooser.deltaValueSpinBox ->setValue(m_precisionOption.deltaValue()); - uiWdgBrushChooser.sizeToStartFromSpinBox ->setValue(m_precisionOption.sizeToStartFrom()); } void KisBrushSelectionWidget::setPrecisionEnabled(bool value) { + uiWdgBrushChooser.autoPrecisionCheckBox->setVisible(value); uiWdgBrushChooser.sliderPrecision->setVisible(value); uiWdgBrushChooser.lblPrecision->setVisible(value); } void KisBrushSelectionWidget::hideOptions(const QStringList &options) { Q_FOREACH(const QString &option, options) { QStringList l = option.split("/"); if (l.count() != 2) { continue; } QObject *o = 0; if (l[0] == "KisAutoBrushWidget") { o = m_autoBrushWidget->findChild(l[1]); } else if (l[0] == "KisBrushChooser") { o = m_predefinedBrushWidget->findChild(l[1]); } else if (l[0] == "KisTextBrushChooser") { o = m_textBrushWidget->findChild(l[1]); } else { qWarning() << "KisBrushSelectionWidget: Invalid option given to disable:" << option; } if (o) { QWidget *w = qobject_cast(o); if (w) { w->setVisible(false); } o = 0; } } } void KisBrushSelectionWidget::setCurrentWidget(QWidget* widget) { if (widget == m_currentBrushWidget) return; if (m_currentBrushWidget) { m_layout->removeWidget(m_currentBrushWidget); m_currentBrushWidget->setParent(this); m_currentBrushWidget->hide(); } widget->setMinimumSize(m_mininmumSize); m_currentBrushWidget = widget; m_layout->addWidget(widget); m_currentBrushWidget->show(); m_buttonGroup->button(m_chooserMap.key(widget))->setChecked(true); m_presetIsValid = (m_buttonGroup->checkedId() != CUSTOMBRUSH); } void KisBrushSelectionWidget::addChooser(const QString& text, QWidget* widget, int id, KoGroupButton::GroupPosition pos) { KoGroupButton * button = new KoGroupButton(this); button->setGroupPosition(pos); button->setText(text); button->setAutoRaise(false); button->setCheckable(true); uiWdgBrushChooser.brushChooserButtonLayout->addWidget(button); m_buttonGroup->addButton(button, id); m_chooserMap[m_buttonGroup->id(button)] = widget; widget->hide(); } void KisBrushSelectionWidget::setAutoPrecisionEnabled(int value) { m_precisionOption.setAutoPrecisionEnabled(value); - if(m_precisionOption.autoPrecisionEnabled()) - { - m_precisionOption.setAutoPrecision(brush()->width()); - setPrecisionEnabled(false); + if (m_precisionOption.autoPrecisionEnabled()) { precisionChanged(m_precisionOption.precisionLevel()); - uiWdgBrushChooser.label->setVisible(true); - uiWdgBrushChooser.label_2->setVisible(true); - uiWdgBrushChooser.deltaValueSpinBox->setVisible(true); - uiWdgBrushChooser.sizeToStartFromSpinBox->setVisible(true); - uiWdgBrushChooser.lblPrecisionValue->setVisible(true); - uiWdgBrushChooser.lblPrecisionValue->setText("Precision:"+QString::number(m_precisionOption.precisionLevel())); - - } - else - { - setPrecisionEnabled(true); - uiWdgBrushChooser.label->setVisible(false); - uiWdgBrushChooser.label_2->setVisible(false); - uiWdgBrushChooser.deltaValueSpinBox->setVisible(false); - uiWdgBrushChooser.sizeToStartFromSpinBox->setVisible(false); - uiWdgBrushChooser.lblPrecisionValue->setVisible(false); + uiWdgBrushChooser.sliderPrecision->setEnabled(false); + uiWdgBrushChooser.lblPrecision->setEnabled(false); + } else { + uiWdgBrushChooser.sliderPrecision->setEnabled(true); + uiWdgBrushChooser.lblPrecision->setEnabled(true); } - emit sigPrecisionChanged(); -} -void KisBrushSelectionWidget::setSizeToStartFrom(double value) -{ - m_precisionOption.setSizeToStartFrom(value); - emit sigPrecisionChanged(); -} -void KisBrushSelectionWidget::setDeltaValue(double value) -{ - m_precisionOption.setDeltaValue(value); emit sigPrecisionChanged(); - } #include "moc_kis_brush_selection_widget.cpp" diff --git a/plugins/paintops/libpaintop/kis_brush_selection_widget.h b/plugins/paintops/libpaintop/kis_brush_selection_widget.h index ce345ba01b..81a7c395de 100644 --- a/plugins/paintops/libpaintop/kis_brush_selection_widget.h +++ b/plugins/paintops/libpaintop/kis_brush_selection_widget.h @@ -1,117 +1,115 @@ /* * Copyright (c) 2008 Boudewijn Rempt * Copyright (c) 2014 Mohit Goyal * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program 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 General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #ifndef KIS_BRUSH_SELECTION_WIDGET_H #define KIS_BRUSH_SELECTION_WIDGET_H #include #include #include #include #include "kis_precision_option.h" #include "ui_wdgbrushchooser.h" class KisAutoBrushWidget; class KisPredefinedBrushChooser; class KisTextBrushChooser; class KisCustomBrushWidget; class KisClipboardBrushWidget; class KisBrush; /** * Compound widget that collects all the various brush selection widgets. */ class PAINTOP_EXPORT KisBrushSelectionWidget : public QWidget { Q_OBJECT public: KisBrushSelectionWidget(QWidget * parent = 0); ~KisBrushSelectionWidget() override; KisBrushSP brush() const; void setAutoBrush(bool on); void setPredefinedBrushes(bool on); void setCustomBrush(bool on); void setClipboardBrush(bool on); void setTextBrush(bool on); void setImage(KisImageWSP image); void setCurrentBrush(KisBrushSP brush); bool presetIsValid() { return m_presetIsValid; } void writeOptionSetting(KisPropertiesConfigurationSP settings) const; void readOptionSetting(const KisPropertiesConfigurationSP setting); void setPrecisionEnabled(bool value); bool autoPrecisionEnabled(); void hideOptions(const QStringList &options); Q_SIGNALS: void sigBrushChanged(); void sigPrecisionChanged(); private Q_SLOTS: void buttonClicked(int id); void precisionChanged(int value); void setAutoPrecisionEnabled(int value); - void setSizeToStartFrom(double value); - void setDeltaValue(double value); private: void setCurrentWidget(QWidget * widget); void addChooser(const QString & text, QWidget * widget, int id, KoGroupButton::GroupPosition pos); private: enum Type { AUTOBRUSH, PREDEFINEDBRUSH, CUSTOMBRUSH, TEXTBRUSH, CLIPBOARDBRUSH }; bool m_presetIsValid; Ui_WdgBrushChooser uiWdgBrushChooser; QGridLayout * m_layout; QWidget * m_currentBrushWidget; QHash m_chooserMap; QButtonGroup * m_buttonGroup; QSize m_mininmumSize; KisAutoBrushWidget * m_autoBrushWidget; KisPredefinedBrushChooser * m_predefinedBrushWidget; KisTextBrushChooser * m_textBrushWidget; KisPrecisionOption m_precisionOption; }; #endif diff --git a/plugins/paintops/libpaintop/kis_dab_cache_base.cpp b/plugins/paintops/libpaintop/kis_dab_cache_base.cpp index 9fb631abae..5f7732638b 100644 --- a/plugins/paintops/libpaintop/kis_dab_cache_base.cpp +++ b/plugins/paintops/libpaintop/kis_dab_cache_base.cpp @@ -1,280 +1,285 @@ /* * Copyright (c) 2012 Dmitry Kazakov * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program 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 General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include "kis_dab_cache_base.h" #include #include "kis_color_source.h" #include "kis_paint_device.h" #include "kis_brush.h" #include #include #include #include #include #include #include struct PrecisionValues { qreal angle; qreal sizeFrac; qreal subPixel; qreal softnessFactor; }; const qreal eps = 1e-6; static const PrecisionValues precisionLevels[] = { {M_PI / 180, 0.05, 1, 0.01}, {M_PI / 180, 0.01, 1, 0.01}, {M_PI / 180, 0, 1, 0.01}, {M_PI / 180, 0, 0.5, 0.01}, {eps, 0, eps, eps} }; struct KisDabCacheBase::SavedDabParameters { KoColor color; qreal angle; int width; int height; qreal subPixelX; qreal subPixelY; qreal softnessFactor; int index; MirrorProperties mirrorProperties; bool compare(const SavedDabParameters &rhs, int precisionLevel) const { const PrecisionValues &prec = precisionLevels[precisionLevel]; return color == rhs.color && qAbs(angle - rhs.angle) <= prec.angle && qAbs(width - rhs.width) <= (int)(prec.sizeFrac * width) && qAbs(height - rhs.height) <= (int)(prec.sizeFrac * height) && qAbs(subPixelX - rhs.subPixelX) <= prec.subPixel && qAbs(subPixelY - rhs.subPixelY) <= prec.subPixel && qAbs(softnessFactor - rhs.softnessFactor) <= prec.softnessFactor && index == rhs.index && mirrorProperties.horizontalMirror == rhs.mirrorProperties.horizontalMirror && mirrorProperties.verticalMirror == rhs.mirrorProperties.verticalMirror; } }; struct KisDabCacheBase::Private { Private() : mirrorOption(0), precisionOption(0), subPixelPrecisionDisabled(false) {} KisPressureMirrorOption *mirrorOption; KisPrecisionOption *precisionOption; bool subPixelPrecisionDisabled; SavedDabParameters lastSavedDabParameters; static qreal positiveFraction(qreal x); }; KisDabCacheBase::KisDabCacheBase() : m_d(new Private()) { } KisDabCacheBase::~KisDabCacheBase() { delete m_d; } void KisDabCacheBase::setMirrorPostprocessing(KisPressureMirrorOption *option) { m_d->mirrorOption = option; } void KisDabCacheBase::setPrecisionOption(KisPrecisionOption *option) { m_d->precisionOption = option; } void KisDabCacheBase::disableSubpixelPrecision() { m_d->subPixelPrecisionDisabled = true; } inline KisDabCacheBase::SavedDabParameters KisDabCacheBase::getDabParameters(KisBrushSP brush, const KoColor& color, KisDabShape const& shape, const KisPaintInformation& info, double subPixelX, double subPixelY, qreal softnessFactor, MirrorProperties mirrorProperties) { SavedDabParameters params; params.color = color; params.angle = shape.rotation(); params.width = brush->maskWidth(shape, subPixelX, subPixelY, info); params.height = brush->maskHeight(shape, subPixelX, subPixelY, info); params.subPixelX = subPixelX; params.subPixelY = subPixelY; params.softnessFactor = softnessFactor; params.index = brush->brushIndex(info); params.mirrorProperties = mirrorProperties; return params; } bool KisDabCacheBase::needSeparateOriginal(KisTextureProperties *textureOption, KisPressureSharpnessOption *sharpnessOption) const { return (textureOption && textureOption->m_enabled) || (sharpnessOption && sharpnessOption->isChecked()); } struct KisDabCacheBase::DabPosition { DabPosition(const QRect &_rect, const QPointF &_subPixel, qreal _realAngle) : rect(_rect), subPixel(_subPixel), realAngle(_realAngle) { } QRect rect; QPointF subPixel; qreal realAngle; }; qreal KisDabCacheBase::Private::positiveFraction(qreal x) { qint32 unused = 0; qreal fraction = 0.0; KisPaintOp::splitCoordinate(x, &unused, &fraction); return fraction; } inline KisDabCacheBase::DabPosition KisDabCacheBase::calculateDabRect(KisBrushSP brush, const QPointF &cursorPoint, KisDabShape shape, const KisPaintInformation& info, const MirrorProperties &mirrorProperties, KisPressureSharpnessOption *sharpnessOption) { qint32 x = 0, y = 0; qreal subPixelX = 0.0, subPixelY = 0.0; if (mirrorProperties.coordinateSystemFlipped) { shape = KisDabShape(shape.scale(), shape.ratio(), 2 * M_PI - shape.rotation()); } QPointF hotSpot = brush->hotSpot(shape, info); QPointF pt = cursorPoint - hotSpot; if (sharpnessOption) { sharpnessOption->apply(info, pt, x, y, subPixelX, subPixelY); } else { KisPaintOp::splitCoordinate(pt.x(), &x, &subPixelX); KisPaintOp::splitCoordinate(pt.y(), &y, &subPixelY); } if (m_d->subPixelPrecisionDisabled) { subPixelX = 0; subPixelY = 0; } if (qIsNaN(subPixelX)) { subPixelX = 0; } if (qIsNaN(subPixelY)) { subPixelY = 0; } int width = brush->maskWidth(shape, subPixelX, subPixelY, info); int height = brush->maskHeight(shape, subPixelX, subPixelY, info); if (mirrorProperties.horizontalMirror) { subPixelX = Private::positiveFraction(-(cursorPoint.x() + hotSpot.x())); width = brush->maskWidth(shape, subPixelX, subPixelY, info); x = qRound(cursorPoint.x() + subPixelX + hotSpot.x()) - width; } if (mirrorProperties.verticalMirror) { subPixelY = Private::positiveFraction(-(cursorPoint.y() + hotSpot.y())); height = brush->maskHeight(shape, subPixelX, subPixelY, info); y = qRound(cursorPoint.y() + subPixelY + hotSpot.y()) - height; } return DabPosition(QRect(x, y, width, height), QPointF(subPixelX, subPixelY), shape.rotation()); } void KisDabCacheBase::fetchDabGenerationInfo(bool hasDabInCache, KisDabCacheUtils::DabRenderingResources *resources, const KisDabCacheUtils::DabRequestInfo &request, KisDabCacheUtils::DabGenerationInfo *di, bool *shouldUseCache) { di->info = request.info; di->softnessFactor = request.softnessFactor; if (m_d->mirrorOption) { di->mirrorProperties = m_d->mirrorOption->apply(request.info); } DabPosition position = calculateDabRect(resources->brush, request.cursorPoint, request.shape, request.info, di->mirrorProperties, resources->sharpnessOption.data()); di->shape = KisDabShape(request.shape.scale(), request.shape.ratio(), position.realAngle); di->dstDabRect = position.rect; di->subPixel = position.subPixel; di->solidColorFill = !resources->colorSource || resources->colorSource->isUniformColor(); di->paintColor = resources->colorSource && resources->colorSource->isUniformColor() ? resources->colorSource->uniformColor() : request.color; SavedDabParameters newParams = getDabParameters(resources->brush, di->paintColor, di->shape, di->info, di->subPixel.x(), di->subPixel.y(), di->softnessFactor, di->mirrorProperties); - const int precisionLevel = m_d->precisionOption ? m_d->precisionOption->precisionLevel() - 1 : 3; + int precisionLevel = 4; + if (m_d->precisionOption) { + const int effectiveDabSize = qMin(newParams.width, newParams.height); + precisionLevel = m_d->precisionOption->effectivePrecisionLevel(effectiveDabSize) - 1; + } + *shouldUseCache = hasDabInCache && di->solidColorFill && newParams.compare(m_d->lastSavedDabParameters, precisionLevel); if (!*shouldUseCache) { m_d->lastSavedDabParameters = newParams; } di->needsPostprocessing = needSeparateOriginal(resources->textureOption.data(), resources->sharpnessOption.data()); } diff --git a/plugins/paintops/libpaintop/kis_precision_option.cpp b/plugins/paintops/libpaintop/kis_precision_option.cpp index 5fb152aa24..b61420dae7 100644 --- a/plugins/paintops/libpaintop/kis_precision_option.cpp +++ b/plugins/paintops/libpaintop/kis_precision_option.cpp @@ -1,101 +1,73 @@ /* * Copyright (c) 2012 Dmitry Kazakov * Copyright (c) 2014 Mohit Goyal * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program 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 General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include "kis_precision_option.h" #include "kis_properties_configuration.h" void KisPrecisionOption::writeOptionSetting(KisPropertiesConfigurationSP settings) const { settings->setProperty(PRECISION_LEVEL, m_precisionLevel); settings->setProperty(AUTO_PRECISION_ENABLED,m_autoPrecisionEnabled); - settings->setProperty(STARTING_SIZE,m_sizeToStartFrom); - settings->setProperty(DELTA_VALUE,m_deltaValue); } void KisPrecisionOption::readOptionSetting(const KisPropertiesConfigurationSP settings) { m_precisionLevel = settings->getInt(PRECISION_LEVEL, 5); m_autoPrecisionEnabled = settings->getBool(AUTO_PRECISION_ENABLED,false); - m_deltaValue = settings->getDouble(DELTA_VALUE,15.00); - m_sizeToStartFrom = settings ->getDouble(STARTING_SIZE,0); } -int KisPrecisionOption::precisionLevel() const +int KisPrecisionOption::effectivePrecisionLevel(qreal effectiveDabSize) const { - return m_precisionLevel; + if (!m_autoPrecisionEnabled) { + return m_precisionLevel; + } else { + return effectiveDabSize < 30.0 || !m_hasImprecisePositionOptions ? 5 : 3; + } } -void KisPrecisionOption::setPrecisionLevel(int precisionLevel) -{ - m_precisionLevel = precisionLevel; -} -void KisPrecisionOption::setAutoPrecisionEnabled(int value) +void KisPrecisionOption::setHasImprecisePositionOptions(bool value) { - m_autoPrecisionEnabled = value; + m_hasImprecisePositionOptions = value; } -void KisPrecisionOption::setDeltaValue(double value) +bool KisPrecisionOption::hasImprecisePositionOptions() const { - m_deltaValue = value; + return m_hasImprecisePositionOptions; } -void KisPrecisionOption::setSizeToStartFrom(double value) -{ - m_sizeToStartFrom = value; -} -bool KisPrecisionOption::autoPrecisionEnabled() +int KisPrecisionOption::precisionLevel() const { - return m_autoPrecisionEnabled; + return m_precisionLevel; } -double KisPrecisionOption::deltaValue() +void KisPrecisionOption::setPrecisionLevel(int precisionLevel) { - return m_deltaValue; + m_precisionLevel = precisionLevel; } -double KisPrecisionOption::sizeToStartFrom() +void KisPrecisionOption::setAutoPrecisionEnabled(int value) { - return m_sizeToStartFrom; + m_autoPrecisionEnabled = value; } -void KisPrecisionOption::setAutoPrecision(double brushSize) + +bool KisPrecisionOption::autoPrecisionEnabled() { - double deltaValue = this->deltaValue(); - double sizeToStartFrom = this ->sizeToStartFrom(); - if (brushSize < sizeToStartFrom + deltaValue) - { - this->setPrecisionLevel(5); - } - else if (brushSize >= sizeToStartFrom + deltaValue && brushSize < sizeToStartFrom + deltaValue*2) - { - this->setPrecisionLevel(4); - } - else if (brushSize >= sizeToStartFrom + deltaValue*2 && brushSize < sizeToStartFrom + deltaValue*3) - { - this->setPrecisionLevel(3); - } - else if (brushSize >= sizeToStartFrom + deltaValue*3 && brushSize < sizeToStartFrom + deltaValue*4) - { - this->setPrecisionLevel(2); - } - else if (brushSize >= sizeToStartFrom + deltaValue*4) - { - this->setPrecisionLevel(1); - } + return m_autoPrecisionEnabled; } diff --git a/plugins/paintops/libpaintop/kis_precision_option.h b/plugins/paintops/libpaintop/kis_precision_option.h index f7089c3a96..49e2119521 100644 --- a/plugins/paintops/libpaintop/kis_precision_option.h +++ b/plugins/paintops/libpaintop/kis_precision_option.h @@ -1,56 +1,56 @@ /* * Copyright (c) 2012 Dmitry Kazakov * Copyright (c) 2014 Mohit Goyal * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program 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 General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #ifndef __KIS_PRECISION_OPTION_H #define __KIS_PRECISION_OPTION_H #include #include #include const QString PRECISION_LEVEL = "KisPrecisionOption/precisionLevel"; const QString AUTO_PRECISION_ENABLED = "KisPrecisionOption/AutoPrecisionEnabled"; const QString STARTING_SIZE = "KisPrecisionOption/SizeToStartFrom"; const QString DELTA_VALUE = "KisPrecisionOption/DeltaValue"; class PAINTOP_EXPORT KisPrecisionOption { public: void writeOptionSetting(KisPropertiesConfigurationSP settings) const; void readOptionSetting(const KisPropertiesConfigurationSP settings); + int effectivePrecisionLevel(qreal effectiveDabSize) const; + void setHasImprecisePositionOptions(bool value); + bool hasImprecisePositionOptions() const; + int precisionLevel() const; void setPrecisionLevel(int precisionLevel); void setAutoPrecisionEnabled(int); - void setDeltaValue(double); - void setSizeToStartFrom(double); bool autoPrecisionEnabled(); - double deltaValue(); - double sizeToStartFrom(); - void setAutoPrecision(double brushSize); private: int m_precisionLevel; bool m_autoPrecisionEnabled; double m_sizeToStartFrom; double m_deltaValue; + bool m_hasImprecisePositionOptions = false; }; #endif /* __KIS_PRECISION_OPTION_H */