diff --git a/commands/imagelib/effects/kpEffectBalanceCommand.cpp b/commands/imagelib/effects/kpEffectBalanceCommand.cpp index 395c17f6..4416d344 100644 --- a/commands/imagelib/effects/kpEffectBalanceCommand.cpp +++ b/commands/imagelib/effects/kpEffectBalanceCommand.cpp @@ -1,57 +1,55 @@ /* Copyright (c) 2003-2007 Clarence Dang All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include "kpEffectBalanceCommand.h" #include "imagelib/effects/kpEffectBalance.h" #include //-------------------------------------------------------------------------------- kpEffectBalanceCommand::kpEffectBalanceCommand (int channels, int brightness, int contrast, int gamma, bool actOnSelection, kpCommandEnvironment *environ) : kpEffectCommandBase (i18n ("Balance"), actOnSelection, environ), m_channels (channels), m_brightness (brightness), m_contrast (contrast), m_gamma (gamma) { } -kpEffectBalanceCommand::~kpEffectBalanceCommand () -{ -} +kpEffectBalanceCommand::~kpEffectBalanceCommand () = default; // protected virtual [base kpEffectCommandBase] kpImage kpEffectBalanceCommand::applyEffect (const kpImage &image) { return kpEffectBalance::applyEffect (image, m_channels, m_brightness, m_contrast, m_gamma); } diff --git a/commands/imagelib/effects/kpEffectBlurSharpenCommand.cpp b/commands/imagelib/effects/kpEffectBlurSharpenCommand.cpp index ef59f36b..9e35845f 100644 --- a/commands/imagelib/effects/kpEffectBlurSharpenCommand.cpp +++ b/commands/imagelib/effects/kpEffectBlurSharpenCommand.cpp @@ -1,71 +1,68 @@ /* Copyright (c) 2003-2007 Clarence Dang All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #define DEBUG_KP_EFFECT_BLUR_SHARPEN 0 #include "kpEffectBlurSharpenCommand.h" #include //-------------------------------------------------------------------------------- kpEffectBlurSharpenCommand::kpEffectBlurSharpenCommand (kpEffectBlurSharpen::Type type, int strength, bool actOnSelection, kpCommandEnvironment *environ) : kpEffectCommandBase (kpEffectBlurSharpenCommand::nameForType (type), actOnSelection, environ), m_type (type), m_strength (strength) { } -kpEffectBlurSharpenCommand::~kpEffectBlurSharpenCommand () -{ -} +kpEffectBlurSharpenCommand::~kpEffectBlurSharpenCommand () = default; // public static QString kpEffectBlurSharpenCommand::nameForType (kpEffectBlurSharpen::Type type) { - if (type == kpEffectBlurSharpen::Blur) - return i18n ("Soften"); - else if (type == kpEffectBlurSharpen::Sharpen) - return i18n ("Sharpen"); - else - return QString(); + switch (type) { + case kpEffectBlurSharpen::Blur: return i18n ("Soften"); + case kpEffectBlurSharpen::Sharpen: return i18n ("Sharpen"); + default: return QString(); + } } // protected virtual [base kpEffectCommandBase] kpImage kpEffectBlurSharpenCommand::applyEffect (const kpImage &image) { return kpEffectBlurSharpen::applyEffect (image, m_type, m_strength); } diff --git a/commands/imagelib/effects/kpEffectClearCommand.cpp b/commands/imagelib/effects/kpEffectClearCommand.cpp index 0c9bf920..9cf7cf02 100644 --- a/commands/imagelib/effects/kpEffectClearCommand.cpp +++ b/commands/imagelib/effects/kpEffectClearCommand.cpp @@ -1,112 +1,110 @@ /* Copyright (c) 2003-2007 Clarence Dang All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include "kpEffectClearCommand.h" #include "layers/selections/image/kpAbstractImageSelection.h" #include "kpDefs.h" #include "document/kpDocument.h" #include //-------------------------------------------------------------------------------- kpEffectClearCommand::kpEffectClearCommand (bool actOnSelection, const kpColor &newColor, kpCommandEnvironment *environ) : kpCommand (environ), m_actOnSelection (actOnSelection), m_newColor (newColor), m_oldImagePtr (nullptr) { } kpEffectClearCommand::~kpEffectClearCommand () { delete m_oldImagePtr; } // public virtual [base kpCommand] QString kpEffectClearCommand::name () const { QString opName = i18n ("Clear"); - if (m_actOnSelection) - return i18n ("Selection: %1", opName); - else - return opName; + return (m_actOnSelection) ? i18n ("Selection: %1", opName) : opName; } // public virtual [base kpCommand] kpCommandSize::SizeType kpEffectClearCommand::size () const { return ImageSize (m_oldImagePtr); } // public virtual [base kpCommand] void kpEffectClearCommand::execute () { kpDocument *doc = document (); Q_ASSERT (doc); m_oldImagePtr = new kpImage (); *m_oldImagePtr = doc->image (m_actOnSelection); // REFACTOR: Would like to derive entire class from kpEffectCommandBase but // this code makes it difficult since it's not just acting on pixels // (kpAbstractImageSelection::fill() takes into account the shape of a selection). if (m_actOnSelection) { // OPT: could just edit pixmap directly and signal change kpAbstractImageSelection *sel = doc->imageSelection (); Q_ASSERT (sel); sel->fill (m_newColor); } - else + else { doc->fill (m_newColor); + } } // public virtual [base kpCommand] void kpEffectClearCommand::unexecute () { kpDocument *doc = document (); Q_ASSERT (doc); doc->setImage (m_actOnSelection, *m_oldImagePtr); delete m_oldImagePtr; m_oldImagePtr = nullptr; } diff --git a/commands/imagelib/effects/kpEffectCommandBase.cpp b/commands/imagelib/effects/kpEffectCommandBase.cpp index 3ebca3a9..67c90700 100644 --- a/commands/imagelib/effects/kpEffectCommandBase.cpp +++ b/commands/imagelib/effects/kpEffectCommandBase.cpp @@ -1,127 +1,124 @@ /* Copyright (c) 2003-2007 Clarence Dang All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include "kpEffectCommandBase.h" #include "kpDefs.h" #include "document/kpDocument.h" #include "generic/kpSetOverrideCursorSaver.h" #include //-------------------------------------------------------------------------------- struct kpEffectCommandBasePrivate { QString name; - bool actOnSelection; + bool actOnSelection{false}; kpImage oldImage; }; kpEffectCommandBase::kpEffectCommandBase (const QString &name, bool actOnSelection, kpCommandEnvironment *environ) : kpCommand (environ), d (new kpEffectCommandBasePrivate ()) { d->name = name; d->actOnSelection = actOnSelection; } kpEffectCommandBase::~kpEffectCommandBase () { delete d; } // public virtual [base kpCommand] QString kpEffectCommandBase::name () const { - if (d->actOnSelection) - return i18n ("Selection: %1", d->name); - else - return d->name; + return (d->actOnSelection) ? i18n ("Selection: %1", d->name) : d->name; } // public virtual [base kpCommand] kpCommandSize::SizeType kpEffectCommandBase::size () const { return ImageSize (d->oldImage); } // public virtual [base kpCommand] void kpEffectCommandBase::execute () { kpSetOverrideCursorSaver cursorSaver (Qt::WaitCursor); kpDocument *doc = document (); Q_ASSERT (doc); const kpImage oldImage = doc->image (d->actOnSelection); if (!isInvertible ()) { d->oldImage = oldImage; } kpImage newImage = /*pure virtual*/applyEffect (oldImage); doc->setImage (d->actOnSelection, newImage); } // public virtual [base kpCommand] void kpEffectCommandBase::unexecute () { kpSetOverrideCursorSaver cursorSaver (Qt::WaitCursor); kpDocument *doc = document (); Q_ASSERT (doc); kpImage newImage; if (!isInvertible ()) { newImage = d->oldImage; } else { newImage = /*pure virtual*/applyEffect (doc->image (d->actOnSelection)); } doc->setImage (d->actOnSelection, newImage); d->oldImage = kpImage (); } diff --git a/commands/imagelib/effects/kpEffectEmbossCommand.cpp b/commands/imagelib/effects/kpEffectEmbossCommand.cpp index c79f0e10..dab84608 100644 --- a/commands/imagelib/effects/kpEffectEmbossCommand.cpp +++ b/commands/imagelib/effects/kpEffectEmbossCommand.cpp @@ -1,57 +1,55 @@ /* Copyright (c) 2003-2007 Clarence Dang All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #define DEBUG_KP_EFFECT_EMBOSS 0 #include "kpEffectEmbossCommand.h" #include "imagelib/effects/kpEffectEmboss.h" #include "kpLogCategories.h" #include kpEffectEmbossCommand::kpEffectEmbossCommand (int strength, bool actOnSelection, kpCommandEnvironment *environ) : kpEffectCommandBase (i18n ("Emboss"), actOnSelection, environ), m_strength (strength) { } -kpEffectEmbossCommand::~kpEffectEmbossCommand () -{ -} +kpEffectEmbossCommand::~kpEffectEmbossCommand () = default; // protected virtual [base kpEffectCommandBase] kpImage kpEffectEmbossCommand::applyEffect (const kpImage &image) { return kpEffectEmboss::applyEffect (image, m_strength); } diff --git a/commands/imagelib/effects/kpEffectFlattenCommand.cpp b/commands/imagelib/effects/kpEffectFlattenCommand.cpp index 570eaa92..f76aa51d 100644 --- a/commands/imagelib/effects/kpEffectFlattenCommand.cpp +++ b/commands/imagelib/effects/kpEffectFlattenCommand.cpp @@ -1,63 +1,61 @@ /* Copyright (c) 2003-2007 Clarence Dang All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #define DEBUG_KP_EFFECT_FLATTEN 0 #include "kpEffectFlattenCommand.h" #include "imagelib/effects/kpEffectFlatten.h" #include //-------------------------------------------------------------------------------- kpEffectFlattenCommand::kpEffectFlattenCommand (const QColor &color1, const QColor &color2, bool actOnSelection, kpCommandEnvironment *environ) : kpEffectCommandBase (i18n ("Flatten"), actOnSelection, environ), m_color1 (color1), m_color2 (color2) { } -kpEffectFlattenCommand::~kpEffectFlattenCommand () -{ -} +kpEffectFlattenCommand::~kpEffectFlattenCommand () = default; // // kpEffectFlattenCommand implements kpEffectCommandBase interface // // protected virtual [base kpEffectCommandBase] kpImage kpEffectFlattenCommand::applyEffect (const kpImage &image) { return kpEffectFlatten::applyEffect (image, m_color1, m_color2); } diff --git a/commands/imagelib/effects/kpEffectGrayscaleCommand.cpp b/commands/imagelib/effects/kpEffectGrayscaleCommand.cpp index 80ddde5e..4c145fee 100644 --- a/commands/imagelib/effects/kpEffectGrayscaleCommand.cpp +++ b/commands/imagelib/effects/kpEffectGrayscaleCommand.cpp @@ -1,61 +1,59 @@ /* Copyright (c) 2003-2007 Clarence Dang All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include "kpEffectGrayscaleCommand.h" #include "imagelib/effects/kpEffectGrayscale.h" #include //-------------------------------------------------------------------------------- kpEffectGrayscaleCommand::kpEffectGrayscaleCommand ( bool actOnSelection, kpCommandEnvironment *environ) : kpEffectCommandBase ( i18n ("Reduce to Grayscale"), actOnSelection, environ) { } -kpEffectGrayscaleCommand::~kpEffectGrayscaleCommand () -{ -} +kpEffectGrayscaleCommand::~kpEffectGrayscaleCommand () = default; // // kpEffectGrayscaleCommand implements kpEffectCommandBase interface // // protected virtual [base kpEffectCommandBase] kpImage kpEffectGrayscaleCommand::applyEffect (const kpImage &image) { return kpEffectGrayscale::applyEffect (image); } diff --git a/commands/imagelib/effects/kpEffectInvertCommand.cpp b/commands/imagelib/effects/kpEffectInvertCommand.cpp index d2564fa4..31621f93 100644 --- a/commands/imagelib/effects/kpEffectInvertCommand.cpp +++ b/commands/imagelib/effects/kpEffectInvertCommand.cpp @@ -1,69 +1,67 @@ /* Copyright (c) 2003-2007 Clarence Dang All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include "kpEffectInvertCommand.h" #include "imagelib/effects/kpEffectInvert.h" #include //-------------------------------------------------------------------------------- kpEffectInvertCommand::kpEffectInvertCommand (int channels, bool actOnSelection, kpCommandEnvironment *environ) : kpEffectCommandBase (channels == kpEffectInvert::RGB ? i18n ("Invert Colors") : i18n ("Invert"), actOnSelection, environ), m_channels (channels) { } kpEffectInvertCommand::kpEffectInvertCommand (bool actOnSelection, kpCommandEnvironment *environ) : kpEffectCommandBase (i18n ("Invert Colors"), actOnSelection, environ), m_channels (kpEffectInvert::RGB) { } -kpEffectInvertCommand::~kpEffectInvertCommand () -{ -} +kpEffectInvertCommand::~kpEffectInvertCommand () = default; // // kpEffectInvertCommand implements kpEffectCommandBase interface // // protected virtual [base kpEffectCommandBase] kpImage kpEffectInvertCommand::applyEffect (const kpImage &image) { return kpEffectInvert::applyEffect (image, m_channels); } diff --git a/commands/imagelib/effects/kpEffectReduceColorsCommand.cpp b/commands/imagelib/effects/kpEffectReduceColorsCommand.cpp index 03c5d9a6..600e6621 100644 --- a/commands/imagelib/effects/kpEffectReduceColorsCommand.cpp +++ b/commands/imagelib/effects/kpEffectReduceColorsCommand.cpp @@ -1,84 +1,80 @@ /* Copyright (c) 2003-2007 Clarence Dang All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #define DEBUG_KP_EFFECT_REDUCE_COLORS 0 #include "kpEffectReduceColorsCommand.h" #include "imagelib/effects/kpEffectReduceColors.h" #include //--------------------------------------------------------------------- kpEffectReduceColorsCommand::kpEffectReduceColorsCommand (int depth, bool dither, bool actOnSelection, kpCommandEnvironment *environ) : kpEffectCommandBase (commandName (depth, dither), actOnSelection, environ), m_depth (depth), m_dither (dither) { } //--------------------------------------------------------------------- // public QString kpEffectReduceColorsCommand::commandName (int depth, int dither) const { - if (depth == 1) - { - if (dither) + switch (depth) { + case 1: if (dither) { return i18n ("Reduce to Monochrome (Dithered)"); - else - return i18n ("Reduce to Monochrome"); - } - else if (depth == 8) - { - if (dither) + } + return i18n ("Reduce to Monochrome"); + + case 8: + if (dither) { return i18n ("Reduce to 256 Color (Dithered)"); - else - return i18n ("Reduce to 256 Color"); - } - else - { - return QString(); + } + return i18n ("Reduce to 256 Color"); + + default: return QString(); } } //--------------------------------------------------------------------- // // kpEffectReduceColorsCommand implements kpEffectCommandBase interface // // protected virtual [base kpEffectCommandBase] kpImage kpEffectReduceColorsCommand::applyEffect (const kpImage &image) { return kpEffectReduceColors::applyEffect (image, m_depth, m_dither); } //--------------------------------------------------------------------- diff --git a/commands/imagelib/effects/kpEffectToneEnhanceCommand.cpp b/commands/imagelib/effects/kpEffectToneEnhanceCommand.cpp index b59cf7f6..c861dda5 100644 --- a/commands/imagelib/effects/kpEffectToneEnhanceCommand.cpp +++ b/commands/imagelib/effects/kpEffectToneEnhanceCommand.cpp @@ -1,56 +1,54 @@ /* Copyright (c) 2003-2007 Clarence Dang Copyright (c) 2006 Mike Gashler All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include "kpEffectToneEnhanceCommand.h" #include "imagelib/effects/kpEffectToneEnhance.h" #include //-------------------------------------------------------------------------------- kpEffectToneEnhanceCommand::kpEffectToneEnhanceCommand (double granularity, double amount, bool actOnSelection, kpCommandEnvironment *environ) : kpEffectCommandBase (i18n ("Histogram Equalizer"), actOnSelection, environ), m_granularity (granularity), m_amount (amount) { } -kpEffectToneEnhanceCommand::~kpEffectToneEnhanceCommand () -{ -} +kpEffectToneEnhanceCommand::~kpEffectToneEnhanceCommand () = default; // protected virtual [base kpEffectCommandBase] kpImage kpEffectToneEnhanceCommand::applyEffect (const kpImage &image) { return kpEffectToneEnhance::applyEffect (image, m_granularity, m_amount); } diff --git a/commands/imagelib/transforms/kpTransformFlipCommand.cpp b/commands/imagelib/transforms/kpTransformFlipCommand.cpp index 351ad210..fc4553f2 100644 --- a/commands/imagelib/transforms/kpTransformFlipCommand.cpp +++ b/commands/imagelib/transforms/kpTransformFlipCommand.cpp @@ -1,136 +1,135 @@ /* Copyright (c) 2003-2007 Clarence Dang All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include "kpTransformFlipCommand.h" #include #include "kpLogCategories.h" #include "layers/selections/image/kpAbstractImageSelection.h" #include "environments/commands/kpCommandEnvironment.h" #include "kpDefs.h" #include "document/kpDocument.h" #include "pixmapfx/kpPixmapFX.h" #include //--------------------------------------------------------------------- kpTransformFlipCommand::kpTransformFlipCommand (bool actOnSelection, bool horiz, bool vert, kpCommandEnvironment *environ) : kpCommand (environ), m_actOnSelection (actOnSelection), m_horiz (horiz), m_vert (vert) { } //--------------------------------------------------------------------- -kpTransformFlipCommand::~kpTransformFlipCommand () -{ -} +kpTransformFlipCommand::~kpTransformFlipCommand () = default; //--------------------------------------------------------------------- // public virtual [base kpCommand] QString kpTransformFlipCommand::name () const { QString opName; #if 1 opName = i18n ("Flip"); #else // re-enable when giving full descriptions for all actions if (m_horiz && m_vert) opName = i18n ("Flip horizontally and vertically"); else if (m_horiz) opName = i18n ("Flip horizontally"); else if (m_vert) opName = i18n ("Flip vertically"); else { - qCCritical(kpLogCommands) << "kpTransformFlipCommand::name() not asked to flip" << endl; + qCCritical(kpLogCommands) << "kpTransformFlipCommand::name() not asked to flip"; return QString(); } #endif - if (m_actOnSelection) + if (m_actOnSelection) { return i18n ("Selection: %1", opName); - else - return opName; + } + + return opName; } //--------------------------------------------------------------------- // public virtual [base kpCommand] kpCommandSize::SizeType kpTransformFlipCommand::size () const { return 0; } //--------------------------------------------------------------------- // public virtual [base kpCommand] void kpTransformFlipCommand::execute () { flip (); } //--------------------------------------------------------------------- // public virtual [base kpCommand] void kpTransformFlipCommand::unexecute () { flip (); } //--------------------------------------------------------------------- // private void kpTransformFlipCommand::flip () { kpDocument *doc = document (); Q_ASSERT (doc); QApplication::setOverrideCursor (Qt::WaitCursor); if (m_actOnSelection) { Q_ASSERT (doc->imageSelection ()); doc->imageSelection ()->flip (m_horiz, m_vert); environ ()->somethingBelowTheCursorChanged (); } else { doc->setImage(doc->image().mirrored(m_horiz, m_vert)); } QApplication::restoreOverrideCursor (); } diff --git a/commands/imagelib/transforms/kpTransformResizeScaleCommand.cpp b/commands/imagelib/transforms/kpTransformResizeScaleCommand.cpp index c6de8d15..4a52f260 100644 --- a/commands/imagelib/transforms/kpTransformResizeScaleCommand.cpp +++ b/commands/imagelib/transforms/kpTransformResizeScaleCommand.cpp @@ -1,473 +1,482 @@ /* Copyright (c) 2003-2007 Clarence Dang All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #define DEBUG_KP_TOOL_RESIZE_SCALE_COMMAND 0 #define DEBUG_KP_TOOL_RESIZE_SCALE_DIALOG 0 #include "kpTransformResizeScaleCommand.h" #include "layers/selections/image/kpAbstractImageSelection.h" #include "environments/commands/kpCommandEnvironment.h" #include "kpDefs.h" #include "document/kpDocument.h" #include "layers/selections/image/kpFreeFormImageSelection.h" #include "pixmapfx/kpPixmapFX.h" #include "layers/selections/image/kpRectangularImageSelection.h" #include "layers/selections/text/kpTextSelection.h" #include #include #include #include #include #include #include "kpLogCategories.h" #include //-------------------------------------------------------------------------------- kpTransformResizeScaleCommand::kpTransformResizeScaleCommand (bool actOnSelection, int newWidth, int newHeight, Type type, kpCommandEnvironment *environ) : kpCommand (environ), m_actOnSelection (actOnSelection), m_type (type), m_backgroundColor (environ->backgroundColor ()), m_oldSelectionPtr (nullptr) { kpDocument *doc = document (); Q_ASSERT (doc); m_oldWidth = doc->width (m_actOnSelection); m_oldHeight = doc->height (m_actOnSelection); m_actOnTextSelection = (m_actOnSelection && doc->textSelection ()); resize (newWidth, newHeight); // If we have a selection _border_ (but not a floating selection), // then scale the selection with the document m_scaleSelectionWithImage = (!m_actOnSelection && (m_type == Scale || m_type == SmoothScale) && document ()->selection () && !document ()->selection ()->hasContent ()); } kpTransformResizeScaleCommand::~kpTransformResizeScaleCommand () { delete m_oldSelectionPtr; } // public virtual [base kpCommand] QString kpTransformResizeScaleCommand::name () const { if (m_actOnSelection) { if (m_actOnTextSelection) { - if (m_type == Resize) + if (m_type == Resize) { return i18n ("Text: Resize Box"); + } } else { - if (m_type == Scale) + if (m_type == Scale) { return i18n ("Selection: Scale"); - else if (m_type == SmoothScale) + } + + if (m_type == SmoothScale) { return i18n ("Selection: Smooth Scale"); + } } } else { switch (m_type) { case Resize: return i18n ("Resize"); case Scale: return i18n ("Scale"); case SmoothScale: return i18n ("Smooth Scale"); } } return QString (); } // public virtual [base kpCommand] kpCommandSize::SizeType kpTransformResizeScaleCommand::size () const { return ImageSize (m_oldImage) + ImageSize (m_oldRightImage) + ImageSize (m_oldBottomImage) + SelectionSize (m_oldSelectionPtr); } // public int kpTransformResizeScaleCommand::newWidth () const { return m_newWidth; } // public void kpTransformResizeScaleCommand::setNewWidth (int width) { resize (width, newHeight ()); } // public int kpTransformResizeScaleCommand::newHeight () const { return m_newHeight; } // public void kpTransformResizeScaleCommand::setNewHeight (int height) { resize (newWidth (), height); } // public QSize kpTransformResizeScaleCommand::newSize () const { - return QSize (newWidth (), newHeight ()); + return {newWidth (), newHeight ()}; } // public virtual void kpTransformResizeScaleCommand::resize (int width, int height) { m_newWidth = width; m_newHeight = height; m_isLosslessScale = ((m_type == Scale) && (m_newWidth / m_oldWidth * m_oldWidth == m_newWidth) && (m_newHeight / m_oldHeight * m_oldHeight == m_newHeight)); } // public bool kpTransformResizeScaleCommand::scaleSelectionWithImage () const { return m_scaleSelectionWithImage; } // private void kpTransformResizeScaleCommand::scaleSelectionRegionWithDocument () { #if DEBUG_KP_TOOL_RESIZE_SCALE_COMMAND - qCDebug(kpLogCommands) << "kpTransformResizeScaleCommand::scaleSelectionRegionWithDocument" - << endl; + qCDebug(kpLogCommands) << "kpTransformResizeScaleCommand::scaleSelectionRegionWithDocument"; #endif Q_ASSERT (m_oldSelectionPtr); Q_ASSERT (!m_oldSelectionPtr->hasContent ()); const double horizScale = double (m_newWidth) / double (m_oldWidth); const double vertScale = double (m_newHeight) / double (m_oldHeight); const int newX = static_cast (m_oldSelectionPtr->x () * horizScale); const int newY = static_cast (m_oldSelectionPtr->y () * vertScale); QPolygon currentPoints = m_oldSelectionPtr->calculatePoints (); currentPoints.translate (-currentPoints.boundingRect ().x (), -currentPoints.boundingRect ().y ()); // TODO: refactor into kpPixmapFX // TODO: Can we get to size 0x0 accidently? QTransform scaleMatrix; scaleMatrix.scale (horizScale, vertScale); currentPoints = scaleMatrix.map (currentPoints); currentPoints.translate ( -currentPoints.boundingRect ().x () + newX, -currentPoints.boundingRect ().y () + newY); - kpAbstractImageSelection *imageSel = - dynamic_cast (m_oldSelectionPtr); - kpTextSelection *textSel = - dynamic_cast (m_oldSelectionPtr); + auto *imageSel = dynamic_cast (m_oldSelectionPtr); + auto *textSel = dynamic_cast (m_oldSelectionPtr); + if (imageSel) { document ()->setSelection ( kpFreeFormImageSelection (currentPoints, kpImage (), imageSel->transparency ())); } else if (textSel) { document ()->setSelection ( kpTextSelection (currentPoints.boundingRect (), textSel->textLines (), textSel->textStyle ())); } - else + else { Q_ASSERT (!"Unknown selection type"); + } environ ()->somethingBelowTheCursorChanged (); } // public virtual [base kpCommand] void kpTransformResizeScaleCommand::execute () { qCDebug(kpLogCommands) << "kpTransformResizeScaleCommand::execute() type=" << (int) m_type << " oldWidth=" << m_oldWidth << " oldHeight=" << m_oldHeight << " newWidth=" << m_newWidth - << " newHeight=" << m_newHeight - << endl; + << " newHeight=" << m_newHeight; if (m_oldWidth == m_newWidth && m_oldHeight == m_newHeight) return; if (m_type == Resize) { if (m_actOnSelection) { - if (!m_actOnTextSelection) + if (!m_actOnTextSelection) { Q_ASSERT (!"kpTransformResizeScaleCommand::execute() resizing sel doesn't make sense"); + } QApplication::setOverrideCursor (Qt::WaitCursor); kpTextSelection *textSel = textSelection (); Q_ASSERT (textSel); kpTextSelection *newSel = textSel->resized (m_newWidth, m_newHeight); document ()->setSelection (*newSel); delete newSel; environ ()->somethingBelowTheCursorChanged (); QApplication::restoreOverrideCursor (); } else { QApplication::setOverrideCursor (Qt::WaitCursor); if (m_newWidth < m_oldWidth) { m_oldRightImage = document ()->getImageAt ( QRect (m_newWidth, 0, m_oldWidth - m_newWidth, m_oldHeight)); } if (m_newHeight < m_oldHeight) { m_oldBottomImage = document ()->getImageAt ( QRect (0, m_newHeight, m_newWidth, m_oldHeight - m_newHeight)); } document ()->resize (m_newWidth, m_newHeight, m_backgroundColor); QApplication::restoreOverrideCursor (); } } // Scale else { QApplication::setOverrideCursor (Qt::WaitCursor); kpImage oldImage = document ()->image (m_actOnSelection); - if (!m_isLosslessScale) + if (!m_isLosslessScale) { m_oldImage = oldImage; + } kpImage newImage = kpPixmapFX::scale (oldImage, m_newWidth, m_newHeight, m_type == SmoothScale); if (!m_oldSelectionPtr && document ()->selection ()) { // Save sel border m_oldSelectionPtr = document ()->selection ()->clone (); m_oldSelectionPtr->deleteContent (); } if (m_actOnSelection) { - if (m_actOnTextSelection) + if (m_actOnTextSelection) { Q_ASSERT (!"kpTransformResizeScaleCommand::execute() scaling text sel doesn't make sense"); + } Q_ASSERT (m_oldSelectionPtr); - if ( !m_oldSelectionPtr ) // make coverity happy - return; + if ( !m_oldSelectionPtr ) { // make coverity happy + return; + } QRect newRect = QRect (m_oldSelectionPtr->x (), m_oldSelectionPtr->y (), newImage.width (), newImage.height ()); // Not possible to retain non-rectangular selection borders on scale // (think about e.g. a 45 deg line as part of the border & 2x scale) Q_ASSERT (dynamic_cast (m_oldSelectionPtr)); document ()->setSelection ( kpRectangularImageSelection (newRect, newImage, - static_cast (m_oldSelectionPtr) + dynamic_cast (m_oldSelectionPtr) ->transparency ())); environ ()->somethingBelowTheCursorChanged (); } else { document ()->setImage (newImage); if (m_scaleSelectionWithImage) { scaleSelectionRegionWithDocument (); } } QApplication::restoreOverrideCursor (); } } // public virtual [base kpCommand] void kpTransformResizeScaleCommand::unexecute () { qCDebug(kpLogCommands) << "kpTransformResizeScaleCommand::unexecute() type=" - << m_type << endl; + << m_type; - if (m_oldWidth == m_newWidth && m_oldHeight == m_newHeight) + if (m_oldWidth == m_newWidth && m_oldHeight == m_newHeight) { return; + } kpDocument *doc = document (); Q_ASSERT (doc); if (m_type == Resize) { if (m_actOnSelection) { - if (!m_actOnTextSelection) + if (!m_actOnTextSelection) { Q_ASSERT (!"kpTransformResizeScaleCommand::unexecute() resizing sel doesn't make sense"); + } QApplication::setOverrideCursor (Qt::WaitCursor); kpTextSelection *textSel = textSelection (); Q_ASSERT (textSel); kpTextSelection *newSel = textSel->resized (m_oldWidth, m_oldHeight); document ()->setSelection (*newSel); delete newSel; environ ()->somethingBelowTheCursorChanged (); QApplication::restoreOverrideCursor (); } else { QApplication::setOverrideCursor (Qt::WaitCursor); kpImage newImage (m_oldWidth, m_oldHeight, QImage::Format_ARGB32_Premultiplied); kpPixmapFX::setPixmapAt (&newImage, QPoint (0, 0), doc->image ()); if (m_newWidth < m_oldWidth) { kpPixmapFX::setPixmapAt (&newImage, QPoint (m_newWidth, 0), m_oldRightImage); } if (m_newHeight < m_oldHeight) { kpPixmapFX::setPixmapAt (&newImage, QPoint (0, m_newHeight), m_oldBottomImage); } doc->setImage (newImage); QApplication::restoreOverrideCursor (); } } // Scale else { QApplication::setOverrideCursor (Qt::WaitCursor); kpImage oldImage; - if (!m_isLosslessScale) + if (!m_isLosslessScale) { oldImage = m_oldImage; - else + } else { oldImage = kpPixmapFX::scale (doc->image (m_actOnSelection), m_oldWidth, m_oldHeight); + } if (m_actOnSelection) { - if (m_actOnTextSelection) + if (m_actOnTextSelection) { Q_ASSERT (!"kpTransformResizeScaleCommand::unexecute() scaling text sel doesn't make sense"); + } Q_ASSERT (dynamic_cast (m_oldSelectionPtr)); - kpAbstractImageSelection *oldImageSel = - static_cast (m_oldSelectionPtr); + auto *oldImageSel = dynamic_cast (m_oldSelectionPtr); kpAbstractImageSelection *oldSelection = oldImageSel->clone (); oldSelection->setBaseImage (oldImage); doc->setSelection (*oldSelection); delete oldSelection; environ ()->somethingBelowTheCursorChanged (); } else { doc->setImage (oldImage); if (m_scaleSelectionWithImage) { doc->setSelection (*m_oldSelectionPtr); environ ()->somethingBelowTheCursorChanged (); } } QApplication::restoreOverrideCursor (); } } diff --git a/commands/imagelib/transforms/kpTransformRotateCommand.cpp b/commands/imagelib/transforms/kpTransformRotateCommand.cpp index f9acf352..28e62588 100644 --- a/commands/imagelib/transforms/kpTransformRotateCommand.cpp +++ b/commands/imagelib/transforms/kpTransformRotateCommand.cpp @@ -1,223 +1,220 @@ /* Copyright (c) 2003-2007 Clarence Dang All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #define DEBUG_KP_TOOL_ROTATE 0 #include "kpTransformRotateCommand.h" #include "layers/selections/image/kpAbstractImageSelection.h" #include "environments/commands/kpCommandEnvironment.h" #include "kpDefs.h" #include "document/kpDocument.h" #include "layers/selections/image/kpFreeFormImageSelection.h" #include "pixmapfx/kpPixmapFX.h" #include "layers/selections/image/kpRectangularImageSelection.h" #include "views/manager/kpViewManager.h" #include "kpLogCategories.h" #include #include #include #include //-------------------------------------------------------------------------------- kpTransformRotateCommand::kpTransformRotateCommand (bool actOnSelection, double angle, kpCommandEnvironment *environ) : kpCommand (environ), m_actOnSelection (actOnSelection), m_angle (angle), m_backgroundColor (environ->backgroundColor (actOnSelection)), m_losslessRotation (kpPixmapFX::isLosslessRotation (angle)), m_oldSelectionPtr (nullptr) { } kpTransformRotateCommand::~kpTransformRotateCommand () { delete m_oldSelectionPtr; } // public virtual [base kpCommand] QString kpTransformRotateCommand::name () const { QString opName = i18n ("Rotate"); - if (m_actOnSelection) - return i18n ("Selection: %1", opName); - else - return opName; + return (m_actOnSelection) ? i18n ("Selection: %1", opName) : opName; } // public virtual [base kpCommand] kpCommandSize::SizeType kpTransformRotateCommand::size () const { return ImageSize (m_oldImage) + SelectionSize (m_oldSelectionPtr); } // public virtual [base kpCommand] void kpTransformRotateCommand::execute () { kpDocument *doc = document (); Q_ASSERT (doc); QApplication::setOverrideCursor (Qt::WaitCursor); - if (!m_losslessRotation) + if (!m_losslessRotation) { m_oldImage = doc->image (m_actOnSelection); + } kpImage newImage = kpPixmapFX::rotate (doc->image (m_actOnSelection), m_angle, m_backgroundColor); - if (!m_actOnSelection) + if (!m_actOnSelection) { doc->setImage (newImage); - else - { + } + else { kpAbstractImageSelection *sel = doc->imageSelection (); Q_ASSERT (sel); // Save old selection m_oldSelectionPtr = sel->clone (); // Conserve memmory: // // 1. If it's a lossless rotation, we don't need to the store old // image anywhere at all, as we can reconstruct it by rotating in // reverse. // 2. If it's not a lossless rotation, "m_oldImage" already holds // a copy of the old image. In this case, we actually save very // little with this line (just, the computed transparency mask) since // kpImage is copy-on-write. m_oldSelectionPtr->setBaseImage (kpImage ()); // Calculate new top left (so selection rotates about center) // (the Times2 trickery is used to reduce integer division error without // resorting to the troublesome world of floating point) QPoint oldCenterTimes2 (sel->x () * 2 + sel->width (), sel->y () * 2 + sel->height ()); QPoint newTopLeftTimes2 (oldCenterTimes2 - QPoint (newImage.width (), newImage.height ())); QPoint newTopLeft (newTopLeftTimes2.x () / 2, newTopLeftTimes2.y () / 2); // Calculate rotated points QPolygon currentPoints = sel->calculatePoints (); currentPoints.translate (-currentPoints.boundingRect ().x (), -currentPoints.boundingRect ().y ()); QTransform rotateMatrix = kpPixmapFX::rotateMatrix (doc->image (m_actOnSelection), m_angle); currentPoints = rotateMatrix.map (currentPoints); currentPoints.translate (-currentPoints.boundingRect ().x () + newTopLeft.x (), -currentPoints.boundingRect ().y () + newTopLeft.y ()); if (currentPoints.boundingRect ().width () == newImage.width () && currentPoints.boundingRect ().height () == newImage.height ()) { doc->setSelection ( kpFreeFormImageSelection ( currentPoints, newImage, m_oldSelectionPtr->transparency ())); } else { // TODO: fix the latter "victim of" problem in kpAbstractImageSelection by // allowing the border width & height != pixmap width & height // Or maybe autocrop? #if DEBUG_KP_TOOL_ROTATE qCDebug(kpLogCommands) << "kpTransformRotateCommand::execute() currentPoints.boundingRect=" << currentPoints.boundingRect () << " newPixmap: w=" << newImage.width () << " h=" << newImage.height () - << " (victim of rounding error and/or rotated-a-(rectangular)-pixmap-that-was-transparent-in-the-corners-making-sel-uselessly-bigger-than-needs-be)" - << endl; + << " (victim of rounding error and/or rotated-a-(rectangular)-pixmap-that-was-transparent-in-the-corners-making-sel-uselessly-bigger-than-needs-be)"; #endif doc->setSelection ( kpRectangularImageSelection ( QRect (newTopLeft.x (), newTopLeft.y (), newImage.width (), newImage.height ()), newImage, m_oldSelectionPtr->transparency ())); } environ ()->somethingBelowTheCursorChanged (); } QApplication::restoreOverrideCursor (); } // public virtual [base kpCommand] void kpTransformRotateCommand::unexecute () { kpDocument *doc = document (); Q_ASSERT (doc); QApplication::setOverrideCursor (Qt::WaitCursor); kpImage oldImage; if (!m_losslessRotation) { oldImage = m_oldImage; m_oldImage = kpImage (); } else { oldImage = kpPixmapFX::rotate (doc->image (m_actOnSelection), 360 - m_angle, m_backgroundColor); } - if (!m_actOnSelection) + if (!m_actOnSelection) { doc->setImage (oldImage); - else - { + } + else { m_oldSelectionPtr->setBaseImage (oldImage); doc->setSelection (*m_oldSelectionPtr); delete m_oldSelectionPtr; m_oldSelectionPtr = nullptr; environ ()->somethingBelowTheCursorChanged (); } QApplication::restoreOverrideCursor (); } diff --git a/commands/imagelib/transforms/kpTransformSkewCommand.cpp b/commands/imagelib/transforms/kpTransformSkewCommand.cpp index e2b727f6..e8aeb337 100644 --- a/commands/imagelib/transforms/kpTransformSkewCommand.cpp +++ b/commands/imagelib/transforms/kpTransformSkewCommand.cpp @@ -1,199 +1,195 @@ /* Copyright (c) 2003-2007 Clarence Dang All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #define DEBUG_KP_TOOL_SKEW 0 #define DEBUG_KP_TOOL_SKEW_DIALOG 0 #include "kpTransformSkewCommand.h" #include "layers/selections/image/kpAbstractImageSelection.h" #include "environments/commands/kpCommandEnvironment.h" #include "kpDefs.h" #include "document/kpDocument.h" #include "layers/selections/image/kpFreeFormImageSelection.h" #include "pixmapfx/kpPixmapFX.h" #include "layers/selections/image/kpRectangularImageSelection.h" #include "kpLogCategories.h" #include #include #include // TODO: nasty, should avoid using GUI class in this command class #include "dialogs/imagelib/transforms/kpTransformSkewDialog.h" #include //-------------------------------------------------------------------------------- kpTransformSkewCommand::kpTransformSkewCommand (bool actOnSelection, int hangle, int vangle, kpCommandEnvironment *environ) : kpCommand (environ), m_actOnSelection (actOnSelection), m_hangle (hangle), m_vangle (vangle), m_backgroundColor (environ->backgroundColor (actOnSelection)), m_oldSelectionPtr (nullptr) { } kpTransformSkewCommand::~kpTransformSkewCommand () { delete m_oldSelectionPtr; } // public virtual [base kpCommand] QString kpTransformSkewCommand::name () const { QString opName = i18n ("Skew"); - if (m_actOnSelection) - return i18n ("Selection: %1", opName); - else - return opName; + return (m_actOnSelection) ? i18n ("Selection: %1", opName) : opName; } // public virtual [base kpCommand] kpCommandSize::SizeType kpTransformSkewCommand::size () const { return ImageSize (m_oldImage) + SelectionSize (m_oldSelectionPtr); } // public virtual [base kpCommand] void kpTransformSkewCommand::execute () { kpDocument *doc = document (); Q_ASSERT (doc); QApplication::setOverrideCursor (Qt::WaitCursor); kpImage newImage = kpPixmapFX::skew (doc->image (m_actOnSelection), kpTransformSkewDialog::horizontalAngleForPixmapFX (m_hangle), kpTransformSkewDialog::verticalAngleForPixmapFX (m_vangle), m_backgroundColor); if (!m_actOnSelection) { m_oldImage = doc->image (m_actOnSelection); doc->setImage (newImage); } else { kpAbstractImageSelection *sel = doc->imageSelection (); Q_ASSERT (sel); // Save old selection m_oldSelectionPtr = sel->clone (); // Calculate skewed points QPolygon currentPoints = sel->calculatePoints (); currentPoints.translate (-currentPoints.boundingRect ().x (), -currentPoints.boundingRect ().y ()); QTransform skewMatrix = kpPixmapFX::skewMatrix ( doc->image (m_actOnSelection), kpTransformSkewDialog::horizontalAngleForPixmapFX (m_hangle), kpTransformSkewDialog::verticalAngleForPixmapFX (m_vangle)); currentPoints = skewMatrix.map (currentPoints); currentPoints.translate (-currentPoints.boundingRect ().x () + m_oldSelectionPtr->x (), -currentPoints.boundingRect ().y () + m_oldSelectionPtr->y ()); if (currentPoints.boundingRect ().width () == newImage.width () && currentPoints.boundingRect ().height () == newImage.height ()) { doc->setSelection ( kpFreeFormImageSelection ( currentPoints, newImage, m_oldSelectionPtr->transparency ())); } else { // TODO: fix the latter "victim of" problem in kpAbstractImageSelection by // allowing the border width & height != pixmap width & height // Or maybe autocrop? #if DEBUG_KP_TOOL_SKEW qCDebug(kpLogCommands) << "kpTransformSkewCommand::execute() currentPoints.boundingRect=" << currentPoints.boundingRect () << " newPixmap: w=" << newImage.width () << " h=" << newImage.height () - << " (victim of rounding error and/or skewed-a-(rectangular)-pixmap-that-was-transparent-in-the-corners-making-sel-uselessly-bigger-than-needs-be))" - << endl; + << " (victim of rounding error and/or skewed-a-(rectangular)-pixmap-that-was-transparent-in-the-corners-making-sel-uselessly-bigger-than-needs-be))"; #endif doc->setSelection ( kpRectangularImageSelection ( QRect (currentPoints.boundingRect ().x (), currentPoints.boundingRect ().y (), newImage.width (), newImage.height ()), newImage, m_oldSelectionPtr->transparency ())); } environ ()->somethingBelowTheCursorChanged (); } QApplication::restoreOverrideCursor (); } // public virtual [base kpCommand] void kpTransformSkewCommand::unexecute () { kpDocument *doc = document (); Q_ASSERT (doc); QApplication::setOverrideCursor (Qt::WaitCursor); if (!m_actOnSelection) { doc->setImage (m_oldImage); m_oldImage = kpImage (); } else { doc->setSelection (*m_oldSelectionPtr); delete m_oldSelectionPtr; m_oldSelectionPtr = nullptr; environ ()->somethingBelowTheCursorChanged (); } QApplication::restoreOverrideCursor (); } diff --git a/commands/kpCommand.cpp b/commands/kpCommand.cpp index ec4de7bc..55e3e7c0 100644 --- a/commands/kpCommand.cpp +++ b/commands/kpCommand.cpp @@ -1,85 +1,83 @@ /* Copyright (c) 2003-2007 Clarence Dang All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #define DEBUG_KP_COMMAND_HISTORY 0 #include "kpCommand.h" #include "environments/commands/kpCommandEnvironment.h" kpCommand::kpCommand (kpCommandEnvironment *environ) : m_environ (environ) { Q_ASSERT (environ); } -kpCommand::~kpCommand () -{ -} +kpCommand::~kpCommand () = default; kpCommandEnvironment *kpCommand::environ () const { return m_environ; } // protected kpDocument *kpCommand::document () const { return m_environ->document (); } // protected kpAbstractSelection *kpCommand::selection () const { return m_environ->selection (); } // protected kpAbstractImageSelection *kpCommand::imageSelection () const { return m_environ->imageSelection (); } // protected kpTextSelection *kpCommand::textSelection () const { return m_environ->textSelection (); } // protected kpViewManager *kpCommand::viewManager () const { return m_environ->viewManager (); } diff --git a/commands/kpCommandHistory.cpp b/commands/kpCommandHistory.cpp index a3cd3412..4a6d29be 100644 --- a/commands/kpCommandHistory.cpp +++ b/commands/kpCommandHistory.cpp @@ -1,124 +1,128 @@ /* Copyright (c) 2003-2007 Clarence Dang All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #define DEBUG_KP_COMMAND_HISTORY 0 #include "kpCommandHistory.h" #include "layers/selections/kpAbstractSelection.h" #include "mainWindow/kpMainWindow.h" #include "tools/kpTool.h" #include "commands/tools/selection/kpToolSelectionCreateCommand.h" #include "kpLogCategories.h" kpCommandHistory::kpCommandHistory (bool doReadConfig, kpMainWindow *mainWindow) : kpCommandHistoryBase (doReadConfig, mainWindow->actionCollection ()), m_mainWindow (mainWindow) { } -kpCommandHistory::~kpCommandHistory () -{ -} +kpCommandHistory::~kpCommandHistory () = default; static bool NextUndoCommandIsCreateBorder (kpCommandHistory *commandHistory) { Q_ASSERT (commandHistory); kpCommand *cmd = commandHistory->nextUndoCommand (); - if (!cmd) + if (!cmd) { return false; + } - kpToolSelectionCreateCommand *c = dynamic_cast (cmd); - if (!c) + auto *c = dynamic_cast (cmd); + if (!c) { return false; + } const kpAbstractSelection *sel = c->fromSelection (); Q_ASSERT (sel); return (!sel->hasContent ()); } // public void kpCommandHistory::addCreateSelectionCommand (kpToolSelectionCreateCommand *cmd, bool execute) { if (cmd->fromSelection ()->hasContent ()) { addCommand (cmd, execute); return; } if (::NextUndoCommandIsCreateBorder (this)) { setNextUndoCommand (cmd); - if (execute) + if (execute) { cmd->execute (); + } } - else + else { addCommand (cmd, execute); + } } //--------------------------------------------------------------------- // public slot virtual [base KCommandHistory] void kpCommandHistory::undo () { qCDebug(kpLogCommands) << "kpCommandHistory::undo() CALLED!"; if (m_mainWindow && m_mainWindow->toolHasBegunShape ()) { qCDebug(kpLogCommands) << "\thas begun shape - cancel draw"; m_mainWindow->tool ()->cancelShapeInternal (); } - else + else { kpCommandHistoryBase::undo (); + } } //--------------------------------------------------------------------- // public slot virtual [base KCommandHistory] void kpCommandHistory::redo () { if (m_mainWindow && m_mainWindow->toolHasBegunShape ()) { // Not completely obvious but what else can we do? // // Ignoring the request would not be intuitive for tools like // Polygon & Polyline (where it's not always apparent to the user // that s/he's still drawing a shape even though the mouse isn't // down). m_mainWindow->tool ()->cancelShapeInternal (); } - else + else { kpCommandHistoryBase::redo (); + } } diff --git a/commands/kpCommandHistoryBase.cpp b/commands/kpCommandHistoryBase.cpp index ee6b0992..61e1f219 100644 --- a/commands/kpCommandHistoryBase.cpp +++ b/commands/kpCommandHistoryBase.cpp @@ -1,674 +1,654 @@ /* Copyright (c) 2003-2007 Clarence Dang All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #define DEBUG_KP_COMMAND_HISTORY 0 #include "kpCommandHistoryBase.h" #include #include #include #include #include #include #include #include #include #include #include #include "kpCommand.h" #include "kpLogCategories.h" #include "environments/commands/kpCommandEnvironment.h" #include "kpDefs.h" #include "document/kpDocument.h" #include "mainWindow/kpMainWindow.h" #include "tools/kpTool.h" //--------------------------------------------------------------------- //template static void ClearPointerList (QLinkedList *listPtr) { if (!listPtr) return; qDeleteAll (listPtr->begin (), listPtr->end ()); listPtr->clear (); } struct kpCommandHistoryBasePrivate { }; kpCommandHistoryBase::kpCommandHistoryBase (bool doReadConfig, KActionCollection *ac) : d (new kpCommandHistoryBasePrivate ()) { m_actionUndo = new KToolBarPopupAction(KDE::icon("edit-undo"), undoActionText (), this); ac->addAction (KStandardAction::name (KStandardAction::Undo), m_actionUndo); ac->setDefaultShortcuts (m_actionUndo, KStandardShortcut::shortcut (KStandardShortcut::Undo)); connect (m_actionUndo, &KToolBarPopupAction::triggered, this, &kpCommandHistoryBase::undo); m_actionRedo = new KToolBarPopupAction(KDE::icon("edit-redo"), redoActionText (), this); ac->addAction (KStandardAction::name (KStandardAction::Redo), m_actionRedo); ac->setDefaultShortcuts (m_actionRedo, KStandardShortcut::shortcut (KStandardShortcut::Redo)); connect (m_actionRedo, &KToolBarPopupAction::triggered, this, &kpCommandHistoryBase::redo ); m_actionUndo->setEnabled (false); m_actionRedo->setEnabled (false); connect (m_actionUndo->menu(), &QMenu::triggered, this, &kpCommandHistoryBase::undoUpToNumber); connect (m_actionRedo->menu(), &QMenu::triggered, this, &kpCommandHistoryBase::redoUpToNumber); m_undoMinLimit = 10; m_undoMaxLimit = 500; m_undoMaxLimitSizeLimit = 16 * 1048576; m_documentRestoredPosition = 0; - if (doReadConfig) + if (doReadConfig) { readConfig (); + } } kpCommandHistoryBase::~kpCommandHistoryBase () { ::ClearPointerList (&m_undoCommandList); ::ClearPointerList (&m_redoCommandList); delete d; } // public int kpCommandHistoryBase::undoLimit () const { return undoMinLimit (); } // public void kpCommandHistoryBase::setUndoLimit (int limit) { setUndoMinLimit (limit); } // public int kpCommandHistoryBase::undoMinLimit () const { return m_undoMinLimit; } // public void kpCommandHistoryBase::setUndoMinLimit (int limit) { qCDebug(kpLogCommands) << "kpCommandHistoryBase::setUndoMinLimit(" - << limit << ")" - << endl; + << limit << ")"; if (limit < 1 || limit > 5000/*"ought to be enough for anybody"*/) { qCCritical(kpLogCommands) << "kpCommandHistoryBase::setUndoMinLimit(" - << limit << ")" - << endl; + << limit << ")"; return; } - if (limit == m_undoMinLimit) + if (limit == m_undoMinLimit) { return; + } m_undoMinLimit = limit; trimCommandListsUpdateActions (); } // public int kpCommandHistoryBase::undoMaxLimit () const { return m_undoMaxLimit; } // public void kpCommandHistoryBase::setUndoMaxLimit (int limit) { qCDebug(kpLogCommands) << "kpCommandHistoryBase::setUndoMaxLimit(" - << limit << ")" - << endl; + << limit << ")"; if (limit < 1 || limit > 5000/*"ought to be enough for anybody"*/) { qCCritical(kpLogCommands) << "kpCommandHistoryBase::setUndoMaxLimit(" - << limit << ")" - << endl; + << limit << ")"; return; } - if (limit == m_undoMaxLimit) + if (limit == m_undoMaxLimit) { return; + } m_undoMaxLimit = limit; trimCommandListsUpdateActions (); } // public kpCommandSize::SizeType kpCommandHistoryBase::undoMaxLimitSizeLimit () const { return m_undoMaxLimitSizeLimit; } // public void kpCommandHistoryBase::setUndoMaxLimitSizeLimit (kpCommandSize::SizeType sizeLimit) { qCDebug(kpLogCommands) << "kpCommandHistoryBase::setUndoMaxLimitSizeLimit(" - << sizeLimit << ")" - << endl; + << sizeLimit << ")"; if (sizeLimit < 0 || sizeLimit > (500 * 1048576)/*"ought to be enough for anybody"*/) { qCCritical(kpLogCommands) << "kpCommandHistoryBase::setUndoMaxLimitSizeLimit(" - << sizeLimit << ")" - << endl; + << sizeLimit << ")"; return; } - if (sizeLimit == m_undoMaxLimitSizeLimit) + if (sizeLimit == m_undoMaxLimitSizeLimit) { return; + } m_undoMaxLimitSizeLimit = sizeLimit; trimCommandListsUpdateActions (); } // public void kpCommandHistoryBase::readConfig () { qCDebug(kpLogCommands) << "kpCommandHistoryBase::readConfig()"; KConfigGroup cfg (KSharedConfig::openConfig (), kpSettingsGroupUndoRedo); setUndoMinLimit (cfg.readEntry (kpSettingUndoMinLimit, undoMinLimit ())); setUndoMaxLimit (cfg.readEntry (kpSettingUndoMaxLimit, undoMaxLimit ())); setUndoMaxLimitSizeLimit ( cfg.readEntry (kpSettingUndoMaxLimitSizeLimit, undoMaxLimitSizeLimit ())); trimCommandListsUpdateActions (); } // public void kpCommandHistoryBase::writeConfig () { qCDebug(kpLogCommands) << "kpCommandHistoryBase::writeConfig()"; KConfigGroup cfg (KSharedConfig::openConfig (), kpSettingsGroupUndoRedo); cfg.writeEntry (kpSettingUndoMinLimit, undoMinLimit ()); cfg.writeEntry (kpSettingUndoMaxLimit, undoMaxLimit ()); cfg.writeEntry ( kpSettingUndoMaxLimitSizeLimit, undoMaxLimitSizeLimit ()); cfg.sync (); } // public void kpCommandHistoryBase::addCommand (kpCommand *command, bool execute) { qCDebug(kpLogCommands) << "kpCommandHistoryBase::addCommand(" << command - << ",execute=" << execute << ")" - << endl; + << ",execute=" << execute << ")"; - if (execute) + if (execute) { command->execute (); + } m_undoCommandList.push_front (command); ::ClearPointerList (&m_redoCommandList); - qCDebug(kpLogCommands) << "\tdocumentRestoredPosition=" << m_documentRestoredPosition - << endl; + qCDebug(kpLogCommands) << "\tdocumentRestoredPosition=" << m_documentRestoredPosition; if (m_documentRestoredPosition != INT_MAX) { - if (m_documentRestoredPosition > 0) + if (m_documentRestoredPosition > 0) { m_documentRestoredPosition = INT_MAX; - else + } + else { m_documentRestoredPosition--; - qCDebug(kpLogCommands) << "\t\tdocumentRestoredPosition=" << m_documentRestoredPosition - << endl; + } + qCDebug(kpLogCommands) << "\t\tdocumentRestoredPosition=" << m_documentRestoredPosition; } trimCommandListsUpdateActions (); } // public void kpCommandHistoryBase::clear () { qCDebug(kpLogCommands) << "kpCommandHistoryBase::clear()"; ::ClearPointerList (&m_undoCommandList); ::ClearPointerList (&m_redoCommandList); m_documentRestoredPosition = 0; updateActions (); } //--------------------------------------------------------------------- // protected slot void kpCommandHistoryBase::undoInternal () { qCDebug(kpLogCommands) << "kpCommandHistoryBase::undoInternal()"; kpCommand *undoCommand = nextUndoCommand (); - if (!undoCommand) + if (!undoCommand) { return; + } undoCommand->unexecute (); m_undoCommandList.erase (m_undoCommandList.begin ()); m_redoCommandList.push_front (undoCommand); - qCDebug(kpLogCommands) << "\tdocumentRestoredPosition=" << m_documentRestoredPosition - << endl; + qCDebug(kpLogCommands) << "\tdocumentRestoredPosition=" << m_documentRestoredPosition; if (m_documentRestoredPosition != INT_MAX) { m_documentRestoredPosition++; if (m_documentRestoredPosition == 0) emit documentRestored (); - qCDebug(kpLogCommands) << "\t\tdocumentRestoredPosition=" << m_documentRestoredPosition - << endl; + qCDebug(kpLogCommands) << "\t\tdocumentRestoredPosition=" << m_documentRestoredPosition; } } //--------------------------------------------------------------------- // protected slot void kpCommandHistoryBase::redoInternal () { qCDebug(kpLogCommands) << "kpCommandHistoryBase::redoInternal()"; kpCommand *redoCommand = nextRedoCommand (); - if (!redoCommand) + if (!redoCommand) { return; + } redoCommand->execute (); m_redoCommandList.erase (m_redoCommandList.begin ()); m_undoCommandList.push_front (redoCommand); - qCDebug(kpLogCommands) << "\tdocumentRestoredPosition=" << m_documentRestoredPosition - << endl; + qCDebug(kpLogCommands) << "\tdocumentRestoredPosition=" << m_documentRestoredPosition; if (m_documentRestoredPosition != INT_MAX) { m_documentRestoredPosition--; - if (m_documentRestoredPosition == 0) + if (m_documentRestoredPosition == 0) { emit documentRestored (); - qCDebug(kpLogCommands) << "\t\tdocumentRestoredPosition=" << m_documentRestoredPosition - << endl; + } + qCDebug(kpLogCommands) << "\t\tdocumentRestoredPosition=" << m_documentRestoredPosition; } } //--------------------------------------------------------------------- // public slot virtual void kpCommandHistoryBase::undo () { qCDebug(kpLogCommands) << "kpCommandHistoryBase::undo()"; undoInternal (); trimCommandListsUpdateActions (); } //--------------------------------------------------------------------- // public slot virtual void kpCommandHistoryBase::redo () { qCDebug(kpLogCommands) << "kpCommandHistoryBase::redo()"; redoInternal (); trimCommandListsUpdateActions (); } //--------------------------------------------------------------------- // public slot virtual void kpCommandHistoryBase::undoUpToNumber (QAction *which) { qCDebug(kpLogCommands) << "kpCommandHistoryBase::undoUpToNumber(" << which << ")"; for (int i = 0; i <= which->data().toInt() && !m_undoCommandList.isEmpty (); i++) { undoInternal (); } trimCommandListsUpdateActions (); } // public slot virtual void kpCommandHistoryBase::redoUpToNumber (QAction *which) { qCDebug(kpLogCommands) << "kpCommandHistoryBase::redoUpToNumber(" << which << ")"; for (int i = 0; i <= which->data().toInt() && !m_redoCommandList.isEmpty (); i++) { redoInternal (); } trimCommandListsUpdateActions (); } // protected QString kpCommandHistoryBase::undoActionText () const { kpCommand *undoCommand = nextUndoCommand (); - if (undoCommand) - return i18n ("&Undo: %1", undoCommand->name ()); - else - return i18n ("&Undo"); + return (undoCommand) ? i18n ("&Undo: %1", undoCommand->name ()) : i18n ("&Undo"); } // protected QString kpCommandHistoryBase::redoActionText () const { kpCommand *redoCommand = nextRedoCommand (); - if (redoCommand) - return i18n ("&Redo: %1", redoCommand->name ()); - else - return i18n ("&Redo"); + return (redoCommand) ? i18n ("&Redo: %1", redoCommand->name ()) : i18n ("&Redo"); } // protected QString kpCommandHistoryBase::undoActionToolTip () const { kpCommand *undoCommand = nextUndoCommand (); - if (undoCommand) - return i18n ("Undo: %1", undoCommand->name ()); - else - return i18n ("Undo"); + return (undoCommand) ? i18n ("Undo: %1", undoCommand->name ()) : i18n ("Undo"); } // protected QString kpCommandHistoryBase::redoActionToolTip () const { kpCommand *redoCommand = nextRedoCommand (); - if (redoCommand) - return i18n ("Redo: %1", redoCommand->name ()); - else - return i18n ("Redo"); + return (redoCommand) ? i18n ("Redo: %1", redoCommand->name ()) : i18n ("Redo"); } // protected void kpCommandHistoryBase::trimCommandListsUpdateActions () { qCDebug(kpLogCommands) << "kpCommandHistoryBase::trimCommandListsUpdateActions()"; trimCommandLists (); updateActions (); } // protected void kpCommandHistoryBase::trimCommandList (QLinkedList *commandList) { qCDebug(kpLogCommands) << "kpCommandHistoryBase::trimCommandList()"; QTime timer; timer.start (); if (!commandList) { - qCCritical(kpLogCommands) << "kpCommandHistoryBase::trimCommandList() passed 0 commandList" - << endl; + qCCritical(kpLogCommands) << "kpCommandHistoryBase::trimCommandList() passed 0 commandList"; return; } qCDebug(kpLogCommands) << "\tsize=" << commandList->size () << " undoMinLimit=" << m_undoMinLimit << " undoMaxLimit=" << m_undoMaxLimit - << " undoMaxLimitSizeLimit=" << m_undoMaxLimitSizeLimit - << endl; + << " undoMaxLimitSizeLimit=" << m_undoMaxLimitSizeLimit; if (static_cast (commandList->size ()) <= m_undoMinLimit) { qCDebug(kpLogCommands) << "\t\tsize under undoMinLimit - done"; return; } qCDebug(kpLogCommands) << "\tsize over undoMinLimit - iterating thru cmds:"; QLinkedList ::iterator it = commandList->begin (); int upto = 0; kpCommandSize::SizeType sizeSoFar = 0; while (it != commandList->end ()) { bool advanceIt = true; if (sizeSoFar <= m_undoMaxLimitSizeLimit) { sizeSoFar += (*it)->size (); } qCDebug(kpLogCommands) << "\t\t" << upto << ":" << " name='" << (*it)->name () << "' size=" << (*it)->size () - << " sizeSoFar=" << sizeSoFar - << endl; + << " sizeSoFar=" << sizeSoFar; if (upto >= m_undoMinLimit) { if (upto >= m_undoMaxLimit || sizeSoFar > m_undoMaxLimitSizeLimit) { #if DEBUG_KP_COMMAND_HISTORY && 0 qCDebug(kpLogCommands) << "\t\t\tkill"; #endif delete (*it); it = m_undoCommandList.erase (it); advanceIt = false; } } - if (advanceIt) + if (advanceIt) { it++; + } upto++; } qCDebug(kpLogCommands) << "\ttook " << timer.elapsed () << "ms"; } // protected void kpCommandHistoryBase::trimCommandLists () { qCDebug(kpLogCommands) << "kpCommandHistoryBase::trimCommandLists()"; trimCommandList (&m_undoCommandList); trimCommandList (&m_redoCommandList); - qCDebug(kpLogCommands) << "\tdocumentRestoredPosition=" << m_documentRestoredPosition - << endl; + qCDebug(kpLogCommands) << "\tdocumentRestoredPosition=" << m_documentRestoredPosition; if (m_documentRestoredPosition != INT_MAX) { qCDebug(kpLogCommands) << "\t\tundoCmdList.size=" << m_undoCommandList.size () - << " redoCmdList.size=" << m_redoCommandList.size () - << endl; + << " redoCmdList.size=" << m_redoCommandList.size (); if (m_documentRestoredPosition > static_cast (m_redoCommandList.size ()) || -m_documentRestoredPosition > static_cast (m_undoCommandList.size ())) { qCDebug(kpLogCommands) << "\t\t\tinvalidate documentRestoredPosition"; m_documentRestoredPosition = INT_MAX; } } } static void populatePopupMenu (QMenu *popupMenu, const QString &undoOrRedo, const QLinkedList &commandList) { - if (!popupMenu) + if (!popupMenu) { return; + } popupMenu->clear (); QLinkedList ::const_iterator it = commandList.begin (); int i = 0; while (i < 10 && it != commandList.end ()) { QAction *action = new QAction(i18n ("%1: %2", undoOrRedo, (*it)->name ()), popupMenu); action->setData(i); popupMenu->addAction (action); i++; it++; } if (it != commandList.end ()) { // TODO: maybe have a scrollview show all the items instead, like KOffice in KDE 3 // LOCOMPAT: should be centered text. popupMenu->addSection (i18np ("%1 more item", "%1 more items", commandList.size () - i)); } } // protected void kpCommandHistoryBase::updateActions () { qCDebug(kpLogCommands) << "kpCommandHistoryBase::updateActions()"; m_actionUndo->setEnabled (static_cast (nextUndoCommand ())); // Don't want to keep changing toolbar text. // TODO: As a bad side-effect, the menu doesn't have "Undo: " // anymore. In any case, the KDE4 KToolBarPopupAction // sucks in menus as it forces the clicking of a submenu. IMO, // there should be no submenu in the menu. //m_actionUndo->setText (undoActionText ()); // But in icon mode, a tooltip with context is useful. m_actionUndo->setToolTip (undoActionToolTip ()); QTime timer; timer.start (); populatePopupMenu (m_actionUndo->menu (), i18n ("Undo"), m_undoCommandList); qCDebug(kpLogCommands) << "\tpopuplatePopupMenu undo=" << timer.elapsed () - << "ms" << endl;; + << "ms"; m_actionRedo->setEnabled (static_cast (nextRedoCommand ())); // Don't want to keep changing toolbar text. // TODO: As a bad side-effect, the menu doesn't have "Undo: " // anymore. In any case, the KDE4 KToolBarPopupAction // sucks in menus as it forces the clicking of a submenu. IMO, // there should be no submenu in the menu. //m_actionRedo->setText (redoActionText ()); // But in icon mode, a tooltip with context is useful. m_actionRedo->setToolTip (redoActionToolTip ()); timer.restart (); populatePopupMenu (m_actionRedo->menu (), i18n ("Redo"), m_redoCommandList); qCDebug(kpLogCommands) << "\tpopuplatePopupMenu redo=" << timer.elapsed () - << "ms" << endl; + << "ms"; } // public kpCommand *kpCommandHistoryBase::nextUndoCommand () const { - if (m_undoCommandList.isEmpty ()) + if (m_undoCommandList.isEmpty ()) { return nullptr; + } return m_undoCommandList.first (); } // public kpCommand *kpCommandHistoryBase::nextRedoCommand () const { - if (m_redoCommandList.isEmpty ()) + if (m_redoCommandList.isEmpty ()) { return nullptr; + } return m_redoCommandList.first (); } // public void kpCommandHistoryBase::setNextUndoCommand (kpCommand *command) { - qCDebug(kpLogCommands) << "kpCommandHistoryBase::setNextUndoCommand(" - << command - << ")" - << endl; + qCDebug(kpLogCommands) << "kpCommandHistoryBase::setNextUndoCommand("<< command << ")"; - if (m_undoCommandList.isEmpty ()) + if (m_undoCommandList.isEmpty ()) { return; - + } delete *m_undoCommandList.begin (); *m_undoCommandList.begin () = command; - trimCommandListsUpdateActions (); } // public slot virtual void kpCommandHistoryBase::documentSaved () { qCDebug(kpLogCommands) << "kpCommandHistoryBase::documentSaved()"; m_documentRestoredPosition = 0; } diff --git a/commands/kpCommandSize.cpp b/commands/kpCommandSize.cpp index 866e0375..4a1bc542 100644 --- a/commands/kpCommandSize.cpp +++ b/commands/kpCommandSize.cpp @@ -1,149 +1,145 @@ /* Copyright (c) 2003-2007 Clarence Dang All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #define DEBUG_KP_COMMAND_SIZE 0 #include "commands/kpCommandSize.h" #include "layers/selections/kpAbstractSelection.h" #include "kpLogCategories.h" #include #include #include #include // public static kpCommandSize::SizeType kpCommandSize::PixmapSize (const QImage &image) { return kpCommandSize::PixmapSize (image.width (), image.height (), image.depth ()); } // public static kpCommandSize::SizeType kpCommandSize::PixmapSize (const QImage *image) { return (image ? kpCommandSize::PixmapSize (*image) : 0); } // public static kpCommandSize::SizeType kpCommandSize::PixmapSize (int width, int height, int depth) { // handle 15bpp int roundedDepth = (depth > 8 ? (depth + 7) / 8 * 8 : depth); kpCommandSize::SizeType ret = static_cast (width) * height * roundedDepth / 8; qCDebug(kpLogCommands) << "kpCommandSize::PixmapSize() w=" << width << " h=" << height << " d=" << depth << " roundedDepth=" << roundedDepth - << " ret=" << ret - << endl; + << " ret=" << ret; return ret; } // public static kpCommandSize::SizeType kpCommandSize::QImageSize (const QImage &image) { return kpCommandSize::QImageSize (image.width (), image.height (), image.depth ()); } // public static kpCommandSize::SizeType kpCommandSize::QImageSize (const QImage *image) { return (image ? kpCommandSize::QImageSize (*image) : 0); } // public static kpCommandSize::SizeType kpCommandSize::QImageSize (int width, int height, int depth) { // handle 15bpp int roundedDepth = (depth > 8 ? (depth + 7) / 8 * 8 : depth); kpCommandSize::SizeType ret = static_cast (width) * height * roundedDepth / 8; qCDebug(kpLogCommands) << "kpCommandSize::QImageSize() w=" << width << " h=" << height << " d=" << depth << " roundedDepth=" << roundedDepth - << " ret=" << ret - << endl; + << " ret=" << ret; return ret; } // public static kpCommandSize::SizeType kpCommandSize::ImageSize (const kpImage &image) { return kpCommandSize::PixmapSize (image); } // public static kpCommandSize::SizeType kpCommandSize::ImageSize (const kpImage *image) { return kpCommandSize::PixmapSize (image); } // public static kpCommandSize::SizeType kpCommandSize::SelectionSize (const kpAbstractSelection &sel) { return sel.size (); } // public static kpCommandSize::SizeType kpCommandSize::SelectionSize (const kpAbstractSelection *sel) { return (sel ? sel->size () : 0); } // public static kpCommandSize::SizeType kpCommandSize::StringSize (const QString &string) { qCDebug(kpLogCommands) << "kpCommandSize::StringSize(" << string << ")" << " len=" << string.length () - << " sizeof(QChar)=" << sizeof (QChar) - << endl; + << " sizeof(QChar)=" << sizeof (QChar); return static_cast (static_cast (string.length ()) * sizeof (QChar)); } // public static kpCommandSize::SizeType kpCommandSize::PolygonSize (const QPolygon &points) { qCDebug(kpLogCommands) << "kpCommandSize::PolygonSize() points.size=" << points.size () - << " sizeof(QPoint)=" << sizeof (QPoint) - << endl; + << " sizeof(QPoint)=" << sizeof (QPoint); return static_cast (static_cast (points.size ()) * sizeof (QPoint)); } diff --git a/commands/kpMacroCommand.cpp b/commands/kpMacroCommand.cpp index 6c8244d1..26294dbc 100644 --- a/commands/kpMacroCommand.cpp +++ b/commands/kpMacroCommand.cpp @@ -1,133 +1,132 @@ /* Copyright (c) 2003-2007 Clarence Dang All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #define DEBUG_KP_COMMAND_HISTORY 0 #include "commands/kpMacroCommand.h" #include "views/manager/kpViewManager.h" #include #include #include "kpLogCategories.h" //--------------------------------------------------------------------- struct kpMacroCommandPrivate { }; kpMacroCommand::kpMacroCommand (const QString &name, kpCommandEnvironment *environ) : kpNamedCommand (name, environ), d (new kpMacroCommandPrivate ()) { } //--------------------------------------------------------------------- kpMacroCommand::~kpMacroCommand () { qDeleteAll (m_commandList.begin (), m_commandList.end ()); delete d; } //--------------------------------------------------------------------- // public virtual [base kpCommand] kpCommandSize::SizeType kpMacroCommand::size () const { qCDebug(kpLogCommands) << "kpMacroCommand::size()"; SizeType s = 0; qCDebug(kpLogCommands) << "\tcalculating:"; - foreach (kpCommand *cmd, m_commandList) + for (auto *cmd : m_commandList) { qCDebug(kpLogCommands) << "\t\tcurrentSize=" << s << " + " - << cmd->name () << ".size=" << cmd->size () - << endl; + << cmd->name () << ".size=" << cmd->size (); s += cmd->size (); } qCDebug(kpLogCommands) << "\treturning " << s; return s; } //--------------------------------------------------------------------- // public virtual [base kpCommand] void kpMacroCommand::execute () { qCDebug(kpLogCommands) << "kpMacroCommand::execute()"; viewManager()->setQueueUpdates(); for (QLinkedList ::const_iterator it = m_commandList.begin (); it != m_commandList.end (); ++it) { qCDebug(kpLogCommands) << "\texecuting " << (*it)->name (); (*it)->execute (); } viewManager()->restoreQueueUpdates(); } //--------------------------------------------------------------------- // public virtual [base kpCommand] void kpMacroCommand::unexecute () { qCDebug(kpLogCommands) << "kpMacroCommand::unexecute()"; viewManager()->setQueueUpdates(); QLinkedList ::const_iterator it = m_commandList.end (); it--; while (it != m_commandList.end ()) { qCDebug(kpLogCommands) << "\tunexecuting " << (*it)->name (); (*it)->unexecute (); it--; } viewManager()->restoreQueueUpdates(); } //--------------------------------------------------------------------- // public void kpMacroCommand::addCommand (kpCommand *command) { m_commandList.push_back (command); } //--------------------------------------------------------------------- diff --git a/commands/tools/flow/kpToolFlowCommand.cpp b/commands/tools/flow/kpToolFlowCommand.cpp index 138d60a3..9548d159 100644 --- a/commands/tools/flow/kpToolFlowCommand.cpp +++ b/commands/tools/flow/kpToolFlowCommand.cpp @@ -1,138 +1,137 @@ /* Copyright (c) 2003-2007 Clarence Dang All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #define DEBUG_KP_TOOL_FLOW_COMMAND 0 #include "kpToolFlowCommand.h" #include "document/kpDocument.h" #include "imagelib/kpImage.h" #include "pixmapfx/kpPixmapFX.h" #include "tools/kpTool.h" #include "views/manager/kpViewManager.h" #include "kpLogCategories.h" #include struct kpToolFlowCommandPrivate { kpImage image; QRect boundingRect; }; kpToolFlowCommand::kpToolFlowCommand (const QString &name, kpCommandEnvironment *environ) : kpNamedCommand (name, environ), d (new kpToolFlowCommandPrivate ()) { d->image = document ()->image (); } kpToolFlowCommand::~kpToolFlowCommand () { delete d; } // public virtual [base kpCommand] kpCommandSize::SizeType kpToolFlowCommand::size () const { return ImageSize (d->image); } // public virtual [base kpCommand] void kpToolFlowCommand::execute () { swapOldAndNew (); } // public virtual [base kpCommand] void kpToolFlowCommand::unexecute () { swapOldAndNew (); } // private void kpToolFlowCommand::swapOldAndNew () { if (d->boundingRect.isValid ()) { const kpImage oldImage = document ()->getImageAt (d->boundingRect); document ()->setImageAt (d->image, d->boundingRect.topLeft ()); d->image = oldImage; } } // public void kpToolFlowCommand::updateBoundingRect (const QPoint &point) { updateBoundingRect (QRect (point, point)); } // public void kpToolFlowCommand::updateBoundingRect (const QRect &rect) { qCDebug(kpLogCommands) << "kpToolFlowCommand::updateBoundingRect() existing=" << d->boundingRect << " plus=" - << rect - << endl; + << rect; d->boundingRect = d->boundingRect.united (rect); qCDebug(kpLogCommands) << "\tresult=" << d->boundingRect; } // public void kpToolFlowCommand::finalize () { if (d->boundingRect.isValid ()) { // Store only the needed part of doc image. d->image = kpTool::neededPixmap (d->image, d->boundingRect); } else { d->image = kpImage (); } } // public void kpToolFlowCommand::cancel () { if (d->boundingRect.isValid ()) { viewManager ()->setFastUpdates (); document ()->setImageAt (d->image, d->boundingRect.topLeft ()); viewManager ()->restoreFastUpdates (); } } diff --git a/commands/tools/kpToolColorPickerCommand.cpp b/commands/tools/kpToolColorPickerCommand.cpp index b6d07e4e..5173fd68 100644 --- a/commands/tools/kpToolColorPickerCommand.cpp +++ b/commands/tools/kpToolColorPickerCommand.cpp @@ -1,83 +1,81 @@ /* Copyright (c) 2003-2007 Clarence Dang All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #define DEBUG_KP_TOOL_COLOR_PICKER 0 #include "kpToolColorPickerCommand.h" #include "environments/commands/kpCommandEnvironment.h" #include "kpDefs.h" #include kpToolColorPickerCommand::kpToolColorPickerCommand ( int mouseButton, const kpColor &newColor, const kpColor &oldColor, kpCommandEnvironment *environ) : kpCommand (environ), m_mouseButton (mouseButton), m_newColor (newColor), m_oldColor (oldColor) { } -kpToolColorPickerCommand::~kpToolColorPickerCommand () -{ -} +kpToolColorPickerCommand::~kpToolColorPickerCommand () = default; // public virtual [base kpCommand] QString kpToolColorPickerCommand::name () const { return i18n ("Color Picker"); } // public virtual [base kpCommand] kpCommandSize::SizeType kpToolColorPickerCommand::size () const { return 0; } // public virtual [base kpCommand] void kpToolColorPickerCommand::execute () { environ ()->setColor (m_mouseButton, m_newColor); } // public virtual [base kpCommand] void kpToolColorPickerCommand::unexecute () { environ ()->setColor (m_mouseButton, m_oldColor); } diff --git a/commands/tools/kpToolFloodFillCommand.cpp b/commands/tools/kpToolFloodFillCommand.cpp index 653f6067..da1ccaf4 100644 --- a/commands/tools/kpToolFloodFillCommand.cpp +++ b/commands/tools/kpToolFloodFillCommand.cpp @@ -1,163 +1,163 @@ /* Copyright (c) 2003-2007 Clarence Dang All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #define DEBUG_KP_TOOL_FLOOD_FILL 0 #include "kpToolFloodFillCommand.h" #include "imagelib/kpColor.h" #include "kpDefs.h" #include "document/kpDocument.h" #include "imagelib/kpImage.h" #include "kpLogCategories.h" #include #include //--------------------------------------------------------------------- struct kpToolFloodFillCommandPrivate { kpImage oldImage; - bool fillEntireImage; + bool fillEntireImage{false}; }; //--------------------------------------------------------------------- kpToolFloodFillCommand::kpToolFloodFillCommand (int x, int y, const kpColor &color, int processedColorSimilarity, kpCommandEnvironment *environ) : kpCommand (environ), kpFloodFill (document ()->imagePointer (), x, y, color, processedColorSimilarity), d (new kpToolFloodFillCommandPrivate ()) { d->fillEntireImage = false; } //--------------------------------------------------------------------- kpToolFloodFillCommand::~kpToolFloodFillCommand () { delete d; } //--------------------------------------------------------------------- // public virtual [base kpCommand] QString kpToolFloodFillCommand::name () const { return i18n ("Flood Fill"); } //--------------------------------------------------------------------- // public virtual [base kpCommand] kpCommandSize::SizeType kpToolFloodFillCommand::size () const { return kpFloodFill::size () + ImageSize (d->oldImage); } //--------------------------------------------------------------------- // public void kpToolFloodFillCommand::setFillEntireImage (bool yes) { d->fillEntireImage = yes; } //--------------------------------------------------------------------- // protected virtual [base kpCommand] void kpToolFloodFillCommand::execute () { qCDebug(kpLogCommands) << "kpToolFloodFillCommand::execute() fillEntireImage=" - << d->fillEntireImage << endl; + << d->fillEntireImage; kpDocument *doc = document (); Q_ASSERT (doc); if (d->fillEntireImage) { doc->fill (kpFloodFill::color ()); } else { QRect rect = kpFloodFill::boundingRect (); if (rect.isValid ()) { QApplication::setOverrideCursor (Qt::WaitCursor); { d->oldImage = doc->getImageAt (rect); kpFloodFill::fill (); doc->slotContentsChanged (rect); } QApplication::restoreOverrideCursor (); } else { qCDebug(kpLogCommands) << "\tinvalid boundingRect - must be NOP case"; } } } //--------------------------------------------------------------------- // protected virtual [base kpCommand] void kpToolFloodFillCommand::unexecute () { qCDebug(kpLogCommands) << "kpToolFloodFillCommand::unexecute() fillEntireImage=" - << d->fillEntireImage << endl; + << d->fillEntireImage; kpDocument *doc = document (); Q_ASSERT (doc); if (d->fillEntireImage) { doc->fill (kpFloodFill::colorToChange ()); } else { QRect rect = kpFloodFill::boundingRect (); if (rect.isValid ()) { doc->setImageAt (d->oldImage, rect.topLeft ()); d->oldImage = kpImage (); doc->slotContentsChanged (rect); } } } //--------------------------------------------------------------------- diff --git a/commands/tools/polygonal/kpToolPolygonalCommand.cpp b/commands/tools/polygonal/kpToolPolygonalCommand.cpp index 17888b21..76ab1ae1 100644 --- a/commands/tools/polygonal/kpToolPolygonalCommand.cpp +++ b/commands/tools/polygonal/kpToolPolygonalCommand.cpp @@ -1,124 +1,124 @@ /* Copyright (c) 2003-2007 Clarence Dang All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #define DEBUG_KP_TOOL_POLYGON 0 #include "kpToolPolygonalCommand.h" #include "document/kpDocument.h" #include "kpDefs.h" #include "imagelib/kpImage.h" #include "tools/polygonal/kpToolPolygonalBase.h" struct kpToolPolygonalCommandPrivate { - kpToolPolygonalBase::DrawShapeFunc drawShapeFunc; + kpToolPolygonalBase::DrawShapeFunc drawShapeFunc{}; QPolygon points; QRect boundingRect; kpColor fcolor; - int penWidth; + int penWidth{}; kpColor bcolor; kpImage oldImage; }; kpToolPolygonalCommand::kpToolPolygonalCommand (const QString &name, kpToolPolygonalBase::DrawShapeFunc drawShapeFunc, const QPolygon &points, const QRect &boundingRect, const kpColor &fcolor, int penWidth, const kpColor &bcolor, kpCommandEnvironment *environ) : kpNamedCommand (name, environ), d (new kpToolPolygonalCommandPrivate ()) { d->drawShapeFunc = drawShapeFunc; d->points = points; d->boundingRect = boundingRect; d->fcolor = fcolor; d->penWidth = penWidth; d->bcolor = bcolor; } kpToolPolygonalCommand::~kpToolPolygonalCommand () { delete d; } // public virtual [base kpCommand] kpCommandSize::SizeType kpToolPolygonalCommand::size () const { return PolygonSize (d->points) + ImageSize (d->oldImage); } // public virtual [base kpCommand] void kpToolPolygonalCommand::execute () { kpDocument *doc = document (); Q_ASSERT (doc); // Store Undo info. Q_ASSERT (d->oldImage.isNull ()); d->oldImage = doc->getImageAt (d->boundingRect); // Invoke shape drawing function passed in ctor. kpImage image = d->oldImage; QPolygon pointsTranslated = d->points; pointsTranslated.translate (-d->boundingRect.x (), -d->boundingRect.y ()); (*d->drawShapeFunc) (&image, pointsTranslated, d->fcolor, d->penWidth, d->bcolor, true/*final shape*/); doc->setImageAt (image, d->boundingRect.topLeft ()); } // public virtual [base kpCommand] void kpToolPolygonalCommand::unexecute () { kpDocument *doc = document (); Q_ASSERT (doc); Q_ASSERT (!d->oldImage.isNull ()); doc->setImageAt (d->oldImage, d->boundingRect.topLeft ()); d->oldImage = kpImage (); } diff --git a/commands/tools/rectangular/kpToolRectangularCommand.cpp b/commands/tools/rectangular/kpToolRectangularCommand.cpp index dd8444af..7cc27348 100644 --- a/commands/tools/rectangular/kpToolRectangularCommand.cpp +++ b/commands/tools/rectangular/kpToolRectangularCommand.cpp @@ -1,126 +1,126 @@ /* Copyright (c) 2003-2007 Clarence Dang All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #define DEBUG_KP_TOOL_RECTANGULAR_COMMAND 0 #include "kpToolRectangularCommand.h" #include "imagelib/kpColor.h" #include "kpDefs.h" #include "document/kpDocument.h" #include "imagelib/kpPainter.h" #include "pixmapfx/kpPixmapFX.h" #include "layers/tempImage/kpTempImage.h" #include "widgets/toolbars/kpToolToolBar.h" #include "widgets/toolbars/options/kpToolWidgetFillStyle.h" #include "widgets/toolbars/options/kpToolWidgetLineWidth.h" #include "views/kpView.h" #include "views/manager/kpViewManager.h" #include "kpLogCategories.h" struct kpToolRectangularCommandPrivate { - kpToolRectangularBase::DrawShapeFunc drawShapeFunc; + kpToolRectangularBase::DrawShapeFunc drawShapeFunc{}; QRect rect; kpColor fcolor; - int penWidth; + int penWidth{}; kpColor bcolor; kpImage oldImage; }; kpToolRectangularCommand::kpToolRectangularCommand (const QString &name, kpToolRectangularBase::DrawShapeFunc drawShapeFunc, const QRect &rect, const kpColor &fcolor, int penWidth, const kpColor &bcolor, kpCommandEnvironment *environ) : kpNamedCommand (name, environ), d (new kpToolRectangularCommandPrivate ()) { d->drawShapeFunc = drawShapeFunc; d->rect = rect; d->fcolor = fcolor; d->penWidth = penWidth; d->bcolor = bcolor; } kpToolRectangularCommand::~kpToolRectangularCommand () { delete d; } // public virtual [base kpCommand] kpCommandSize::SizeType kpToolRectangularCommand::size () const { return ImageSize (d->oldImage); } // public virtual [base kpCommand] void kpToolRectangularCommand::execute () { kpDocument *doc = document (); Q_ASSERT (doc); // Store Undo info. // OPT: For a pure rectangle, can do better if there is no bcolor, by only // saving 4 pixmaps corresponding to the pixels dirtied by the 4 edges. Q_ASSERT (d->oldImage.isNull ()); d->oldImage = doc->getImageAt (d->rect); // Invoke shape drawing function passed in ctor. kpImage image = d->oldImage; (*d->drawShapeFunc) (&image, 0, 0, d->rect.width (), d->rect.height (), d->fcolor, d->penWidth, d->bcolor); doc->setImageAt (image, d->rect.topLeft ()); } // public virtual [base kpCommand] void kpToolRectangularCommand::unexecute () { kpDocument *doc = document (); Q_ASSERT (doc); Q_ASSERT (!d->oldImage.isNull ()); doc->setImageAt (d->oldImage, d->rect.topLeft ()); d->oldImage = kpImage (); } diff --git a/commands/tools/selection/kpToolImageSelectionTransparencyCommand.cpp b/commands/tools/selection/kpToolImageSelectionTransparencyCommand.cpp index 5f68061b..3f6cffa1 100644 --- a/commands/tools/selection/kpToolImageSelectionTransparencyCommand.cpp +++ b/commands/tools/selection/kpToolImageSelectionTransparencyCommand.cpp @@ -1,92 +1,92 @@ /* Copyright (c) 2003-2007 Clarence Dang All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #define DEBUG_KP_TOOL_SELECTION 0 #include "kpToolImageSelectionTransparencyCommand.h" #include "environments/commands/kpCommandEnvironment.h" #include "kpDefs.h" #include "generic/kpSetOverrideCursorSaver.h" #include "kpLogCategories.h" #include "layers/selections/image/kpAbstractImageSelection.h" #include //-------------------------------------------------------------------------------- kpToolImageSelectionTransparencyCommand::kpToolImageSelectionTransparencyCommand ( const QString &name, const kpImageSelectionTransparency &st, const kpImageSelectionTransparency &oldST, kpCommandEnvironment *environ) : kpNamedCommand (name, environ), m_st (st), m_oldST (oldST) { } -kpToolImageSelectionTransparencyCommand::~kpToolImageSelectionTransparencyCommand () -{ -} +kpToolImageSelectionTransparencyCommand::~kpToolImageSelectionTransparencyCommand () = default; // public virtual [base kpCommand] kpCommandSize::SizeType kpToolImageSelectionTransparencyCommand::size () const { return 0; } // public virtual [base kpCommand] void kpToolImageSelectionTransparencyCommand::execute () { qCDebug(kpLogCommands) << "kpToolImageSelectionTransparencyCommand::execute()"; kpSetOverrideCursorSaver cursorSaver (Qt::WaitCursor); environ ()->setImageSelectionTransparency (m_st, true/*force colour change*/); - if (imageSelection ()) + if (imageSelection ()) { imageSelection ()->setTransparency (m_st); + } } // public virtual [base kpCommand] void kpToolImageSelectionTransparencyCommand::unexecute () { qCDebug(kpLogCommands) << "kpToolImageSelectionTransparencyCommand::unexecute()"; kpSetOverrideCursorSaver cursorSaver (Qt::WaitCursor); environ ()->setImageSelectionTransparency (m_oldST, true/*force colour change*/); - if (imageSelection ()) + if (imageSelection ()) { imageSelection ()->setTransparency (m_oldST); + } } diff --git a/commands/tools/selection/kpToolSelectionCreateCommand.cpp b/commands/tools/selection/kpToolSelectionCreateCommand.cpp index 3c83f455..03c8c13c 100644 --- a/commands/tools/selection/kpToolSelectionCreateCommand.cpp +++ b/commands/tools/selection/kpToolSelectionCreateCommand.cpp @@ -1,154 +1,156 @@ /* Copyright (c) 2003-2007 Clarence Dang All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #define DEBUG_KP_TOOL_SELECTION 0 #include "commands/tools/selection/kpToolSelectionCreateCommand.h" #include "layers/selections/kpAbstractSelection.h" #include "layers/selections/image/kpAbstractImageSelection.h" #include "environments/commands/kpCommandEnvironment.h" #include "commands/kpCommandHistory.h" #include "kpDefs.h" #include "document/kpDocument.h" #include "layers/selections/text/kpTextSelection.h" #include "widgets/toolbars/options/kpToolWidgetOpaqueOrTransparent.h" #include "views/kpView.h" #include "views/manager/kpViewManager.h" #include "kpLogCategories.h" #include #include #include #include #include #include #include #include #include kpToolSelectionCreateCommand::kpToolSelectionCreateCommand (const QString &name, const kpAbstractSelection &fromSelection, kpCommandEnvironment *environ) : kpNamedCommand (name, environ), m_fromSelection (nullptr), m_textRow (0), m_textCol (0) { setFromSelection (fromSelection); } kpToolSelectionCreateCommand::~kpToolSelectionCreateCommand () { delete m_fromSelection; } // public virtual [base kpCommand] kpCommandSize::SizeType kpToolSelectionCreateCommand::size () const { return SelectionSize (m_fromSelection); } // public const kpAbstractSelection *kpToolSelectionCreateCommand::fromSelection () const { return m_fromSelection; } // public void kpToolSelectionCreateCommand::setFromSelection (const kpAbstractSelection &fromSelection) { delete m_fromSelection; m_fromSelection = fromSelection.clone (); } // public virtual [base kpCommand] void kpToolSelectionCreateCommand::execute () { qCDebug(kpLogCommands) << "kpToolSelectionCreateCommand::execute()"; kpDocument *doc = document (); Q_ASSERT (doc); if (m_fromSelection) { qCDebug(kpLogCommands) << "\tusing fromSelection"; - qCDebug(kpLogCommands) << "\t\thave sel=" << doc->selection () - << endl; - kpAbstractImageSelection *imageSel = - dynamic_cast (m_fromSelection); - kpTextSelection *textSel = - dynamic_cast (m_fromSelection); + qCDebug(kpLogCommands) << "\t\thave sel=" << doc->selection (); + auto *imageSel = dynamic_cast (m_fromSelection); + auto *textSel = dynamic_cast (m_fromSelection); + if (imageSel) { - if (imageSel->transparency () != environ ()->imageSelectionTransparency ()) + if (imageSel->transparency () != environ ()->imageSelectionTransparency ()) { environ ()->setImageSelectionTransparency (imageSel->transparency ()); + } } else if (textSel) { - if (textSel->textStyle () != environ ()->textStyle ()) + if (textSel->textStyle () != environ ()->textStyle ()) { environ ()->setTextStyle (textSel->textStyle ()); + } } - else + else { Q_ASSERT (!"Unknown selection type"); + } viewManager ()->setTextCursorPosition (m_textRow, m_textCol); doc->setSelection (*m_fromSelection); environ ()->somethingBelowTheCursorChanged (); } } // public virtual [base kpCommand] void kpToolSelectionCreateCommand::unexecute () { kpDocument *doc = document (); Q_ASSERT (doc); if (!doc->selection ()) { // Was just a border that got deselected? - if (m_fromSelection && !m_fromSelection->hasContent ()) + if (m_fromSelection && !m_fromSelection->hasContent ()) { return; + } Q_ASSERT (!"kpToolSelectionCreateCommand::unexecute() without sel region"); return; } m_textRow = viewManager ()->textCursorRow (); m_textCol = viewManager ()->textCursorCol (); doc->selectionDelete (); environ ()->somethingBelowTheCursorChanged (); } diff --git a/commands/tools/selection/kpToolSelectionDestroyCommand.cpp b/commands/tools/selection/kpToolSelectionDestroyCommand.cpp index 584bec28..ef595ed7 100644 --- a/commands/tools/selection/kpToolSelectionDestroyCommand.cpp +++ b/commands/tools/selection/kpToolSelectionDestroyCommand.cpp @@ -1,161 +1,165 @@ /* Copyright (c) 2003-2007 Clarence Dang All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #define DEBUG_KP_TOOL_SELECTION 0 #include "kpToolSelectionDestroyCommand.h" #include "kpLogCategories.h" #include "layers/selections/kpAbstractSelection.h" #include "layers/selections/image/kpAbstractImageSelection.h" #include "environments/commands/kpCommandEnvironment.h" #include "kpDefs.h" #include "document/kpDocument.h" #include "layers/selections/text/kpTextSelection.h" #include "views/manager/kpViewManager.h" //--------------------------------------------------------------------- kpToolSelectionDestroyCommand::kpToolSelectionDestroyCommand (const QString &name, bool pushOntoDocument, kpCommandEnvironment *environ) : kpNamedCommand (name, environ), m_pushOntoDocument (pushOntoDocument), m_oldSelectionPtr (nullptr), m_textRow(0), m_textCol(0) { } //--------------------------------------------------------------------- kpToolSelectionDestroyCommand::~kpToolSelectionDestroyCommand () { delete m_oldSelectionPtr; } //--------------------------------------------------------------------- // public virtual [base kpCommand] kpCommandSize::SizeType kpToolSelectionDestroyCommand::size () const { return ImageSize (m_oldDocImage) + SelectionSize (m_oldSelectionPtr); } //--------------------------------------------------------------------- // public virtual [base kpCommand] void kpToolSelectionDestroyCommand::execute () { qCDebug(kpLogCommands) << "kpToolSelectionDestroyCommand::execute () CALLED"; kpDocument *doc = document (); Q_ASSERT (doc); Q_ASSERT (doc->selection ()); m_textRow = viewManager ()->textCursorRow (); m_textCol = viewManager ()->textCursorCol (); Q_ASSERT (!m_oldSelectionPtr); m_oldSelectionPtr = doc->selection ()->clone (); if (m_pushOntoDocument) { m_oldDocImage = doc->getImageAt (doc->selection ()->boundingRect ()); doc->selectionPushOntoDocument (); } - else + else { doc->selectionDelete (); + } environ ()->somethingBelowTheCursorChanged (); } //--------------------------------------------------------------------- // public virtual [base kpCommand] void kpToolSelectionDestroyCommand::unexecute () { qCDebug(kpLogCommands) << "kpToolSelectionDestroyCommand::unexecute () CALLED"; kpDocument *doc = document (); Q_ASSERT (doc); if (doc->selection ()) { // not error because it's possible that the user dragged out a new // region (without pulling image), and then CTRL+Z qCDebug(kpLogCommands) << "kpToolSelectionDestroyCommand::unexecute() already has sel region"; if (doc->selection ()->hasContent ()) { Q_ASSERT (!"kpToolSelectionDestroyCommand::unexecute() already has sel content"); return; } } Q_ASSERT (m_oldSelectionPtr); if (m_pushOntoDocument) { qCDebug(kpLogCommands) << "\tunpush oldDocImage onto doc first"; doc->setImageAt (m_oldDocImage, m_oldSelectionPtr->topLeft ()); } qCDebug(kpLogCommands) << "\tsetting selection to: rect=" << m_oldSelectionPtr->boundingRect () - << " hasContent=" << m_oldSelectionPtr->hasContent () - << endl; - kpAbstractImageSelection *imageSel = - dynamic_cast (m_oldSelectionPtr); - kpTextSelection *textSel = - dynamic_cast (m_oldSelectionPtr); + << " hasContent=" << m_oldSelectionPtr->hasContent (); + auto *imageSel = dynamic_cast (m_oldSelectionPtr); + auto *textSel = dynamic_cast (m_oldSelectionPtr); + if (imageSel) { - if (imageSel->transparency () != environ ()->imageSelectionTransparency ()) + if (imageSel->transparency () != environ ()->imageSelectionTransparency ()) { environ ()->setImageSelectionTransparency (imageSel->transparency ()); - if (dynamic_cast (doc->selection())) + } + if (dynamic_cast (doc->selection())) { doc->selectionPushOntoDocument(); + } } else if (textSel) { - if (textSel->textStyle () != environ ()->textStyle ()) + if (textSel->textStyle () != environ ()->textStyle ()) { environ ()->setTextStyle (textSel->textStyle ()); - if (dynamic_cast (doc->selection())) + } + if (dynamic_cast (doc->selection())) { doc->selectionPushOntoDocument(); + } } - else + else { Q_ASSERT (!"Unknown selection type"); + } viewManager ()->setTextCursorPosition (m_textRow, m_textCol); doc->setSelection (*m_oldSelectionPtr); environ ()->somethingBelowTheCursorChanged (); delete m_oldSelectionPtr; m_oldSelectionPtr = nullptr; } diff --git a/commands/tools/selection/kpToolSelectionMoveCommand.cpp b/commands/tools/selection/kpToolSelectionMoveCommand.cpp index 4b20ae80..81abb2ab 100644 --- a/commands/tools/selection/kpToolSelectionMoveCommand.cpp +++ b/commands/tools/selection/kpToolSelectionMoveCommand.cpp @@ -1,208 +1,208 @@ /* Copyright (c) 2003-2007 Clarence Dang All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #define DEBUG_KP_TOOL_SELECTION 0 #include "kpToolSelectionMoveCommand.h" #include "layers/selections/kpAbstractSelection.h" #include "environments/commands/kpCommandEnvironment.h" #include "kpDefs.h" #include "document/kpDocument.h" #include "tools/kpTool.h" #include "widgets/toolbars/options/kpToolWidgetOpaqueOrTransparent.h" #include "views/manager/kpViewManager.h" #include "kpLogCategories.h" //-------------------------------------------------------------------------------- kpToolSelectionMoveCommand::kpToolSelectionMoveCommand (const QString &name, kpCommandEnvironment *environ) : kpNamedCommand (name, environ) { kpDocument *doc = document (); Q_ASSERT (doc); Q_ASSERT (doc->selection ()); m_startPoint = m_endPoint = doc->selection ()->topLeft (); } -kpToolSelectionMoveCommand::~kpToolSelectionMoveCommand () -{ -} +kpToolSelectionMoveCommand::~kpToolSelectionMoveCommand () = default; // public kpAbstractSelection *kpToolSelectionMoveCommand::originalSelectionClone () const { kpDocument *doc = document (); Q_ASSERT (doc); Q_ASSERT (doc->selection ()); kpAbstractSelection *selection = doc->selection ()->clone (); selection->moveTo (m_startPoint); return selection; } // public virtual [base kpComand] kpCommandSize::SizeType kpToolSelectionMoveCommand::size () const { return ImageSize (m_oldDocumentImage) + PolygonSize (m_copyOntoDocumentPoints); } // public virtual [base kpCommand] void kpToolSelectionMoveCommand::execute () { qCDebug(kpLogCommands) << "kpToolSelectionMoveCommand::execute()"; kpDocument *doc = document (); Q_ASSERT (doc); kpAbstractSelection *sel = doc->selection (); // Must have content before it can be moved. Q_ASSERT (sel && sel->hasContent ()); kpViewManager *vm = viewManager (); Q_ASSERT (vm); vm->setQueueUpdates (); { - foreach (const QPoint &p, m_copyOntoDocumentPoints) + for (const auto &p : m_copyOntoDocumentPoints) { sel->moveTo (p); doc->selectionCopyOntoDocument (); } sel->moveTo (m_endPoint); environ ()->somethingBelowTheCursorChanged (); } vm->restoreQueueUpdates (); } // public virtual [base kpCommand] void kpToolSelectionMoveCommand::unexecute () { qCDebug(kpLogCommands) << "kpToolSelectionMoveCommand::unexecute()"; kpDocument *doc = document (); Q_ASSERT (doc); kpAbstractSelection *sel = doc->selection (); // Must have content before it can be un-moved. Q_ASSERT (sel && sel->hasContent ()); kpViewManager *vm = viewManager (); Q_ASSERT (vm); vm->setQueueUpdates (); - if (!m_oldDocumentImage.isNull ()) + if (!m_oldDocumentImage.isNull ()) { doc->setImageAt (m_oldDocumentImage, m_documentBoundingRect.topLeft ()); + } qCDebug(kpLogCommands) << "\tmove to startPoint=" << m_startPoint; sel->moveTo (m_startPoint); environ ()->somethingBelowTheCursorChanged (); vm->restoreQueueUpdates (); } // public void kpToolSelectionMoveCommand::moveTo (const QPoint &point, bool moveLater) { qCDebug(kpLogCommands) << "kpToolSelectionMoveCommand::moveTo" << point - << " moveLater=" << moveLater - <selection (); // Must have content before we allow it be stamped onto the document, // to be consistent with the requirement on other selection operations. Q_ASSERT (sel && sel->hasContent ()); - if (m_oldDocumentImage.isNull ()) + if (m_oldDocumentImage.isNull ()) { m_oldDocumentImage = doc->image (); + } QRect selBoundingRect = sel->boundingRect (); m_documentBoundingRect = m_documentBoundingRect.united (selBoundingRect); doc->selectionCopyOntoDocument (); m_copyOntoDocumentPoints.putPoints (m_copyOntoDocumentPoints.count (), 1, selBoundingRect.x (), selBoundingRect.y ()); } // public void kpToolSelectionMoveCommand::finalize () { if (!m_oldDocumentImage.isNull () && !m_documentBoundingRect.isNull ()) { m_oldDocumentImage = kpTool::neededPixmap (m_oldDocumentImage, m_documentBoundingRect); } } diff --git a/commands/tools/selection/kpToolSelectionPullFromDocumentCommand.cpp b/commands/tools/selection/kpToolSelectionPullFromDocumentCommand.cpp index 4f88356c..18cf8fb1 100644 --- a/commands/tools/selection/kpToolSelectionPullFromDocumentCommand.cpp +++ b/commands/tools/selection/kpToolSelectionPullFromDocumentCommand.cpp @@ -1,136 +1,134 @@ /* Copyright (c) 2003-2007 Clarence Dang All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #define DEBUG_KP_TOOL_SELECTION 0 #include "kpToolSelectionPullFromDocumentCommand.h" #include "layers/selections/image/kpAbstractImageSelection.h" #include "environments/commands/kpCommandEnvironment.h" #include "document/kpDocument.h" #include "views/manager/kpViewManager.h" #include "kpLogCategories.h" kpToolSelectionPullFromDocumentCommand::kpToolSelectionPullFromDocumentCommand ( const kpAbstractImageSelection &originalSelBorder, const kpColor &backgroundColor, const QString &name, kpCommandEnvironment *environ) : kpAbstractSelectionContentCommand (originalSelBorder, name, environ), m_backgroundColor (backgroundColor) { qCDebug(kpLogCommands) << "kpToolSelectionPullFromDocumentCommand::() environ=" - << environ - << endl; + << environ; } -kpToolSelectionPullFromDocumentCommand::~kpToolSelectionPullFromDocumentCommand () -{ -} +kpToolSelectionPullFromDocumentCommand::~kpToolSelectionPullFromDocumentCommand () = default; // public virtual [base kpCommand] void kpToolSelectionPullFromDocumentCommand::execute () { qCDebug(kpLogCommands) << "kpToolSelectionPullFromDocumentCommand::execute()"; kpDocument *doc = document (); Q_ASSERT (doc); kpViewManager *vm = viewManager (); Q_ASSERT (vm); vm->setQueueUpdates (); { // // Recreate border // // The previously executed command is required to have been a // kpToolSelectionCreateCommand, which must have been given an image // selection with no content. // // However, there is a tricky case. Suppose we are called for the first // time, where the above precondition holds. We would add content // to the selection as expected. But the user then undoes (CTRL+Z) the // operation, calling unexecute(). There is now no content again. // Since selection is only a border, the user can freely deselect it // and/or select another region without changing the command history // or document modified state. Therefore, if they now call us again // by redoing (CTRL+Shift+Z), there is potentially no selection at all // or it is at an arbitrary location. // // This assertion covers all 3 possibilities: // // 1. First call: image selection with no content // 2. Later calls: // a) no image selection (due to deselection) // b) image selection with no content, at an arbitrary location Q_ASSERT (!imageSelection () || !imageSelection ()->hasContent ()); - const kpAbstractImageSelection *originalImageSel = - static_cast (originalSelection ()); + const auto *originalImageSel = dynamic_cast + (originalSelection ()); + if (originalImageSel->transparency () != environ ()->imageSelectionTransparency ()) { environ ()->setImageSelectionTransparency (originalImageSel->transparency ()); } doc->setSelection (*originalSelection ()); // // Add content // doc->imageSelectionPullFromDocument (m_backgroundColor); } vm->restoreQueueUpdates (); } // public virtual [base kpCommand] void kpToolSelectionPullFromDocumentCommand::unexecute () { qCDebug(kpLogCommands) << "kpToolSelectionPullFromDocumentCommand::unexecute()"; kpDocument *doc = document (); Q_ASSERT (doc); // Must have selection image content. Q_ASSERT (doc->imageSelection () && doc->imageSelection ()->hasContent ()); // We can have faith that this is the state of the selection after // execute(), rather than after the user tried to throw us off by // simply selecting another region as to do that, a destroy command // must have been used. doc->selectionCopyOntoDocument (false/*use opaque pixmap*/); doc->imageSelection ()->deleteContent (); } diff --git a/commands/tools/selection/kpToolSelectionResizeScaleCommand.cpp b/commands/tools/selection/kpToolSelectionResizeScaleCommand.cpp index ad1043c9..d0d569eb 100644 --- a/commands/tools/selection/kpToolSelectionResizeScaleCommand.cpp +++ b/commands/tools/selection/kpToolSelectionResizeScaleCommand.cpp @@ -1,254 +1,253 @@ /* Copyright (c) 2003-2007 Clarence Dang All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #define DEBUG_KP_TOOL_SELECTION 0 #include "kpToolSelectionResizeScaleCommand.h" #include "layers/selections/kpAbstractSelection.h" #include "layers/selections/image/kpAbstractImageSelection.h" #include "environments/commands/kpCommandEnvironment.h" #include "kpDefs.h" #include "document/kpDocument.h" #include "layers/selections/image/kpRectangularImageSelection.h" #include "layers/selections/text/kpTextSelection.h" #include "kpLogCategories.h" #include #include #include #include //-------------------------------------------------------------------------------- kpToolSelectionResizeScaleCommand::kpToolSelectionResizeScaleCommand ( kpCommandEnvironment *environ) : kpNamedCommand (environ->textSelection () ? i18n ("Text: Resize Box") : i18n ("Selection: Smooth Scale"), environ), m_smoothScaleTimer (new QTimer (this)) { m_originalSelectionPtr = selection ()->clone (); m_newTopLeft = selection ()->topLeft (); m_newWidth = selection ()->width (); m_newHeight = selection ()->height (); m_smoothScaleTimer->setSingleShot (true); connect (m_smoothScaleTimer, &QTimer::timeout, this, [this]{resizeScaleAndMove(false);}); } kpToolSelectionResizeScaleCommand::~kpToolSelectionResizeScaleCommand () { delete m_originalSelectionPtr; } // public virtual kpCommandSize::SizeType kpToolSelectionResizeScaleCommand::size () const { return SelectionSize (m_originalSelectionPtr); } // public const kpAbstractSelection *kpToolSelectionResizeScaleCommand::originalSelection () const { return m_originalSelectionPtr; } // public QPoint kpToolSelectionResizeScaleCommand::topLeft () const { return m_newTopLeft; } // public void kpToolSelectionResizeScaleCommand::moveTo (const QPoint &point) { - if (point == m_newTopLeft) + if (point == m_newTopLeft) { return; + } m_newTopLeft = point; selection ()->moveTo (m_newTopLeft); } // public int kpToolSelectionResizeScaleCommand::width () const { return m_newWidth; } // public int kpToolSelectionResizeScaleCommand::height () const { return m_newHeight; } // public void kpToolSelectionResizeScaleCommand::resize (int width, int height, bool delayed) { - if (width == m_newWidth && height == m_newHeight) + if (width == m_newWidth && height == m_newHeight) { return; + } m_newWidth = width; m_newHeight = height; resizeScaleAndMove (delayed); } // public void kpToolSelectionResizeScaleCommand::resizeAndMoveTo (int width, int height, const QPoint &point, bool delayed) { if (width == m_newWidth && height == m_newHeight && point == m_newTopLeft) { return; } m_newWidth = width; m_newHeight = height; m_newTopLeft = point; resizeScaleAndMove (delayed); } // protected void kpToolSelectionResizeScaleCommand::killSmoothScaleTimer () { m_smoothScaleTimer->stop (); } // protected void kpToolSelectionResizeScaleCommand::resizeScaleAndMove (bool delayed) { qCDebug(kpLogCommands) << "kpToolSelectionResizeScaleCommand::resizeScaleAndMove(delayed=" - << delayed << ")" << endl; + << delayed << ")"; killSmoothScaleTimer (); kpAbstractSelection *newSelPtr = nullptr; if (textSelection ()) { Q_ASSERT (dynamic_cast (m_originalSelectionPtr)); - kpTextSelection *orgTextSel = - static_cast (m_originalSelectionPtr); + auto *orgTextSel = dynamic_cast (m_originalSelectionPtr); newSelPtr = orgTextSel->resized (m_newWidth, m_newHeight); } else { Q_ASSERT (dynamic_cast (m_originalSelectionPtr)); - kpAbstractImageSelection *imageSel = - static_cast (m_originalSelectionPtr); + auto *imageSel = dynamic_cast (m_originalSelectionPtr); newSelPtr = new kpRectangularImageSelection ( QRect (imageSel->x (), imageSel->y (), m_newWidth, m_newHeight), kpPixmapFX::scale (imageSel->baseImage (), m_newWidth, m_newHeight, !delayed/*if not delayed, smooth*/), imageSel->transparency ()); if (delayed) { // Call self (once) with delayed==false in 200ms m_smoothScaleTimer->start (200/*ms*/); } } Q_ASSERT (newSelPtr); newSelPtr->moveTo (m_newTopLeft); document ()->setSelection (*newSelPtr); delete newSelPtr; } // public void kpToolSelectionResizeScaleCommand::finalize () { qCDebug(kpLogCommands) << "kpToolSelectionResizeScaleCommand::finalize()" << " smoothScaleTimer->isActive=" - << m_smoothScaleTimer->isActive () - << endl; + << m_smoothScaleTimer->isActive (); // Make sure the selection contains the final image and the timer won't // fire afterwards. if (m_smoothScaleTimer->isActive ()) { resizeScaleAndMove (); Q_ASSERT (!m_smoothScaleTimer->isActive ()); } } // public virtual [base kpToolResizeScaleCommand] void kpToolSelectionResizeScaleCommand::execute () { QApplication::setOverrideCursor (Qt::WaitCursor); killSmoothScaleTimer (); resizeScaleAndMove (); environ ()->somethingBelowTheCursorChanged (); QApplication::restoreOverrideCursor (); } // public virtual [base kpToolResizeScaleCommand] void kpToolSelectionResizeScaleCommand::unexecute () { QApplication::setOverrideCursor (Qt::WaitCursor); killSmoothScaleTimer (); document ()->setSelection (*m_originalSelectionPtr); environ ()->somethingBelowTheCursorChanged (); QApplication::restoreOverrideCursor (); } diff --git a/commands/tools/selection/text/kpToolTextBackspaceCommand.cpp b/commands/tools/selection/text/kpToolTextBackspaceCommand.cpp index df641e00..03b3cc16 100644 --- a/commands/tools/selection/text/kpToolTextBackspaceCommand.cpp +++ b/commands/tools/selection/text/kpToolTextBackspaceCommand.cpp @@ -1,152 +1,152 @@ /* Copyright (c) 2003-2007 Clarence Dang All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #define DEBUG_KP_TOOL_TEXT 0 #include "kpToolTextBackspaceCommand.h" #include "layers/selections/text/kpTextSelection.h" #include "views/manager/kpViewManager.h" #include kpToolTextBackspaceCommand::kpToolTextBackspaceCommand (const QString &name, int row, int col, Action action, kpCommandEnvironment *environ) : kpNamedCommand (name, environ), m_row (row), m_col (col), m_numBackspaces (0) { viewManager ()->setTextCursorPosition (m_row, m_col); - if (action == AddBackspaceNow) + if (action == AddBackspaceNow) { addBackspace (); + } } -kpToolTextBackspaceCommand::~kpToolTextBackspaceCommand () -{ -} +kpToolTextBackspaceCommand::~kpToolTextBackspaceCommand () = default; // public void kpToolTextBackspaceCommand::addBackspace () { QList textLines = textSelection ()->textLines (); if (m_col > 0) { m_deletedText.prepend (textLines [m_row][m_col - 1]); textLines [m_row] = textLines [m_row].left (m_col - 1) + textLines [m_row].mid (m_col); m_col--; } else { if (m_row > 0) { int newCursorRow = m_row - 1; int newCursorCol = textLines [newCursorRow].length (); m_deletedText.prepend ('\n'); textLines [newCursorRow] += textLines [m_row]; textLines.erase (textLines.begin () + m_row); m_row = newCursorRow; m_col = newCursorCol; } } textSelection ()->setTextLines (textLines); viewManager ()->setTextCursorPosition (m_row, m_col); m_numBackspaces++; } // public virtual [base kpCommand] kpCommandSize::SizeType kpToolTextBackspaceCommand::size () const { return static_cast (static_cast (m_deletedText.length ()) * sizeof (QChar)); } // public virtual [base kpCommand] void kpToolTextBackspaceCommand::execute () { viewManager ()->setTextCursorPosition (m_row, m_col); m_deletedText.clear (); int oldNumBackspaces = m_numBackspaces; m_numBackspaces = 0; - for (int i = 0; i < oldNumBackspaces; i++) + for (int i = 0; i < oldNumBackspaces; i++) { addBackspace (); + } } // public virtual [base kpCommand] void kpToolTextBackspaceCommand::unexecute () { viewManager ()->setTextCursorPosition (m_row, m_col); QList textLines = textSelection ()->textLines (); - for (int i = 0; i < static_cast (m_deletedText.length ()); i++) + for (auto && i : m_deletedText) { - if (m_deletedText [i] == '\n') + if (i == '\n') { const QString rightHalf = textLines [m_row].mid (m_col); textLines [m_row].truncate (m_col); textLines.insert (textLines.begin () + m_row + 1, rightHalf); m_row++; m_col = 0; } else { const QString leftHalf = textLines [m_row].left (m_col); const QString rightHalf = textLines [m_row].mid (m_col); - textLines [m_row] = leftHalf + m_deletedText [i] + rightHalf; + textLines [m_row] = leftHalf + i + rightHalf; m_col++; } } m_deletedText.clear (); textSelection ()->setTextLines (textLines); viewManager ()->setTextCursorPosition (m_row, m_col); } diff --git a/commands/tools/selection/text/kpToolTextChangeStyleCommand.cpp b/commands/tools/selection/text/kpToolTextChangeStyleCommand.cpp index e31a2063..2c593674 100644 --- a/commands/tools/selection/text/kpToolTextChangeStyleCommand.cpp +++ b/commands/tools/selection/text/kpToolTextChangeStyleCommand.cpp @@ -1,95 +1,92 @@ /* Copyright (c) 2003-2007 Clarence Dang All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #define DEBUG_KP_TOOL_TEXT 0 #include "kpToolTextChangeStyleCommand.h" #include "environments/commands/kpCommandEnvironment.h" #include "layers/selections/text/kpTextSelection.h" #include "kpLogCategories.h" kpToolTextChangeStyleCommand::kpToolTextChangeStyleCommand (const QString &name, const kpTextStyle &newTextStyle, const kpTextStyle &oldTextStyle, kpCommandEnvironment *environ) : kpNamedCommand (name, environ), m_newTextStyle (newTextStyle), m_oldTextStyle (oldTextStyle) { } -kpToolTextChangeStyleCommand::~kpToolTextChangeStyleCommand () -{ -} +kpToolTextChangeStyleCommand::~kpToolTextChangeStyleCommand () = default; // public virtual [base kpCommand] kpCommandSize::SizeType kpToolTextChangeStyleCommand::size () const { return 0; } // public virtual [base kpCommand] void kpToolTextChangeStyleCommand::execute () { qCDebug(kpLogCommands) << "kpToolTextChangeStyleCommand::execute()" << " font=" << m_newTextStyle.fontFamily () << " fontSize=" << m_newTextStyle.fontSize () << " isBold=" << m_newTextStyle.isBold () << " isItalic=" << m_newTextStyle.isItalic () << " isUnderline=" << m_newTextStyle.isUnderline () - << " isStrikeThru=" << m_newTextStyle.isStrikeThru () - << endl; + << " isStrikeThru=" << m_newTextStyle.isStrikeThru (); environ ()->setTextStyle (m_newTextStyle); - if (textSelection ()) + if (textSelection ()) { textSelection ()->setTextStyle (m_newTextStyle); + } } // public virtual [base kpCommand] void kpToolTextChangeStyleCommand::unexecute () { qCDebug(kpLogCommands) << "kpToolTextChangeStyleCommand::unexecute()" << " font=" << m_newTextStyle.fontFamily () << " fontSize=" << m_newTextStyle.fontSize () << " isBold=" << m_newTextStyle.isBold () << " isItalic=" << m_newTextStyle.isItalic () << " isUnderline=" << m_newTextStyle.isUnderline () - << " isStrikeThru=" << m_newTextStyle.isStrikeThru () - << endl; + << " isStrikeThru=" << m_newTextStyle.isStrikeThru (); environ ()->setTextStyle (m_oldTextStyle); if (textSelection ()) textSelection ()->setTextStyle (m_oldTextStyle); } diff --git a/commands/tools/selection/text/kpToolTextDeleteCommand.cpp b/commands/tools/selection/text/kpToolTextDeleteCommand.cpp index 1dd9cce6..459657c7 100644 --- a/commands/tools/selection/text/kpToolTextDeleteCommand.cpp +++ b/commands/tools/selection/text/kpToolTextDeleteCommand.cpp @@ -1,140 +1,140 @@ /* Copyright (c) 2003-2007 Clarence Dang All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #define DEBUG_KP_TOOL_TEXT 0 #include "kpToolTextDeleteCommand.h" #include "layers/selections/text/kpTextSelection.h" #include "views/manager/kpViewManager.h" #include kpToolTextDeleteCommand::kpToolTextDeleteCommand (const QString &name, int row, int col, Action action, kpCommandEnvironment *environ) : kpNamedCommand (name, environ), m_row (row), m_col (col), m_numDeletes (0) { viewManager ()->setTextCursorPosition (m_row, m_col); - if (action == AddDeleteNow) + if (action == AddDeleteNow) { addDelete (); + } } -kpToolTextDeleteCommand::~kpToolTextDeleteCommand () -{ -} +kpToolTextDeleteCommand::~kpToolTextDeleteCommand () = default; // public void kpToolTextDeleteCommand::addDelete () { QList textLines = textSelection ()->textLines (); if (m_col < static_cast (textLines [m_row].length ())) { m_deletedText.prepend (textLines [m_row][m_col]); textLines [m_row] = textLines [m_row].left (m_col) + textLines [m_row].mid (m_col + 1); } else { if (m_row < static_cast (textLines.size () - 1)) { m_deletedText.prepend ('\n'); textLines [m_row] += textLines [m_row + 1]; textLines.erase (textLines.begin () + m_row + 1); } } textSelection ()->setTextLines (textLines); viewManager ()->setTextCursorPosition (m_row, m_col); m_numDeletes++; } // public virtual [base kpCommand] kpCommandSize::SizeType kpToolTextDeleteCommand::size () const { return static_cast (static_cast (m_deletedText.length ()) * sizeof (QChar)); } // public virtual [base kpCommand] void kpToolTextDeleteCommand::execute () { viewManager ()->setTextCursorPosition (m_row, m_col); m_deletedText.clear (); int oldNumDeletes = m_numDeletes; m_numDeletes = 0; - for (int i = 0; i < oldNumDeletes; i++) + for (int i = 0; i < oldNumDeletes; i++) { addDelete (); + } } // public virtual [base kpCommand] void kpToolTextDeleteCommand::unexecute () { viewManager ()->setTextCursorPosition (m_row, m_col); QList textLines = textSelection ()->textLines (); - for (int i = 0; i < static_cast (m_deletedText.length ()); i++) + for (auto && i : m_deletedText) { - if (m_deletedText [i] == '\n') + if (i == '\n') { const QString rightHalf = textLines [m_row].mid (m_col); textLines [m_row].truncate (m_col); textLines.insert (textLines.begin () + m_row + 1, rightHalf); } else { const QString leftHalf = textLines [m_row].left (m_col); const QString rightHalf = textLines [m_row].mid (m_col); - textLines [m_row] = leftHalf + m_deletedText [i] + rightHalf; + textLines [m_row] = leftHalf + i + rightHalf; } } m_deletedText.clear (); textSelection ()->setTextLines (textLines); viewManager ()->setTextCursorPosition (m_row, m_col); } diff --git a/commands/tools/selection/text/kpToolTextEnterCommand.cpp b/commands/tools/selection/text/kpToolTextEnterCommand.cpp index 9f87e654..c341c779 100644 --- a/commands/tools/selection/text/kpToolTextEnterCommand.cpp +++ b/commands/tools/selection/text/kpToolTextEnterCommand.cpp @@ -1,125 +1,126 @@ /* Copyright (c) 2003-2007 Clarence Dang All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #define DEBUG_KP_TOOL_TEXT 0 #include "kpToolTextEnterCommand.h" #include "layers/selections/text/kpTextSelection.h" #include "views/manager/kpViewManager.h" #include kpToolTextEnterCommand::kpToolTextEnterCommand (const QString &name, int row, int col, Action action, kpCommandEnvironment *environ) : kpNamedCommand (name, environ), m_row (row), m_col (col), m_numEnters (0) { viewManager ()->setTextCursorPosition (m_row, m_col); - if (action == AddEnterNow) + if (action == AddEnterNow) { addEnter (); + } } -kpToolTextEnterCommand::~kpToolTextEnterCommand () -{ -} +kpToolTextEnterCommand::~kpToolTextEnterCommand () = default; // public void kpToolTextEnterCommand::addEnter () { QList textLines = textSelection ()->textLines (); const QString rightHalf = textLines [m_row].mid (m_col); textLines [m_row].truncate (m_col); textLines.insert (textLines.begin () + m_row + 1, rightHalf); textSelection ()->setTextLines (textLines); m_row++; m_col = 0; viewManager ()->setTextCursorPosition (m_row, m_col); m_numEnters++; } // public virtual [base kpCommand] kpCommandSize::SizeType kpToolTextEnterCommand::size () const { return 0; } // public virtual [base kpCommand] void kpToolTextEnterCommand::execute () { viewManager ()->setTextCursorPosition (m_row, m_col); int oldNumEnters = m_numEnters; m_numEnters = 0; - for (int i = 0; i < oldNumEnters; i++) + for (int i = 0; i < oldNumEnters; i++) { addEnter (); + } } // public virtual [base kpCommand] void kpToolTextEnterCommand::unexecute () { viewManager ()->setTextCursorPosition (m_row, m_col); QList textLines = textSelection ()->textLines (); for (int i = 0; i < m_numEnters; i++) { Q_ASSERT (m_col == 0); - if (m_row <= 0) + if (m_row <= 0) { break; + } int newRow = m_row - 1; int newCol = textLines [newRow].length (); textLines [newRow] += textLines [m_row]; textLines.erase (textLines.begin () + m_row); m_row = newRow; m_col = newCol; } textSelection ()->setTextLines (textLines); viewManager ()->setTextCursorPosition (m_row, m_col); } diff --git a/commands/tools/selection/text/kpToolTextGiveContentCommand.cpp b/commands/tools/selection/text/kpToolTextGiveContentCommand.cpp index 06d3f34e..72cdb07a 100644 --- a/commands/tools/selection/text/kpToolTextGiveContentCommand.cpp +++ b/commands/tools/selection/text/kpToolTextGiveContentCommand.cpp @@ -1,146 +1,145 @@ /* Copyright (c) 2003-2007 Clarence Dang All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #define DEBUG_KP_TOOL_SELECTION 0 #include "kpToolTextGiveContentCommand.h" #include "environments/commands/kpCommandEnvironment.h" #include "document/kpDocument.h" #include "layers/selections/text/kpTextSelection.h" #include "views/manager/kpViewManager.h" #include "kpLogCategories.h" kpToolTextGiveContentCommand::kpToolTextGiveContentCommand ( const kpTextSelection &originalSelBorder, const QString &name, kpCommandEnvironment *environ) : kpAbstractSelectionContentCommand (originalSelBorder, name, environ) { qCDebug(kpLogCommands) << "kpToolTextGiveContentCommand::() environ=" - << environ - << endl; + << environ; } -kpToolTextGiveContentCommand::~kpToolTextGiveContentCommand () -{ -} +kpToolTextGiveContentCommand::~kpToolTextGiveContentCommand () = default; // public virtual [base kpCommand] void kpToolTextGiveContentCommand::execute () { qCDebug(kpLogCommands) << "kpToolTextGiveContentCommand::execute()"; kpDocument *doc = document (); Q_ASSERT (doc); kpViewManager *vm = viewManager (); Q_ASSERT (vm); // See API Doc for kpViewManager::textCursorRow() & textCursorCol(). Q_ASSERT (vm->textCursorRow () == 0 && vm->textCursorCol () == 0); vm->setQueueUpdates (); { // // Recreate border // // The previously executed command is required to have been a // kpToolSelectionCreateCommand, which must have been given a text // selection with no content. // // However, there is a tricky case. Suppose we are called for the first // time, where the above precondition holds. We would add content // to the selection as expected. But the user then undoes (CTRL+Z) the // operation, calling unexecute(). There is now no content again. // Since selection is only a border, the user can freely deselect it // and/or select another region without changing the command history // or document modified state. Therefore, if they now call us again // by redoing (CTRL+Shift+Z), there is potentially no selection at all // or it is at an arbitrary location. // // This assertion covers all 3 possibilities: // // 1. First call: text selection with no content // 2. Later calls: // a) no text selection (due to deselection) // b) text selection with no content, at an arbitrary location Q_ASSERT (!textSelection () || !textSelection ()->hasContent ()); - const kpTextSelection *originalTextSel = - static_cast (originalSelection ()); - if (originalTextSel->textStyle () != environ ()->textStyle ()) + const auto *originalTextSel = dynamic_cast + (originalSelection ()); + + if (originalTextSel->textStyle () != environ ()->textStyle ()) { environ ()->setTextStyle (originalTextSel->textStyle ()); + } doc->setSelection (*originalSelection ()); // // Add Content // QList listOfOneEmptyString; listOfOneEmptyString.append (QString ()); textSelection ()->setTextLines (listOfOneEmptyString); } vm->restoreQueueUpdates (); // This should not have changed from the start of the method. Q_ASSERT (vm->textCursorRow () == 0 && vm->textCursorCol () == 0); } // public virtual [base kpCommand] void kpToolTextGiveContentCommand::unexecute () { qCDebug(kpLogCommands) << "kpToolTextGiveContentCommand::unexecute()"; kpDocument *doc = document (); Q_ASSERT (doc); // Must have selection text content. Q_ASSERT (doc->textSelection () && doc->textSelection ()->hasContent ()); kpViewManager *vm = viewManager (); Q_ASSERT (vm); // All the commands after us have been unexecuted, so we must be back // to the state we were after our execute(). Q_ASSERT (vm->textCursorRow () == 0 && vm->textCursorCol () == 0); // We can have faith that this is the state of the selection after // execute(), rather than after the user tried to throw us off by // simply selecting another region as to do that, a destroy command // must have been used. doc->textSelection ()->deleteContent (); // This should not have changed from the start of the method. Q_ASSERT (vm->textCursorRow () == 0 && vm->textCursorCol () == 0); } diff --git a/commands/tools/selection/text/kpToolTextInsertCommand.cpp b/commands/tools/selection/text/kpToolTextInsertCommand.cpp index 1ab3db8f..7db6e13e 100644 --- a/commands/tools/selection/text/kpToolTextInsertCommand.cpp +++ b/commands/tools/selection/text/kpToolTextInsertCommand.cpp @@ -1,109 +1,110 @@ /* Copyright (c) 2003-2007 Clarence Dang All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #define DEBUG_KP_TOOL_TEXT 0 #include "kpToolTextInsertCommand.h" #include "layers/selections/text/kpTextSelection.h" #include "views/manager/kpViewManager.h" #include //--------------------------------------------------------------------- kpToolTextInsertCommand::kpToolTextInsertCommand (const QString &name, - int row, int col, QString newText, + int row, int col, const QString& newText, kpCommandEnvironment *environ) : kpNamedCommand (name, environ), m_row (row), m_col (col) { viewManager ()->setTextCursorPosition (m_row, m_col); addText (newText); } //--------------------------------------------------------------------- // public void kpToolTextInsertCommand::addText (const QString &moreText) { - if (moreText.isEmpty ()) + if (moreText.isEmpty ()) { return; + } QList textLines = textSelection ()->textLines (); const QString leftHalf = textLines [m_row].left (m_col); const QString rightHalf = textLines [m_row].mid (m_col); textLines [m_row] = leftHalf + moreText + rightHalf; textSelection ()->setTextLines (textLines); m_newText += moreText; m_col += moreText.length (); viewManager ()->setTextCursorPosition (m_row, m_col); } //--------------------------------------------------------------------- // public virtual [base kpCommand] kpCommandSize::SizeType kpToolTextInsertCommand::size () const { return static_cast (static_cast (m_newText.length ()) * sizeof (QChar)); } //--------------------------------------------------------------------- // public virtual [base kpCommand] void kpToolTextInsertCommand::execute () { viewManager ()->setTextCursorPosition (m_row, m_col); QString text = m_newText; m_newText.clear (); addText (text); } //--------------------------------------------------------------------- // public virtual [base kpCommand] void kpToolTextInsertCommand::unexecute () { viewManager ()->setTextCursorPosition (m_row, m_col); QList textLines = textSelection ()->textLines (); const QString leftHalf = textLines [m_row].left (m_col - m_newText.length ()); const QString rightHalf = textLines [m_row].mid (m_col); textLines [m_row] = leftHalf + rightHalf; textSelection ()->setTextLines (textLines); m_col -= m_newText.length (); viewManager ()->setTextCursorPosition (m_row, m_col); } //--------------------------------------------------------------------- diff --git a/commands/tools/selection/text/kpToolTextInsertCommand.h b/commands/tools/selection/text/kpToolTextInsertCommand.h index 8153e9dc..aaf79569 100644 --- a/commands/tools/selection/text/kpToolTextInsertCommand.h +++ b/commands/tools/selection/text/kpToolTextInsertCommand.h @@ -1,56 +1,56 @@ /* Copyright (c) 2003-2007 Clarence Dang All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #ifndef KP_TOOL_TEXT_INSERT_COMMAND_H #define KP_TOOL_TEXT_INSERT_COMMAND_H #include "commands/kpNamedCommand.h" class kpToolTextInsertCommand : public kpNamedCommand { public: kpToolTextInsertCommand (const QString &name, - int row, int col, QString newText, + int row, int col, const QString& newText, kpCommandEnvironment *environ); void addText (const QString &moreText); kpCommandSize::SizeType size () const override; void execute () override; void unexecute () override; protected: int m_row, m_col; QString m_newText; }; #endif // KP_TOOL_TEXT_INSERT_COMMAND_H diff --git a/cursors/kpCursorLightCross.cpp b/cursors/kpCursorLightCross.cpp index 828c2b6a..bd954710 100644 --- a/cursors/kpCursorLightCross.cpp +++ b/cursors/kpCursorLightCross.cpp @@ -1,127 +1,129 @@ /* Copyright (c) 2003-2007 Clarence Dang All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #define DEBUG_KP_CURSOR_LIGHT_CROSS 0 #include "kpCursorLightCross.h" #include "kpLogCategories.h" #include #include enum PixelValue { White, Black, Transparent }; static void setPixel (unsigned char *colorBitmap, unsigned char *maskBitmap, int width, int y, int x, enum PixelValue pv) { const int ColorBlack = 1; const int ColorWhite = 0; const int MaskOpaque = 1; const int MaskTransparent = 0; int colorValue, maskValue; switch (pv) { case White: colorValue = ColorWhite; maskValue = MaskOpaque; break; case Black: colorValue = ColorBlack; maskValue = MaskOpaque; break; case Transparent: colorValue = ColorWhite; maskValue = MaskTransparent; break; } - if (colorValue) + if (colorValue) { colorBitmap [y * (width / 8) + (x / 8)] |= (1 << (x % 8)); + } - if (maskValue) + if (maskValue) { maskBitmap [y * (width / 8) + (x / 8)] |= (1 << (x % 8)); + } } const QCursor *kpCursorLightCrossCreate () { qCDebug(kpLogMisc) << "kpCursorLightCrossCreate() "; const int side = 24; const int byteSize = (side * side) / 8; - unsigned char *colorBitmap = new unsigned char [byteSize]; - unsigned char *maskBitmap = new unsigned char [byteSize]; + auto *colorBitmap = new unsigned char [byteSize]; + auto *maskBitmap = new unsigned char [byteSize]; memset (colorBitmap, 0, byteSize); memset (maskBitmap, 0, byteSize); const int oddSide = side - 1; const int strokeLen = oddSide * 3 / 8; for (int i = 0; i < strokeLen; i++) { const enum PixelValue pv = (i % 2) ? Black : White; #define X_(val) (val) #define Y_(val) (val) #define DRAW(y,x) setPixel (colorBitmap, maskBitmap, side, (y), (x), pv) // horizontal DRAW (Y_(side / 2), X_(1 + i)); DRAW (Y_(side / 2), X_(side - 1 - i)); // vertical DRAW (Y_(1 + i), X_(side / 2)); DRAW (Y_(side - 1 - i), X_(side / 2)); #undef DRAW #undef Y_ #undef X_ } const QSize size (side, side); QCursor *cursor = new QCursor ( QBitmap::fromData (size, colorBitmap, QImage::Format_MonoLSB), QBitmap::fromData (size, maskBitmap, QImage::Format_MonoLSB)); delete [] maskBitmap; delete [] colorBitmap; return cursor; } diff --git a/cursors/kpCursorProvider.cpp b/cursors/kpCursorProvider.cpp index ff5cf2d7..fdc3d51d 100644 --- a/cursors/kpCursorProvider.cpp +++ b/cursors/kpCursorProvider.cpp @@ -1,47 +1,48 @@ /* Copyright (c) 2003-2007 Clarence Dang All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include "kpCursorProvider.h" #include "kpCursorLightCross.h" #include static const QCursor *TheLightCursor = nullptr; // public static QCursor kpCursorProvider::lightCross () { // TODO: don't leak (although it's cleaned up on exit by OS anyway) - if (!::TheLightCursor) + if (!::TheLightCursor) { ::TheLightCursor = kpCursorLightCrossCreate (); + } return *::TheLightCursor; } diff --git a/dialogs/imagelib/effects/kpEffectsDialog.cpp b/dialogs/imagelib/effects/kpEffectsDialog.cpp index b5207ca8..6ff638bd 100644 --- a/dialogs/imagelib/effects/kpEffectsDialog.cpp +++ b/dialogs/imagelib/effects/kpEffectsDialog.cpp @@ -1,331 +1,339 @@ /* Copyright (c) 2003-2007 Clarence Dang All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #define DEBUG_KP_EFFECTS_DIALOG 0 #include "kpEffectsDialog.h" #include "kpDefs.h" #include "document/kpDocument.h" #include "widgets/imagelib/effects/kpEffectBalanceWidget.h" #include "widgets/imagelib/effects/kpEffectBlurSharpenWidget.h" #include "widgets/imagelib/effects/kpEffectEmbossWidget.h" #include "widgets/imagelib/effects/kpEffectFlattenWidget.h" #include "widgets/imagelib/effects/kpEffectHSVWidget.h" #include "widgets/imagelib/effects/kpEffectInvertWidget.h" #include "widgets/imagelib/effects/kpEffectReduceColorsWidget.h" #include "widgets/imagelib/effects/kpEffectToneEnhanceWidget.h" #include "pixmapfx/kpPixmapFX.h" #include "environments/dialogs/imagelib/transforms/kpTransformDialogEnvironment.h" #include #include "kpLogCategories.h" #include #include #include #include #include #include #include // protected static int kpEffectsDialog::s_lastWidth = 640; int kpEffectsDialog::s_lastHeight = 620; kpEffectsDialog::kpEffectsDialog (bool actOnSelection, kpTransformDialogEnvironment *_env, QWidget *parent, int defaultSelectedEffect) : kpTransformPreviewDialog (kpTransformPreviewDialog::Preview, true/*reserve top row*/, QString()/*caption*/, QString()/*afterActionText (no Dimensions Group Box)*/, actOnSelection, _env, parent), m_delayedUpdateTimer (new QTimer (this)), m_effectsComboBox (nullptr), m_settingsGroupBox (nullptr), m_settingsLayout (nullptr), m_effectWidget (nullptr) { qCDebug(kpLogDialogs) << "kpEffectsDialog::kpEffectsDialog()"; const bool e = updatesEnabled (); setUpdatesEnabled (false); - if (actOnSelection) + if (actOnSelection) { setWindowTitle (i18nc ("@title:window", "More Image Effects (Selection)")); - else + } + else { setWindowTitle (i18nc ("@title:window", "More Image Effects")); + } m_delayedUpdateTimer->setSingleShot (true); connect (m_delayedUpdateTimer, &QTimer::timeout, this, &kpEffectsDialog::slotUpdateWithWaitCursor); QWidget *effectContainer = new QWidget (mainWidget ()); - QHBoxLayout *containerLayout = new QHBoxLayout (effectContainer); + + auto *containerLayout = new QHBoxLayout (effectContainer); containerLayout->setContentsMargins(0, 0, 0, 0); QLabel *label = new QLabel (i18n ("&Effect:"), effectContainer); m_effectsComboBox = new QComboBox (effectContainer); // Keep in alphabetical order. // TODO: What about translations? // sync: order in selectEffect(). m_effectsComboBox->addItem (i18n ("Balance")); m_effectsComboBox->addItem (i18n ("Emboss")); m_effectsComboBox->addItem (i18n ("Flatten")); m_effectsComboBox->addItem (i18n ("Histogram Equalizer")); m_effectsComboBox->addItem (i18n ("Hue, Saturation, Value")); m_effectsComboBox->addItem (i18n ("Invert")); m_effectsComboBox->addItem (i18n ("Reduce Colors")); m_effectsComboBox->addItem (i18n ("Soften & Sharpen")); containerLayout->addWidget (label); containerLayout->addWidget (m_effectsComboBox, 1); label->setBuddy (m_effectsComboBox); addCustomWidgetToFront (effectContainer); m_settingsGroupBox = new QGroupBox (mainWidget ()); m_settingsLayout = new QVBoxLayout ( m_settingsGroupBox ); addCustomWidgetToBack (m_settingsGroupBox); connect (m_effectsComboBox, static_cast(&QComboBox::activated), this, &kpEffectsDialog::selectEffect); selectEffect (defaultSelectedEffect); resize (s_lastWidth, s_lastHeight); qCDebug(kpLogDialogs) << "about to setUpdatesEnabled()"; // OPT: The preview pixmap gets recalculated here and then possibly // again when QResizeEvent fires, when the dialog is shown. setUpdatesEnabled (e); } kpEffectsDialog::~kpEffectsDialog () { s_lastWidth = width (); s_lastHeight = height (); } // public virtual [base kpTransformPreviewDialog] bool kpEffectsDialog::isNoOp () const { - if (!m_effectWidget) + if (!m_effectWidget) { return true; + } return m_effectWidget->isNoOp (); } // public kpEffectCommandBase *kpEffectsDialog::createCommand () const { - if (!m_effectWidget) + if (!m_effectWidget) { return nullptr; + } return m_effectWidget->createCommand (m_environ->commandEnvironment ()); } // protected virtual [base kpTransformPreviewDialog] QSize kpEffectsDialog::newDimensions () const { kpDocument *doc = document (); - if (!doc) - return QSize (); + if (!doc) { + return {}; + } - return QSize (doc->width (m_actOnSelection), - doc->height (m_actOnSelection)); + return {doc->width (m_actOnSelection), doc->height (m_actOnSelection)}; } // protected virtual [base kpTransformPreviewDialog] QImage kpEffectsDialog::transformPixmap (const QImage &pixmap, int targetWidth, int targetHeight) const { QImage pixmapWithEffect; - if (m_effectWidget && !m_effectWidget->isNoOp ()) + if (m_effectWidget && !m_effectWidget->isNoOp ()) { pixmapWithEffect = m_effectWidget->applyEffect (pixmap); - else + } + else { pixmapWithEffect = pixmap; + } return kpPixmapFX::scale (pixmapWithEffect, targetWidth, targetHeight); } // public int kpEffectsDialog::selectedEffect () const { return m_effectsComboBox->currentIndex (); } // public slot void kpEffectsDialog::selectEffect (int which) { #if DEBUG_KP_EFFECTS_DIALOG qCDebug(kpLogDialogs) << "kpEffectsDialog::selectEffect(" << which << ")"; #endif if (which < 0 || which >= m_effectsComboBox->count ()) { return; } - if (which != m_effectsComboBox->currentIndex ()) + if (which != m_effectsComboBox->currentIndex ()) { m_effectsComboBox->setCurrentIndex (which); + } delete m_effectWidget; m_effectWidget = nullptr; m_settingsGroupBox->setWindowTitle(QString()); #define CREATE_EFFECT_WIDGET(name) \ m_effectWidget = new name (m_actOnSelection, m_settingsGroupBox) // sync: order in constructor. switch (which) { case 0: CREATE_EFFECT_WIDGET (kpEffectBalanceWidget); break; case 1: CREATE_EFFECT_WIDGET (kpEffectEmbossWidget); break; case 2: CREATE_EFFECT_WIDGET (kpEffectFlattenWidget); break; case 3: CREATE_EFFECT_WIDGET (kpEffectToneEnhanceWidget); break; case 4: CREATE_EFFECT_WIDGET (kpEffectHSVWidget); break; case 5: CREATE_EFFECT_WIDGET (kpEffectInvertWidget); break; case 6: CREATE_EFFECT_WIDGET (kpEffectReduceColorsWidget); break; case 7: CREATE_EFFECT_WIDGET (kpEffectBlurSharpenWidget); break; } #undef CREATE_EFFECT_WIDGET if (m_effectWidget) { const bool e = updatesEnabled (); setUpdatesEnabled (false); qCDebug(kpLogDialogs) << "widget exists for effect #"; m_settingsGroupBox->setTitle (m_effectWidget->caption ()); // Show widget. // // Don't resize the whole dialog when doing this. // This seems to work magically without any extra code with Qt4. qCDebug(kpLogDialogs) << "addWidget"; m_settingsLayout->addWidget (m_effectWidget); qCDebug(kpLogDialogs) << "show widget"; m_effectWidget->show (); connect (m_effectWidget, &kpEffectWidgetBase::settingsChangedNoWaitCursor, this, &kpEffectsDialog::slotUpdate); connect (m_effectWidget, &kpEffectWidgetBase::settingsChanged, this, &kpEffectsDialog::slotUpdateWithWaitCursor); connect (m_effectWidget, &kpEffectWidgetBase::settingsChangedDelayed, this, &kpEffectsDialog::slotDelayedUpdate); qCDebug(kpLogDialogs) << "about to setUpdatesEnabled()"; setUpdatesEnabled (e); } qCDebug(kpLogDialogs) << "done"; } // protected slot virtual [base kpTransformPreviewDialog] void kpEffectsDialog::slotUpdate () { qCDebug(kpLogDialogs) << "kpEffectsDialog::slotUpdate()" << " timerActive=" << m_delayedUpdateTimer->isActive (); m_delayedUpdateTimer->stop (); kpTransformPreviewDialog::slotUpdate (); } // protected slot virtual [base kpTransformPreviewDialog] void kpEffectsDialog::slotUpdateWithWaitCursor () { qCDebug(kpLogDialogs) << "kpEffectsDialog::slotUpdateWithWaitCursor()" << " timerActive=" << m_delayedUpdateTimer->isActive (); m_delayedUpdateTimer->stop (); kpTransformPreviewDialog::slotUpdateWithWaitCursor (); } // protected slot void kpEffectsDialog::slotDelayedUpdate () { qCDebug(kpLogDialogs) << "kpEffectsDialog::slotDelayedUpdate()" << " timerActive=" << m_delayedUpdateTimer->isActive (); m_delayedUpdateTimer->stop (); // (single shot) m_delayedUpdateTimer->start (400/*ms*/); } diff --git a/dialogs/imagelib/kpDocumentMetaInfoDialog.cpp b/dialogs/imagelib/kpDocumentMetaInfoDialog.cpp index 997cc2c0..5c8c3f0a 100644 --- a/dialogs/imagelib/kpDocumentMetaInfoDialog.cpp +++ b/dialogs/imagelib/kpDocumentMetaInfoDialog.cpp @@ -1,714 +1,716 @@ /* Copyright (c) 2003-2007 Clarence Dang All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #define DEBUG_KP_DOCUMENT_META_INFO_DIALOG 0 #include "kpDocumentMetaInfoDialog.h" #include "kpDefs.h" #include "imagelib/kpDocumentMetaInfo.h" #include #include #include "kpLogCategories.h" #include #include #include #include #include #include #include #include #include #include struct kpDocumentMetaInfoDialogPrivate { const kpDocumentMetaInfo *originalMetaInfoPtr; QDoubleSpinBox *horizDpiInput, *vertDpiInput; QSpinBox *horizOffsetInput, *vertOffsetInput; QTableWidget *fieldsTableWidget; QPushButton *fieldsAddRowButton, *fieldsDeleteRowButton, *fieldsResetButton; }; // (shared by all dialogs, across all main windows, in a KolourPaint instance) static int LastWidth = -1, LastHeight = -1; // sync: You must keep DpiMinStep = 10 ^ (-DpiPrecision). // // You can increase the precision to reduce the chance of inadvertently changing // the resolution when converting from kpDocumentMetaInfo's "dots per meter" // to our "dots per inch" and back. It would be bad if simply going into this // dialog and pressing OK changed the resolution (it's unlikely but I still think // it might happen with the current precision). // TODO: On a related note, for many particular resolutions, if the user enters // one of them into the UI, presses OK and then comes back to the dialog, // s/he is presented with a different resolution to the one typed in. // Maybe make DotsPerMeter[XY] be of type "double" instead of "int" to // solve this problem? // // Of course, if you increase the precision too much, the minimum step will // become so small that it will start experiencing floating point inaccuracies // esp. since we use it for the "DpiUnspecified" hack. static const int DpiPrecision = 3; static const double DpiMinStep = 0.001; static const double DpiLegalMin = kpDocumentMetaInfo::MinDotsPerMeter / KP_INCHES_PER_METER; // Out of range represents unspecified DPI. static const double DpiUnspecified = ::DpiLegalMin - ::DpiMinStep; static const double DpiInputMin = ::DpiUnspecified; static const double DpiInputMax = kpDocumentMetaInfo::MaxDotsPerMeter / KP_INCHES_PER_METER; // The increment the DPI spinboxes jump by when they're clicked. // // We make this relatively big since people don't usually just increase their // DPIs by 1 or so -- they are usually changing from say, 72, to 96. // // Obviously, making it equal to DpiMinStep is too slow a UI. Therefore, with // our big setting, the user will still have to manually change the value in // the spinbox, using the keyboard, after all their clicking to ensure it is // exactly the value they want. static const double DpiInputStep = 10; // TODO: Halve groupbox layout margins in every other file since it doesn't // seem to be need in Qt4. kpDocumentMetaInfoDialog::kpDocumentMetaInfoDialog ( const kpDocumentMetaInfo *docMetaInfo, QWidget *parent) : QDialog (parent), d (new kpDocumentMetaInfoDialogPrivate ()) { d->originalMetaInfoPtr = docMetaInfo; setWindowTitle (i18nc ("@title:window", "Document Properties")); - QDialogButtonBox * buttons = new QDialogButtonBox (QDialogButtonBox::Ok | + auto * buttons = new QDialogButtonBox (QDialogButtonBox::Ok | QDialogButtonBox::Cancel, this); connect (buttons, &QDialogButtonBox::accepted, this, &kpDocumentMetaInfoDialog::accept); connect (buttons, &QDialogButtonBox::rejected, this, &kpDocumentMetaInfoDialog::reject); - QWidget *baseWidget = new QWidget (this); + auto *baseWidget = new QWidget (this); - QVBoxLayout *dialogLayout = new QVBoxLayout (this); + auto *dialogLayout = new QVBoxLayout (this); dialogLayout->addWidget (baseWidget); dialogLayout->addWidget (buttons); // // DPI Group Box // Q_ASSERT (::DpiInputMin < ::DpiInputMax); - QGroupBox *dpiGroupBox = new QGroupBox(i18n("Dots &Per Inch (DPI)"), baseWidget); + auto *dpiGroupBox = new QGroupBox(i18n("Dots &Per Inch (DPI)"), baseWidget); d->horizDpiInput = new QDoubleSpinBox(dpiGroupBox); d->horizDpiInput->setRange(::DpiInputMin, ::DpiInputMax); d->horizDpiInput->setValue(0.0); d->horizDpiInput->setSingleStep(::DpiInputStep); d->horizDpiInput->setDecimals(::DpiPrecision); d->horizDpiInput->setSpecialValueText(i18n("Unspecified")); - QLabel *dpiXLabel = new QLabel ( + auto *dpiXLabel = new QLabel ( i18nc ("Horizontal DPI 'x' Vertical DPI", " x "), dpiGroupBox); dpiXLabel->setAlignment (Qt::AlignCenter); d->vertDpiInput = new QDoubleSpinBox(dpiGroupBox); d->vertDpiInput->setRange(::DpiInputMin, ::DpiInputMax); d->vertDpiInput->setValue(0.0); d->vertDpiInput->setSingleStep(::DpiInputStep); d->vertDpiInput->setDecimals(::DpiPrecision); d->vertDpiInput->setSpecialValueText(i18n("Unspecified")); - QGridLayout *dpiLay = new QGridLayout(dpiGroupBox); + auto *dpiLay = new QGridLayout(dpiGroupBox); dpiLay->addWidget(new QLabel(i18n("Horizontal:")), 0, 0, Qt::AlignHCenter); dpiLay->addWidget(d->horizDpiInput, 1, 0); dpiLay->addWidget(dpiXLabel, 0, 1); dpiLay->addWidget(new QLabel(i18n("Vertical:")), 0, 2, Qt::AlignHCenter); dpiLay->addWidget(d->vertDpiInput, 1, 2); dpiLay->setRowStretch(2, 1); dpiGroupBox->setWhatsThis ( i18n ( "" "

Dots Per Inch (DPI) specifies the number of pixels" " of the image that should be printed inside one inch (2.54cm).

" "

The higher the image's DPI, the smaller the printed image." " Note that your printer is unlikely to produce high" " quality prints if you increase this to more than 300 or 600 DPI," " depending on the printer.

" "

If you would like to print the image so that it is the same" " size as it is displayed on the screen, set the image's DPI" " values to be the same as the screen's.

" // TODO: This is currently not true! // See "96dpi" TODO in kpMainWindow::sendPixmapToPrinter(). // This also why we don't try to report the current screen DPI // for the above paragraph. "

If either DPI value is Unspecified, the image will also" " be printed to be the same size as on the screen.

" "

Not all image formats support DPI values. If the format you" " save in does not support them, they will not be saved.

" "
" )); // // Offset Group Box // - QGroupBox *offsetGroupBox = new QGroupBox(i18n ("O&ffset"), baseWidget); + auto *offsetGroupBox = new QGroupBox(i18n ("O&ffset"), baseWidget); d->horizOffsetInput = new QSpinBox; d->horizOffsetInput->setRange(kpDocumentMetaInfo::MinOffset, kpDocumentMetaInfo::MaxOffset); d->vertOffsetInput = new QSpinBox; d->vertOffsetInput->setRange(kpDocumentMetaInfo::MinOffset, kpDocumentMetaInfo::MaxOffset); - QGridLayout *offsetLay = new QGridLayout(offsetGroupBox); + auto *offsetLay = new QGridLayout(offsetGroupBox); offsetLay->addWidget(new QLabel(i18n("Horizontal:")), 0, 0, Qt::AlignHCenter); offsetLay->addWidget(d->horizOffsetInput, 1, 0); offsetLay->addWidget(new QLabel(i18n("Vertical:")), 0, 1, Qt::AlignHCenter); offsetLay->addWidget(d->vertOffsetInput, 1, 1); offsetLay->setRowStretch (2, 1); offsetGroupBox->setWhatsThis ( i18n ( "" "

The Offset is the relative position where this image" " should be placed, compared to other images.

" "

Not all image formats support the Offset feature." " If the format you save in does not support it, the values" " specified here will not be saved.

" "
" )); // // Fields Group Box // - QGroupBox *fieldsGroupBox = new QGroupBox (i18n ("&Text Fields"), + auto *fieldsGroupBox = new QGroupBox (i18n ("&Text Fields"), baseWidget); d->fieldsTableWidget = new QTableWidget (fieldsGroupBox); d->fieldsTableWidget->setEditTriggers(QAbstractItemView::AllEditTriggers); connect (d->fieldsTableWidget, &QTableWidget::currentCellChanged, this, &kpDocumentMetaInfoDialog::slotFieldsCurrentCellChanged); connect (d->fieldsTableWidget, &QTableWidget::itemChanged, this, &kpDocumentMetaInfoDialog::slotFieldsItemChanged); d->fieldsAddRowButton = new QPushButton (i18n ("&Add Row"), fieldsGroupBox); connect (d->fieldsAddRowButton, &QPushButton::clicked, this, &kpDocumentMetaInfoDialog::slotFieldsAddRowButtonClicked); d->fieldsDeleteRowButton = new QPushButton (i18n ("&Delete Row"), fieldsGroupBox); connect (d->fieldsDeleteRowButton, &QPushButton::clicked, this, &kpDocumentMetaInfoDialog::slotFieldsDeleteRowButtonClicked); d->fieldsResetButton = new QPushButton (i18n ("&Reset"), fieldsGroupBox); connect (d->fieldsResetButton, &QPushButton::clicked, this, &kpDocumentMetaInfoDialog::setUIToOriginalMetaInfo); - QHBoxLayout *fieldsButtonsLayout = new QHBoxLayout (); + auto *fieldsButtonsLayout = new QHBoxLayout (); fieldsButtonsLayout->addWidget (d->fieldsAddRowButton); fieldsButtonsLayout->addWidget (d->fieldsDeleteRowButton); fieldsButtonsLayout->addStretch (); fieldsButtonsLayout->addWidget (d->fieldsResetButton); - QVBoxLayout *fieldsLayout = new QVBoxLayout (fieldsGroupBox); + auto *fieldsLayout = new QVBoxLayout (fieldsGroupBox); fieldsLayout->addWidget (d->fieldsTableWidget); fieldsLayout->addLayout (fieldsButtonsLayout); fieldsGroupBox->setWhatsThis ( i18n ( "" "

Text Fields provide extra information about the image." " This is probably a comment area that you can freely write any text in.

" "

However, this is format-specific so the fields could theoretically be" " computer-interpreted data - that you should not modify -" " but this is unlikely.

" "

Not all image formats support Text Fields. If the format" " you save in does not support them, they will not be saved.

" "
" )); // // Global Layout // - - - QGridLayout *baseLayout = new QGridLayout (baseWidget); + auto *baseLayout = new QGridLayout (baseWidget); baseLayout->setContentsMargins(0, 0, 0, 0); // Col 0 baseLayout->addWidget (dpiGroupBox, 0, 0); baseLayout->addWidget (offsetGroupBox, 1, 0); // Col 1 baseLayout->addWidget (fieldsGroupBox, 0, 1, 2/*row span*/, 1/*col span*/); baseLayout->setColumnStretch (1, 1/*stretch*/); // // Remaining UI Setup // setUIToOriginalMetaInfo (); - if (::LastWidth > 0 && ::LastHeight > 0) + if (::LastWidth > 0 && ::LastHeight > 0) { resize (::LastWidth, ::LastHeight); + } } //--------------------------------------------------------------------- kpDocumentMetaInfoDialog::~kpDocumentMetaInfoDialog () { ::LastWidth = width (); ::LastHeight = height (); delete d; } //--------------------------------------------------------------------- // private void kpDocumentMetaInfoDialog::editCell (int r, int c) { d->fieldsTableWidget->setCurrentCell (r, c); d->fieldsTableWidget->editItem (d->fieldsTableWidget->item (r, c)); } //--------------------------------------------------------------------- // private slot void kpDocumentMetaInfoDialog::setUIToOriginalMetaInfo () { // Set DPI spinboxes. d->horizDpiInput->setValue (d->originalMetaInfoPtr->dotsPerMeterX () / KP_INCHES_PER_METER); d->vertDpiInput->setValue (d->originalMetaInfoPtr->dotsPerMeterY () / KP_INCHES_PER_METER); // Set Offset spinboxes. d->horizOffsetInput->setValue (d->originalMetaInfoPtr->offset ().x ()); d->vertOffsetInput->setValue (d->originalMetaInfoPtr->offset ().y ()); // Set Text Fields. // // Block itemChanged() signal as slotFieldsItemChanged() should not get called // when rows are half-created. const bool b = d->fieldsTableWidget->blockSignals (true); { d->fieldsTableWidget->clear (); d->fieldsTableWidget->setRowCount (d->originalMetaInfoPtr->textKeys ().size ()); d->fieldsTableWidget->setColumnCount (2); QStringList fieldsHeader; fieldsHeader << i18n ("Key") << i18n ("Value"); d->fieldsTableWidget->setHorizontalHeaderLabels (fieldsHeader); int row = 0; - foreach (const QString &key, d->originalMetaInfoPtr->textKeys ()) + for (const auto &key : d->originalMetaInfoPtr->textKeys ()) { d->fieldsTableWidget->setItem (row, 0/*1st col*/, new QTableWidgetItem (key)); d->fieldsTableWidget->setItem (row, 1/*2nd col*/, new QTableWidgetItem (d->originalMetaInfoPtr->text (key))); row++; } fieldsAppendEmptyRow (); } d->fieldsTableWidget->blockSignals (b); editCell (0/*row*/, 0/*col*/); enableFieldsDeleteRowButtonIfShould (); } //--------------------------------------------------------------------- // public bool kpDocumentMetaInfoDialog::isNoOp () const { return (metaInfo () == *d->originalMetaInfoPtr); } //--------------------------------------------------------------------- // public kpDocumentMetaInfo kpDocumentMetaInfoDialog::originalMetaInfo () const { return *d->originalMetaInfoPtr; } // public kpDocumentMetaInfo kpDocumentMetaInfoDialog::metaInfo ( QString *errorMessage) const { if (errorMessage) { // No errors to start with. *errorMessage = QString (); } kpDocumentMetaInfo ret; - if (d->horizDpiInput->value () < ::DpiLegalMin) + if (d->horizDpiInput->value () < ::DpiLegalMin) { ret.setDotsPerMeterX (0/*unspecified*/); - else + } + else { ret.setDotsPerMeterX (qRound (d->horizDpiInput->value () * KP_INCHES_PER_METER)); + } - if (d->vertDpiInput->value () < ::DpiLegalMin) + if (d->vertDpiInput->value () < ::DpiLegalMin) { ret.setDotsPerMeterY (0/*unspecified*/); - else + } + else { ret.setDotsPerMeterY (qRound (d->vertDpiInput->value () * KP_INCHES_PER_METER)); + } ret.setOffset (QPoint (d->horizOffsetInput->value (), d->vertOffsetInput->value ())); for (int r = 0; r < d->fieldsTableWidget->rowCount (); r++) { const QString key = d->fieldsTableWidget->item (r, 0)->text (); const QString value = d->fieldsTableWidget->item (r, 1)->text (); // Empty key? if (key.isEmpty ()) { // Empty value too? if (value.isEmpty ()) { // Ignore empty row. continue; } // Value without a key? - else + + + if (errorMessage) { - if (errorMessage) - { - *errorMessage = + *errorMessage = ki18n ("The text value \"%1\" on line %2 requires a key.") - .subs (value).subs (r + 1/*count from 1*/).toString (); - - // Print only 1 error message per method invocation. - errorMessage = nullptr; - } + .subs (value).subs (r + 1/*count from 1*/).toString (); - // Ignore. - continue; + // Print only 1 error message per method invocation. + errorMessage = nullptr; } + + // Ignore. + continue; + } // Duplicate key? if (ret.textKeys ().contains (key)) { if (errorMessage) { int q; for (q = 0; q < r; q++) { - if (d->fieldsTableWidget->item (q, 0)->text () == key) + if (d->fieldsTableWidget->item (q, 0)->text () == key) { break; + } } Q_ASSERT (q != r); *errorMessage = ki18n ("All text keys must be unique. The text key \"%1\"" " on lines %2 and %3 are identical.") .subs (key) .subs (q + 1/*count from 1*/) .subs (r + 1/*count from 1*/) .toString (); // Print only 1 error message per method invocation. errorMessage = nullptr; } // Ignore this duplicate - keep the first value of the key. continue; } ret.setText (key, value); } // for (r = 0; r < table widget rows; r++) { return ret; } // private void kpDocumentMetaInfoDialog::fieldsUpdateVerticalHeader () { QStringList vertLabels; - for (int r = 1; r <= d->fieldsTableWidget->rowCount (); r++) + for (int r = 1; r <= d->fieldsTableWidget->rowCount (); r++) { vertLabels << QString::number (r); + } d->fieldsTableWidget->setVerticalHeaderLabels (vertLabels); } // private void kpDocumentMetaInfoDialog::fieldsAddEmptyRow (int atRow) { // Block itemChanged() signal as slotFieldsItemChanged() should not get called // when rows are half-created. const bool b = d->fieldsTableWidget->blockSignals (true); { d->fieldsTableWidget->insertRow (atRow); d->fieldsTableWidget->setItem (atRow, 0, new QTableWidgetItem (QString ())); d->fieldsTableWidget->setItem (atRow, 1, new QTableWidgetItem (QString ())); } d->fieldsTableWidget->blockSignals (b); // Hack around Qt's failure to redraw these sometimes. fieldsUpdateVerticalHeader (); enableFieldsDeleteRowButtonIfShould (); } // private void kpDocumentMetaInfoDialog::fieldsAppendEmptyRow () { fieldsAddEmptyRow (d->fieldsTableWidget->rowCount ()); } // private bool kpDocumentMetaInfoDialog::isFieldsRowDeleteable (int row) const { // Can't delete no row and can't delete last (always blank) row, which // is used to make it easy for the user to add rows without pressing // the "Add" button explicitly. return (row >= 0 && row < d->fieldsTableWidget->rowCount () - 1); } // private void kpDocumentMetaInfoDialog::fieldsDeleteRow (int r) { qCDebug(kpLogDialogs) << "kpDocumentMetaInfoDialog::fieldsDeleteRow(" << "row=" << r << ")" - << " currentRow=" << d->fieldsTableWidget->currentRow () << endl; + << " currentRow=" << d->fieldsTableWidget->currentRow (); Q_ASSERT (isFieldsRowDeleteable (r)); if (r == d->fieldsTableWidget->currentRow ()) { // Assertion follows from previous assertion. const int newRow = r + 1; qCDebug(kpLogDialogs) << "\tnewRow=" << newRow; Q_ASSERT (newRow < d->fieldsTableWidget->rowCount ()); int newCol = d->fieldsTableWidget->currentColumn (); qCDebug(kpLogDialogs) << "\tnewCol=" << newCol; if (newCol != 0 && newCol != 1) { newCol = 0; qCDebug(kpLogDialogs) << "\t\tcorrecting to " << newCol; } // WARNING: You must call this _before_ deleting the row. Else, you'll // trigger a Qt bug where if the editor is active on the row to // be deleted, it might crash. To reproduce, move this line to // after removeRow() (and subtract 1 from newRow) and // press the "Delete Row" button several times in succession // very quickly. // // TODO: This usually results in a redraw error if the scrollbar scrolls // after deleting the 2nd last row. Qt bug. editCell (newRow, newCol); } d->fieldsTableWidget->removeRow (r); fieldsUpdateVerticalHeader (); enableFieldsDeleteRowButtonIfShould (); } // private void kpDocumentMetaInfoDialog::enableFieldsDeleteRowButtonIfShould () { qCDebug(kpLogDialogs) << "kpDocumentMetaInfoDialog::enableFieldsDeleteRowButtonIfShould()"; const int r = d->fieldsTableWidget->currentRow (); qCDebug(kpLogDialogs) << "\tr=" << r; d->fieldsDeleteRowButton->setEnabled (isFieldsRowDeleteable (r)); } // private slot void kpDocumentMetaInfoDialog::slotFieldsCurrentCellChanged (int row, int col, int oldRow, int oldCol) { qCDebug(kpLogDialogs) << "kpDocumentMetaInfoDialog::slotFieldsCurrentCellChanged(" << "row=" << row << ",col=" << col << ",oldRow=" << oldRow << ",oldCol=" << oldCol << ")"; enableFieldsDeleteRowButtonIfShould (); } //--------------------------------------------------------------------- // private slot void kpDocumentMetaInfoDialog::slotFieldsItemChanged (QTableWidgetItem *it) { qCDebug(kpLogDialogs) << "kpDocumentMetaInfoDialog::slotFieldsItemChanged(" - << "item=" << it << ") rows=" << d->fieldsTableWidget->rowCount () - << endl; + << "item=" << it << ") rows=" << d->fieldsTableWidget->rowCount (); const int r = d->fieldsTableWidget->row (it); qCDebug(kpLogDialogs) << "\tr=" << r; Q_ASSERT (r >= 0 && r < d->fieldsTableWidget->rowCount ()); const QString key = d->fieldsTableWidget->item (r, 0)->text (); qCDebug(kpLogDialogs) << " key='" << key << "'"; const QString value = d->fieldsTableWidget->item (r, 1)->text (); qCDebug(kpLogDialogs) << " value='" << value << "'"; // At the last row? if (r == d->fieldsTableWidget->rowCount () - 1) { // Typed some text? if (!key.isEmpty () || !value.isEmpty ()) { // LOTODO: If we're called due to the cell's text being finalized // as a result of the user pressing the "Add Row" button, // should this really append a row since // slotFieldsAddRowButtonClicked() button is going to add // another one? That's two rows when the user only clicked // that button once! fieldsAppendEmptyRow (); } } } //--------------------------------------------------------------------- // private slot void kpDocumentMetaInfoDialog::slotFieldsAddRowButtonClicked () { - qCDebug(kpLogDialogs) << "kpDocumentMetaInfoDialog::slotFieldsAddRowButtonClicked()" - << endl; + qCDebug(kpLogDialogs) << "kpDocumentMetaInfoDialog::slotFieldsAddRowButtonClicked()"; const int r = d->fieldsTableWidget->currentRow (); qCDebug(kpLogDialogs) << "\tr=" << r; // (if no row is selected, r = -1) fieldsAddEmptyRow (r + 1); // Edit the key of this new row (column 0). // No one edits the value first (column 1). editCell ((r + 1)/*row*/, 0/*col*/); } //--------------------------------------------------------------------- // private slot void kpDocumentMetaInfoDialog::slotFieldsDeleteRowButtonClicked () { - qCDebug(kpLogDialogs) << "kpDocumentMetaInfoDialog::slotFieldsDeleteRowButtonClicked()" - << endl; + qCDebug(kpLogDialogs) << "kpDocumentMetaInfoDialog::slotFieldsDeleteRowButtonClicked()"; const int r = d->fieldsTableWidget->currentRow (); qCDebug(kpLogDialogs) << "\tr=" << r; Q_ASSERT (isFieldsRowDeleteable (r)); fieldsDeleteRow (r); } // private slot virtual [base QDialog] void kpDocumentMetaInfoDialog::accept () { // Validate text fields. QString errorMessage; (void) metaInfo (&errorMessage); if (!errorMessage.isEmpty ()) { KMessageBox::sorry (this, errorMessage, i18nc ("@title:window", "Invalid Text Fields")); return; } QDialog::accept (); } diff --git a/dialogs/imagelib/transforms/kpTransformPreviewDialog.cpp b/dialogs/imagelib/transforms/kpTransformPreviewDialog.cpp index 730c0494..48359fb9 100644 --- a/dialogs/imagelib/transforms/kpTransformPreviewDialog.cpp +++ b/dialogs/imagelib/transforms/kpTransformPreviewDialog.cpp @@ -1,432 +1,440 @@ /* Copyright (c) 2003-2007 Clarence Dang All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #define DEBUG_KP_TRANSFORM_PREVIEW_DIALOG 0 #include "dialogs/imagelib/transforms/kpTransformPreviewDialog.h" #include #include #include #include #include #include #include #include #include #include "kpLogCategories.h" #include #include "layers/selections/image/kpAbstractImageSelection.h" #include "imagelib/kpColor.h" #include "document/kpDocument.h" #include "pixmapfx/kpPixmapFX.h" #include "generic/widgets/kpResizeSignallingLabel.h" #include "environments/dialogs/imagelib/transforms/kpTransformDialogEnvironment.h" kpTransformPreviewDialog::kpTransformPreviewDialog (Features features, bool reserveTopRow, const QString &caption, const QString &afterActionText, bool actOnSelection, kpTransformDialogEnvironment *_env, QWidget *parent) : QDialog (parent), m_afterActionText (afterActionText), m_actOnSelection (actOnSelection), m_dimensionsGroupBox (nullptr), m_afterTransformDimensionsLabel (nullptr), m_previewGroupBox (nullptr), m_previewPixmapLabel (nullptr), m_gridLayout (nullptr), m_environ (_env) { setWindowTitle (caption); QDialogButtonBox *buttons = new QDialogButtonBox (QDialogButtonBox::Ok | QDialogButtonBox::Cancel, this); connect (buttons, &QDialogButtonBox::accepted, this, &kpTransformPreviewDialog::accept); connect (buttons, &QDialogButtonBox::rejected, this, &kpTransformPreviewDialog::reject); QWidget *baseWidget = new QWidget (this); m_mainWidget = baseWidget; - QVBoxLayout *dialogLayout = new QVBoxLayout (this); + auto *dialogLayout = new QVBoxLayout (this); dialogLayout->addWidget (baseWidget); dialogLayout->addWidget (buttons); if (document ()) { m_oldWidth = document ()->width (actOnSelection); m_oldHeight = document ()->height (actOnSelection); } else { m_oldWidth = m_oldHeight = 1; } - if (features & Dimensions) + if (features & Dimensions) { createDimensionsGroupBox (); + } - if (features & Preview) + if (features & Preview) { createPreviewGroupBox (); + } m_gridLayout = new QGridLayout (baseWidget ); m_gridLayout->setContentsMargins(0, 0, 0, 0); m_gridNumRows = reserveTopRow ? 1 : 0; if (m_dimensionsGroupBox || m_previewGroupBox) { if (m_dimensionsGroupBox && m_previewGroupBox) { m_gridLayout->addWidget (m_dimensionsGroupBox, m_gridNumRows, 0); m_gridLayout->addWidget (m_previewGroupBox, m_gridNumRows, 1); m_gridLayout->setColumnStretch (1, 1); } else if (m_dimensionsGroupBox) { m_gridLayout->addWidget (m_dimensionsGroupBox, m_gridNumRows, 0, 1, 2); } else if (m_previewGroupBox) { m_gridLayout->addWidget (m_previewGroupBox, m_gridNumRows, 0, 1, 2); } m_gridLayout->setRowStretch (m_gridNumRows, 1); - m_gridNumRows++;; + m_gridNumRows++; } } -kpTransformPreviewDialog::~kpTransformPreviewDialog () -{ -} +kpTransformPreviewDialog::~kpTransformPreviewDialog () = default; // private void kpTransformPreviewDialog::createDimensionsGroupBox () { m_dimensionsGroupBox = new QGroupBox (i18n ("Dimensions"), mainWidget ()); - QLabel *originalLabel = new QLabel (i18n ("Original:"), m_dimensionsGroupBox); + auto *originalLabel = new QLabel (i18n ("Original:"), m_dimensionsGroupBox); QString originalDimensions; if (document ()) { originalDimensions = i18n ("%1 x %2", m_oldWidth, m_oldHeight); // Stop the Dimensions Group Box from resizing so often const QString minimumLengthString ("100000 x 100000"); const int padLength = minimumLengthString.length (); - for (int i = originalDimensions.length (); i < padLength; i++) + for (int i = originalDimensions.length (); i < padLength; i++) { originalDimensions += ' '; + } } - QLabel *originalDimensionsLabel = new QLabel (originalDimensions, m_dimensionsGroupBox); + auto *originalDimensionsLabel = new QLabel (originalDimensions, m_dimensionsGroupBox); - QLabel *afterTransformLabel = new QLabel (m_afterActionText, m_dimensionsGroupBox); + auto *afterTransformLabel = new QLabel (m_afterActionText, m_dimensionsGroupBox); m_afterTransformDimensionsLabel = new QLabel (m_dimensionsGroupBox); - QGridLayout *dimensionsLayout = new QGridLayout (m_dimensionsGroupBox ); + auto *dimensionsLayout = new QGridLayout (m_dimensionsGroupBox ); dimensionsLayout->addWidget (originalLabel, 0, 0, Qt::AlignBottom); dimensionsLayout->addWidget (originalDimensionsLabel, 0, 1, Qt::AlignBottom); dimensionsLayout->addWidget (afterTransformLabel, 1, 0, Qt::AlignTop); dimensionsLayout->addWidget (m_afterTransformDimensionsLabel, 1, 1, Qt::AlignTop); } // private void kpTransformPreviewDialog::createPreviewGroupBox () { m_previewGroupBox = new QGroupBox (i18n ("Preview"), mainWidget ()); m_previewPixmapLabel = new kpResizeSignallingLabel (m_previewGroupBox); m_previewPixmapLabel->setMinimumSize (150, 110); connect (m_previewPixmapLabel, &kpResizeSignallingLabel::resized, this, &kpTransformPreviewDialog::updatePreview); QPushButton *updatePushButton = new QPushButton (i18n ("&Update"), m_previewGroupBox); connect (updatePushButton, &QPushButton::clicked, this, &kpTransformPreviewDialog::slotUpdateWithWaitCursor); - QVBoxLayout *previewLayout = new QVBoxLayout (m_previewGroupBox); + auto *previewLayout = new QVBoxLayout (m_previewGroupBox); previewLayout->addWidget (m_previewPixmapLabel, 1/*stretch*/); previewLayout->addWidget (updatePushButton, 0/*stretch*/, Qt::AlignHCenter); } // protected kpDocument *kpTransformPreviewDialog::document () const { return m_environ->document (); } // protected QWidget *kpTransformPreviewDialog::mainWidget () const { return m_mainWidget; } // protected void kpTransformPreviewDialog::addCustomWidgetToFront (QWidget *w) { m_gridLayout->addWidget (w, 0, 0, 1, 2); } // protected void kpTransformPreviewDialog::addCustomWidget (QWidget *w) { m_gridLayout->addWidget (w, m_gridNumRows, 0, 1, 2); m_gridNumRows++; } // public override [base QWidget] void kpTransformPreviewDialog::setUpdatesEnabled (bool enable) { QDialog::setUpdatesEnabled (enable); - if (enable) + if (enable) { slotUpdateWithWaitCursor (); + } } // private void kpTransformPreviewDialog::updateDimensions () { - if (!m_dimensionsGroupBox) + if (!m_dimensionsGroupBox) { return; + } kpDocument *doc = document (); - if (!doc) + if (!doc) { return; + } if (!updatesEnabled ()) { qCDebug(kpLogDialogs) << "updates not enabled - aborting"; return; } QSize newDim = newDimensions (); qCDebug(kpLogDialogs) << "kpTransformPreviewDialog::updateDimensions(): newDim=" << newDim; QString newDimString = i18n ("%1 x %2", newDim.width (), newDim.height ()); m_afterTransformDimensionsLabel->setText (newDimString); } // public static double kpTransformPreviewDialog::aspectScale (int newWidth, int newHeight, int oldWidth, int oldHeight) { double widthScale = double (newWidth) / double (oldWidth); double heightScale = double (newHeight) / double (oldHeight); // Keeps aspect ratio return qMin (widthScale, heightScale); } // public static int kpTransformPreviewDialog::scaleDimension (int dimension, double scale, int min, int max) { return qMax (min, qMin (max, qRound (dimension * scale))); } // private void kpTransformPreviewDialog::updateShrunkenDocumentPixmap () { qCDebug(kpLogDialogs) << "kpTransformPreviewDialog::updateShrunkenDocumentPixmap()" << " shrunkenDocPixmap.size=" << m_shrunkenDocumentPixmap.size () << " previewPixmapLabelSizeWhenUpdatedPixmap=" << m_previewPixmapLabelSizeWhenUpdatedPixmap << " previewPixmapLabel.size=" << m_previewPixmapLabel->size (); - if (!m_previewGroupBox) + if (!m_previewGroupBox) { return; + } kpDocument *doc = document (); Q_ASSERT (doc && !doc->image ().isNull ()); if (m_shrunkenDocumentPixmap.isNull () || m_previewPixmapLabel->size () != m_previewPixmapLabelSizeWhenUpdatedPixmap) { qCDebug(kpLogDialogs) << "\tupdating shrunkenDocPixmap"; // TODO: Why the need to keep aspect ratio here? // Isn't scaling the skewed result maintaining aspect enough? double keepsAspectScale = aspectScale (m_previewPixmapLabel->width (), m_previewPixmapLabel->height (), m_oldWidth, m_oldHeight); kpImage image; if (m_actOnSelection) { kpAbstractImageSelection *sel = doc->imageSelection ()->clone (); - if (!sel->hasContent ()) + if (!sel->hasContent ()) { sel->setBaseImage (doc->getSelectedBaseImage ()); + } image = sel->transparentImage (); delete sel; } else { image = doc->image (); } m_shrunkenDocumentPixmap = kpPixmapFX::scale ( image, scaleDimension (m_oldWidth, keepsAspectScale, 1, m_previewPixmapLabel->width ()), scaleDimension (m_oldHeight, keepsAspectScale, 1, m_previewPixmapLabel->height ())); m_previewPixmapLabelSizeWhenUpdatedPixmap = m_previewPixmapLabel->size (); } } // private void kpTransformPreviewDialog::updatePreview () { qCDebug(kpLogDialogs) << "kpTransformPreviewDialog::updatePreview()"; - if (!m_previewGroupBox) + if (!m_previewGroupBox) { return; + } kpDocument *doc = document (); - if (!doc) + if (!doc) { return; + } if (!updatesEnabled ()) { qCDebug(kpLogDialogs) << "updates not enabled - aborting"; return; } updateShrunkenDocumentPixmap (); if (!m_shrunkenDocumentPixmap.isNull ()) { QSize newDim = newDimensions (); double keepsAspectScale = aspectScale (m_previewPixmapLabel->width (), m_previewPixmapLabel->height (), newDim.width (), newDim.height ()); int targetWidth = scaleDimension (newDim.width (), keepsAspectScale, 1, // min m_previewPixmapLabel->width ()); // max int targetHeight = scaleDimension (newDim.height (), keepsAspectScale, 1, // min m_previewPixmapLabel->height ()); // max // TODO: Some effects work directly on QImage; so could cache the // QImage so that transformPixmap() is faster QImage transformedShrunkenDocumentPixmap = transformPixmap (m_shrunkenDocumentPixmap, targetWidth, targetHeight); QImage previewPixmap (m_previewPixmapLabel->width (), m_previewPixmapLabel->height (), QImage::Format_ARGB32_Premultiplied); previewPixmap.fill(QColor(Qt::transparent).rgba()); kpPixmapFX::setPixmapAt (&previewPixmap, (previewPixmap.width () - transformedShrunkenDocumentPixmap.width ()) / 2, (previewPixmap.height () - transformedShrunkenDocumentPixmap.height ()) / 2, transformedShrunkenDocumentPixmap); qCDebug(kpLogDialogs) << "kpTransformPreviewDialog::updatePreview ():" << " shrunkenDocumentPixmap: w=" << m_shrunkenDocumentPixmap.width () << " h=" << m_shrunkenDocumentPixmap.height () << " previewPixmapLabel: w=" << m_previewPixmapLabel->width () << " h=" << m_previewPixmapLabel->height () << " transformedShrunkenDocumentPixmap: w=" << transformedShrunkenDocumentPixmap.width () << " h=" << transformedShrunkenDocumentPixmap.height () << " previewPixmap: w=" << previewPixmap.width () << " h=" << previewPixmap.height (); m_previewPixmapLabel->setPixmap (QPixmap::fromImage(previewPixmap)); // immediate update esp. for expensive previews m_previewPixmapLabel->repaint (); qCDebug(kpLogDialogs) << "\tafter QLabel::setPixmap() previewPixmapLabel: w=" << m_previewPixmapLabel->width () << " h=" << m_previewPixmapLabel->height (); } } // protected slot virtual void kpTransformPreviewDialog::slotUpdate () { qCDebug(kpLogDialogs) << "kpTransformPreviewDialog::slotUpdate()"; updateDimensions (); updatePreview (); } // protected slot virtual void kpTransformPreviewDialog::slotUpdateWithWaitCursor () { qCDebug(kpLogDialogs) << "kpTransformPreviewDialog::slotUpdateWithWaitCursor()"; QApplication::setOverrideCursor (Qt::WaitCursor); slotUpdate (); QApplication::restoreOverrideCursor (); } diff --git a/dialogs/imagelib/transforms/kpTransformResizeScaleDialog.cpp b/dialogs/imagelib/transforms/kpTransformResizeScaleDialog.cpp index a5b8a324..76cae6cd 100644 --- a/dialogs/imagelib/transforms/kpTransformResizeScaleDialog.cpp +++ b/dialogs/imagelib/transforms/kpTransformResizeScaleDialog.cpp @@ -1,815 +1,824 @@ /* Copyright (c) 2003-2007 Clarence Dang Copyright (c) 2011 Martin Koller All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #define DEBUG_KP_TOOL_RESIZE_SCALE_DIALOG 0 #include "kpTransformResizeScaleDialog.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "kpLogCategories.h" #include #include #include #include "layers/selections/kpAbstractSelection.h" #include "kpDefs.h" #include "document/kpDocument.h" #include "layers/selections/text/kpTextSelection.h" #include "tools/kpTool.h" #include "environments/dialogs/imagelib/transforms/kpTransformDialogEnvironment.h" //--------------------------------------------------------------------- #define kpSettingResizeScaleLastKeepAspect "Resize Scale - Last Keep Aspect" #define kpSettingResizeScaleScaleType "Resize Scale - ScaleType" //--------------------------------------------------------------------- #define SET_VALUE_WITHOUT_SIGNAL_EMISSION(knuminput_instance,value) \ { \ knuminput_instance->blockSignals (true); \ knuminput_instance->setValue (value); \ knuminput_instance->blockSignals (false); \ } #define IGNORE_KEEP_ASPECT_RATIO(cmd) \ { \ m_ignoreKeepAspectRatio++; \ cmd; \ m_ignoreKeepAspectRatio--; \ } //--------------------------------------------------------------------- kpTransformResizeScaleDialog::kpTransformResizeScaleDialog ( kpTransformDialogEnvironment *_env, QWidget *parent) : QDialog (parent), m_environ (_env), m_ignoreKeepAspectRatio (0), m_lastType(kpTransformResizeScaleCommand::Resize) { setWindowTitle (i18nc ("@title:window", "Resize / Scale")); QDialogButtonBox *buttons = new QDialogButtonBox (QDialogButtonBox::Ok | QDialogButtonBox::Cancel, this); connect (buttons, &QDialogButtonBox::accepted, this, &kpTransformResizeScaleDialog::accept); connect (buttons, &QDialogButtonBox::rejected, this, &kpTransformResizeScaleDialog::reject); QWidget *baseWidget = new QWidget (this); - QVBoxLayout *dialogLayout = new QVBoxLayout (this); + auto *dialogLayout = new QVBoxLayout (this); dialogLayout->addWidget (baseWidget); dialogLayout->addWidget (buttons); QWidget *actOnBox = createActOnBox(baseWidget); QGroupBox *operationGroupBox = createOperationGroupBox(baseWidget); QGroupBox *dimensionsGroupBox = createDimensionsGroupBox(baseWidget); - QVBoxLayout *baseLayout = new QVBoxLayout (baseWidget); + auto *baseLayout = new QVBoxLayout (baseWidget); baseLayout->setContentsMargins(0, 0, 0, 0); baseLayout->addWidget(actOnBox); baseLayout->addWidget(operationGroupBox); baseLayout->addWidget(dimensionsGroupBox); KConfigGroup cfg(KSharedConfig::openConfig(), kpSettingsGroupGeneral); setKeepAspectRatio(cfg.readEntry(kpSettingResizeScaleLastKeepAspect, false)); m_lastType = static_cast (cfg.readEntry(kpSettingResizeScaleScaleType, static_cast(kpTransformResizeScaleCommand::Resize))); slotActOnChanged (); m_newWidthInput->setFocus (); //enableButtonOk (!isNoOp ()); } //--------------------------------------------------------------------- // private kpDocument *kpTransformResizeScaleDialog::document () const { return m_environ->document (); } //--------------------------------------------------------------------- // private kpAbstractSelection *kpTransformResizeScaleDialog::selection () const { Q_ASSERT (document ()); return document ()->selection (); } //--------------------------------------------------------------------- // private kpTextSelection *kpTransformResizeScaleDialog::textSelection () const { Q_ASSERT (document ()); return document ()->textSelection (); } //--------------------------------------------------------------------- // private QWidget *kpTransformResizeScaleDialog::createActOnBox(QWidget *baseWidget) { QWidget *actOnBox = new QWidget (baseWidget); - QLabel *actOnLabel = new QLabel (i18n ("Ac&t on:"), actOnBox); + auto *actOnLabel = new QLabel (i18n ("Ac&t on:"), actOnBox); m_actOnCombo = new QComboBox (actOnBox); actOnLabel->setBuddy (m_actOnCombo); m_actOnCombo->insertItem (Image, i18n ("Entire Image")); if (selection ()) { QString selName = i18n ("Selection"); - if (textSelection ()) + if (textSelection ()) { selName = i18n ("Text Box"); + } m_actOnCombo->insertItem (Selection, selName); m_actOnCombo->setCurrentIndex (Selection); } else { actOnLabel->setEnabled (false); m_actOnCombo->setEnabled (false); } - - QHBoxLayout *lay = new QHBoxLayout (actOnBox); + auto *lay = new QHBoxLayout (actOnBox); lay->setContentsMargins(0, 0, 0, 0); lay->addWidget (actOnLabel); lay->addWidget (m_actOnCombo, 1); - connect (m_actOnCombo, static_cast(&QComboBox::activated), this, &kpTransformResizeScaleDialog::slotActOnChanged); return actOnBox; } //--------------------------------------------------------------------- static void toolButtonSetLook (QToolButton *button, const QString &iconName, const QString &name) { QPixmap icon = UserIcon (iconName); button->setIconSize (QSize (icon.width (), icon.height ())); button->setIcon (icon); button->setToolButtonStyle (Qt::ToolButtonTextUnderIcon); button->setText (name); button->setFocusPolicy (Qt::StrongFocus); button->setCheckable (true); } //--------------------------------------------------------------------- // private QGroupBox *kpTransformResizeScaleDialog::createOperationGroupBox (QWidget *baseWidget) { QGroupBox *operationGroupBox = new QGroupBox (i18n ("Operation"), baseWidget); operationGroupBox->setWhatsThis( i18n ("" "
    " "
  • Resize: The size of the picture will be" " increased" " by creating new areas to the right and/or bottom" " (filled in with the background color) or" " decreased by cutting" " it at the right and/or bottom.
  • " "
  • Scale: The picture will be expanded" " by duplicating pixels or squashed by dropping pixels.
  • " "
  • Smooth Scale: This is the same as" " Scale except that it blends neighboring" " pixels to produce a smoother looking picture.
  • " "
" "
")); m_resizeButton = new QToolButton (operationGroupBox); toolButtonSetLook (m_resizeButton, QLatin1String ("resize"), i18n ("&Resize")); m_scaleButton = new QToolButton (operationGroupBox); toolButtonSetLook (m_scaleButton, QLatin1String ("scale"), i18n ("&Scale")); m_smoothScaleButton = new QToolButton (operationGroupBox); toolButtonSetLook (m_smoothScaleButton, QLatin1String ("smooth_scale"), i18n ("S&mooth Scale")); - QButtonGroup *resizeScaleButtonGroup = new QButtonGroup (baseWidget); + auto *resizeScaleButtonGroup = new QButtonGroup (baseWidget); resizeScaleButtonGroup->addButton (m_resizeButton); resizeScaleButtonGroup->addButton (m_scaleButton); resizeScaleButtonGroup->addButton (m_smoothScaleButton); - QGridLayout *operationLayout = new QGridLayout (operationGroupBox ); + auto *operationLayout = new QGridLayout (operationGroupBox ); operationLayout->addWidget (m_resizeButton, 0, 0, Qt::AlignCenter); operationLayout->addWidget (m_scaleButton, 0, 1, Qt::AlignCenter); operationLayout->addWidget (m_smoothScaleButton, 0, 2, Qt::AlignCenter); connect (m_resizeButton, &QToolButton::toggled, this, &kpTransformResizeScaleDialog::slotTypeChanged); connect (m_scaleButton, &QToolButton::toggled, this, &kpTransformResizeScaleDialog::slotTypeChanged); connect (m_smoothScaleButton, &QToolButton::toggled, this, &kpTransformResizeScaleDialog::slotTypeChanged); return operationGroupBox; } //--------------------------------------------------------------------- // private QGroupBox *kpTransformResizeScaleDialog::createDimensionsGroupBox(QWidget *baseWidget) { QGroupBox *dimensionsGroupBox = new QGroupBox (i18n ("Dimensions"), baseWidget); - QLabel *widthLabel = new QLabel (i18n ("Width:"), dimensionsGroupBox); + auto *widthLabel = new QLabel (i18n ("Width:"), dimensionsGroupBox); widthLabel->setAlignment (widthLabel->alignment () | Qt::AlignHCenter); - QLabel *heightLabel = new QLabel (i18n ("Height:"), dimensionsGroupBox); + auto *heightLabel = new QLabel (i18n ("Height:"), dimensionsGroupBox); heightLabel->setAlignment (heightLabel->alignment () | Qt::AlignHCenter); - QLabel *originalLabel = new QLabel (i18n ("Original:"), dimensionsGroupBox); + auto *originalLabel = new QLabel (i18n ("Original:"), dimensionsGroupBox); m_originalWidthInput = new QSpinBox; m_originalWidthInput->setRange(1, INT_MAX); m_originalWidthInput->setValue(document()->width(static_cast (selection()))); - QLabel *xLabel0 = new QLabel (i18n ("x"), dimensionsGroupBox); + auto *xLabel0 = new QLabel (i18n ("x"), dimensionsGroupBox); m_originalHeightInput = new QSpinBox; m_originalHeightInput->setRange(1, INT_MAX); m_originalHeightInput->setValue(document()->height(static_cast (selection()))); - QLabel *newLabel = new QLabel (i18n ("&New:"), dimensionsGroupBox); + auto *newLabel = new QLabel (i18n ("&New:"), dimensionsGroupBox); m_newWidthInput = new QSpinBox; m_newWidthInput->setRange(1, INT_MAX); - QLabel *xLabel1 = new QLabel (i18n ("x"), dimensionsGroupBox); + auto *xLabel1 = new QLabel (i18n ("x"), dimensionsGroupBox); m_newHeightInput = new QSpinBox; m_newHeightInput->setRange(1, INT_MAX); - QLabel *percentLabel = new QLabel (i18n ("&Percent:"), dimensionsGroupBox); + auto *percentLabel = new QLabel (i18n ("&Percent:"), dimensionsGroupBox); m_percentWidthInput = new QDoubleSpinBox; m_percentWidthInput->setRange(0.01, 1000000); m_percentWidthInput->setValue(100); m_percentWidthInput->setSingleStep(1); m_percentWidthInput->setDecimals(2); m_percentWidthInput->setSuffix(i18n("%")); - QLabel *xLabel2 = new QLabel (i18n ("x"), dimensionsGroupBox); + auto *xLabel2 = new QLabel (i18n ("x"), dimensionsGroupBox); m_percentHeightInput = new QDoubleSpinBox; m_percentHeightInput->setRange(0.01, 1000000); m_percentHeightInput->setValue(100); m_percentHeightInput->setSingleStep(1); m_percentHeightInput->setDecimals(2); m_percentHeightInput->setSuffix(i18n("%")); m_keepAspectRatioCheckBox = new QCheckBox (i18n ("Keep &aspect ratio"), dimensionsGroupBox); m_originalWidthInput->setEnabled (false); m_originalHeightInput->setEnabled (false); originalLabel->setBuddy (m_originalWidthInput); newLabel->setBuddy (m_newWidthInput); m_percentWidthInput->setValue (100); m_percentHeightInput->setValue (100); percentLabel->setBuddy (m_percentWidthInput); - QGridLayout *dimensionsLayout = new QGridLayout (dimensionsGroupBox); + auto *dimensionsLayout = new QGridLayout (dimensionsGroupBox); dimensionsLayout->setColumnStretch (1/*column*/, 1); dimensionsLayout->setColumnStretch (3/*column*/, 1); dimensionsLayout->addWidget (widthLabel, 0, 1); dimensionsLayout->addWidget (heightLabel, 0, 3); dimensionsLayout->addWidget (originalLabel, 1, 0); dimensionsLayout->addWidget (m_originalWidthInput, 1, 1); dimensionsLayout->addWidget (xLabel0, 1, 2); dimensionsLayout->addWidget (m_originalHeightInput, 1, 3); dimensionsLayout->addWidget (newLabel, 2, 0); dimensionsLayout->addWidget (m_newWidthInput, 2, 1); dimensionsLayout->addWidget (xLabel1, 2, 2); dimensionsLayout->addWidget (m_newHeightInput, 2, 3); dimensionsLayout->addWidget (percentLabel, 3, 0); dimensionsLayout->addWidget (m_percentWidthInput, 3, 1); dimensionsLayout->addWidget (xLabel2, 3, 2); dimensionsLayout->addWidget (m_percentHeightInput, 3, 3); dimensionsLayout->addWidget (m_keepAspectRatioCheckBox, 4, 0, 1, 4); dimensionsLayout->setRowStretch (4/*row*/, 1); dimensionsLayout->setRowMinimumHeight (4/*row*/, dimensionsLayout->rowMinimumHeight (4) * 2); connect (m_newWidthInput, static_cast(&QSpinBox::valueChanged), this, &kpTransformResizeScaleDialog::slotWidthChanged); connect (m_newHeightInput, static_cast(&QSpinBox::valueChanged), this, &kpTransformResizeScaleDialog::slotHeightChanged); // COMPAT: KDoubleNumInput only fires valueChanged(double) once per // edit. It should either fire: // // 1. At the end of the edit (triggered by clicking or tabbing // away), like with KDE 3. // // OR // // 2. Once per keystroke. // // Bug in KDoubleNumInput. connect (m_percentWidthInput, static_cast(&QDoubleSpinBox::valueChanged), this, &kpTransformResizeScaleDialog::slotPercentWidthChanged); connect (m_percentHeightInput, static_cast(&QDoubleSpinBox::valueChanged), this, &kpTransformResizeScaleDialog::slotPercentHeightChanged); connect (m_keepAspectRatioCheckBox, &QCheckBox::toggled, this, &kpTransformResizeScaleDialog::setKeepAspectRatio); return dimensionsGroupBox; } //--------------------------------------------------------------------- // private void kpTransformResizeScaleDialog::widthFitHeightToAspectRatio () { if (m_keepAspectRatioCheckBox->isChecked () && !m_ignoreKeepAspectRatio) { // width / height = oldWidth / oldHeight // height = width * oldHeight / oldWidth const int newHeight = qRound (double (imageWidth ()) * double (originalHeight ()) / double (originalWidth ())); IGNORE_KEEP_ASPECT_RATIO (m_newHeightInput->setValue (newHeight)); } } //--------------------------------------------------------------------- // private void kpTransformResizeScaleDialog::heightFitWidthToAspectRatio () { if (m_keepAspectRatioCheckBox->isChecked () && !m_ignoreKeepAspectRatio) { // width / height = oldWidth / oldHeight // width = height * oldWidth / oldHeight const int newWidth = qRound (double (imageHeight ()) * double (originalWidth ()) / double (originalHeight ())); IGNORE_KEEP_ASPECT_RATIO (m_newWidthInput->setValue (newWidth)); } } //--------------------------------------------------------------------- // private bool kpTransformResizeScaleDialog::resizeEnabled () const { return (!actOnSelection () || (actOnSelection () && textSelection ())); } //--------------------------------------------------------------------- // private bool kpTransformResizeScaleDialog::scaleEnabled () const { return (!(actOnSelection () && textSelection ())); } //--------------------------------------------------------------------- // private bool kpTransformResizeScaleDialog::smoothScaleEnabled () const { return scaleEnabled (); } //--------------------------------------------------------------------- // public slot void kpTransformResizeScaleDialog::slotActOnChanged () { qCDebug(kpLogDialogs) << "kpTransformResizeScaleDialog::slotActOnChanged()"; m_resizeButton->setEnabled (resizeEnabled ()); m_scaleButton->setEnabled (scaleEnabled ()); m_smoothScaleButton->setEnabled (smoothScaleEnabled ()); // TODO: somehow share logic with (resize|*scale)Enabled() if (actOnSelection ()) { if (textSelection ()) { m_resizeButton->setChecked (true); } else { - if (m_lastType == kpTransformResizeScaleCommand::Scale) + if (m_lastType == kpTransformResizeScaleCommand::Scale) { m_scaleButton->setChecked (true); - else + } + else { m_smoothScaleButton->setChecked (true); + } } } else { - if (m_lastType == kpTransformResizeScaleCommand::Resize) + if (m_lastType == kpTransformResizeScaleCommand::Resize) { m_resizeButton->setChecked (true); - else if (m_lastType == kpTransformResizeScaleCommand::Scale) + } + else if (m_lastType == kpTransformResizeScaleCommand::Scale) { m_scaleButton->setChecked (true); - else + } + else { m_smoothScaleButton->setChecked (true); + } } m_originalWidthInput->setValue (originalWidth ()); m_originalHeightInput->setValue (originalHeight ()); m_newWidthInput->blockSignals (true); m_newHeightInput->blockSignals (true); m_newWidthInput->setMinimum (actOnSelection () ? selection ()->minimumWidth () : 1); m_newHeightInput->setMinimum (actOnSelection () ? selection ()->minimumHeight () : 1); m_newWidthInput->blockSignals (false); m_newHeightInput->blockSignals (false); IGNORE_KEEP_ASPECT_RATIO (slotPercentWidthChanged (m_percentWidthInput->value ())); IGNORE_KEEP_ASPECT_RATIO (slotPercentHeightChanged (m_percentHeightInput->value ())); setKeepAspectRatio (m_keepAspectRatioCheckBox->isChecked ()); } //--------------------------------------------------------------------- // public slot void kpTransformResizeScaleDialog::slotTypeChanged () { m_lastType = type (); } //--------------------------------------------------------------------- // public slot void kpTransformResizeScaleDialog::slotWidthChanged (int width) { qCDebug(kpLogDialogs) << "kpTransformResizeScaleDialog::slotWidthChanged(" << width << ")"; const double newPercentWidth = double (width) * 100 / double (originalWidth ()); SET_VALUE_WITHOUT_SIGNAL_EMISSION (m_percentWidthInput,newPercentWidth); widthFitHeightToAspectRatio (); //enableButtonOk (!isNoOp ()); } //--------------------------------------------------------------------- // public slot void kpTransformResizeScaleDialog::slotHeightChanged (int height) { qCDebug(kpLogDialogs) << "kpTransformResizeScaleDialog::slotHeightChanged(" << height << ")"; const double newPercentHeight = double (height) * 100 / double (originalHeight ()); SET_VALUE_WITHOUT_SIGNAL_EMISSION (m_percentHeightInput,newPercentHeight); heightFitWidthToAspectRatio (); //enableButtonOk (!isNoOp ()); } //--------------------------------------------------------------------- // public slot void kpTransformResizeScaleDialog::slotPercentWidthChanged (double percentWidth) { qCDebug(kpLogDialogs) << "kpTransformResizeScaleDialog::slotPercentWidthChanged(" - << percentWidth << ")" << endl; + << percentWidth << ")"; SET_VALUE_WITHOUT_SIGNAL_EMISSION (m_newWidthInput, qRound (percentWidth * originalWidth () / 100.0)); widthFitHeightToAspectRatio (); //enableButtonOk (!isNoOp ()); } //--------------------------------------------------------------------- // public slot void kpTransformResizeScaleDialog::slotPercentHeightChanged (double percentHeight) { qCDebug(kpLogDialogs) << "kpTransformResizeScaleDialog::slotPercentHeightChanged(" - << percentHeight << ")" << endl; + << percentHeight << ")"; SET_VALUE_WITHOUT_SIGNAL_EMISSION (m_newHeightInput, qRound (percentHeight * originalHeight () / 100.0)); heightFitWidthToAspectRatio (); //enableButtonOk (!isNoOp ()); } //--------------------------------------------------------------------- // public slot void kpTransformResizeScaleDialog::setKeepAspectRatio (bool on) { qCDebug(kpLogDialogs) << "kpTransformResizeScaleDialog::setKeepAspectRatio(" - << on << ")" << endl; - if (on != m_keepAspectRatioCheckBox->isChecked ()) + << on << ")"; + if (on != m_keepAspectRatioCheckBox->isChecked ()) { m_keepAspectRatioCheckBox->setChecked (on); + } - if (on) + if (on) { widthFitHeightToAspectRatio (); + } } //--------------------------------------------------------------------- #undef IGNORE_KEEP_ASPECT_RATIO #undef SET_VALUE_WITHOUT_SIGNAL_EMISSION //--------------------------------------------------------------------- // private int kpTransformResizeScaleDialog::originalWidth () const { return document ()->width (actOnSelection ()); } //--------------------------------------------------------------------- // private int kpTransformResizeScaleDialog::originalHeight () const { return document ()->height (actOnSelection ()); } //--------------------------------------------------------------------- // public int kpTransformResizeScaleDialog::imageWidth () const { return m_newWidthInput->value (); } //--------------------------------------------------------------------- // public int kpTransformResizeScaleDialog::imageHeight () const { return m_newHeightInput->value (); } //--------------------------------------------------------------------- // public bool kpTransformResizeScaleDialog::actOnSelection () const { return (m_actOnCombo->currentIndex () == Selection); } //--------------------------------------------------------------------- // public kpTransformResizeScaleCommand::Type kpTransformResizeScaleDialog::type () const { - if (m_resizeButton->isChecked ()) + if (m_resizeButton->isChecked ()) { return kpTransformResizeScaleCommand::Resize; - else if (m_scaleButton->isChecked ()) + } + + if (m_scaleButton->isChecked ()) { return kpTransformResizeScaleCommand::Scale; - else - return kpTransformResizeScaleCommand::SmoothScale; + } + + return kpTransformResizeScaleCommand::SmoothScale; } //--------------------------------------------------------------------- // public bool kpTransformResizeScaleDialog::isNoOp () const { return (imageWidth () == originalWidth () && imageHeight () == originalHeight ()); } //--------------------------------------------------------------------- // private slot virtual [base QDialog] void kpTransformResizeScaleDialog::accept () { enum { eText, eSelection, eImage } actionTarget = eText; if (actOnSelection ()) { if (textSelection ()) { actionTarget = eText; } else { actionTarget = eSelection; } } else { actionTarget = eImage; } KLocalizedString message; QString caption, continueButtonText; // Note: If eText, can't Scale nor SmoothScale. // If eSelection, can't Resize. switch (type ()) { default: case kpTransformResizeScaleCommand::Resize: if (actionTarget == eText) { message = ki18n ("

Resizing the text box to %1x%2" " may take a substantial amount of memory." " This can reduce system" " responsiveness and cause other application resource" " problems.

" "

Are you sure you want to resize the text box?

"); caption = i18nc ("@title:window", "Resize Text Box?"); continueButtonText = i18n ("R&esize Text Box"); } else if (actionTarget == eImage) { message = ki18n ("

Resizing the image to %1x%2" " may take a substantial amount of memory." " This can reduce system" " responsiveness and cause other application resource" " problems.

" "

Are you sure you want to resize the image?

"); caption = i18nc ("@title:window", "Resize Image?"); continueButtonText = i18n ("R&esize Image"); } break; case kpTransformResizeScaleCommand::Scale: if (actionTarget == eImage) { message = ki18n ("

Scaling the image to %1x%2" " may take a substantial amount of memory." " This can reduce system" " responsiveness and cause other application resource" " problems.

" "

Are you sure you want to scale the image?

"); caption = i18nc ("@title:window", "Scale Image?"); continueButtonText = i18n ("Scal&e Image"); } else if (actionTarget == eSelection) { message = ki18n ("

Scaling the selection to %1x%2" " may take a substantial amount of memory." " This can reduce system" " responsiveness and cause other application resource" " problems.

" "

Are you sure you want to scale the selection?

"); caption = i18nc ("@title:window", "Scale Selection?"); continueButtonText = i18n ("Scal&e Selection"); } break; case kpTransformResizeScaleCommand::SmoothScale: if (actionTarget == eImage) { message = ki18n ("

Smooth Scaling the image to %1x%2" " may take a substantial amount of memory." " This can reduce system" " responsiveness and cause other application resource" " problems.

" "

Are you sure you want to smooth scale the image?

"); caption = i18nc ("@title:window", "Smooth Scale Image?"); continueButtonText = i18n ("Smooth Scal&e Image"); } else if (actionTarget == eSelection) { message = ki18n ("

Smooth Scaling the selection to %1x%2" " may take a substantial amount of memory." " This can reduce system" " responsiveness and cause other application resource" " problems.

" "

Are you sure you want to smooth scale the selection?

"); caption = i18nc ("@title:window", "Smooth Scale Selection?"); continueButtonText = i18n ("Smooth Scal&e Selection"); } break; } if (kpTool::warnIfBigImageSize (originalWidth (), originalHeight (), imageWidth (), imageHeight (), message.subs (imageWidth ()).subs (imageHeight ()).toString (), caption, continueButtonText, this)) { QDialog::accept (); } // store settings KConfigGroup cfg(KSharedConfig::openConfig(), kpSettingsGroupGeneral); cfg.writeEntry(kpSettingResizeScaleLastKeepAspect, m_keepAspectRatioCheckBox->isChecked()); cfg.writeEntry(kpSettingResizeScaleScaleType, static_cast(m_lastType)); cfg.sync(); } //--------------------------------------------------------------------- diff --git a/dialogs/imagelib/transforms/kpTransformRotateDialog.cpp b/dialogs/imagelib/transforms/kpTransformRotateDialog.cpp index 2bc50c96..0b5e87a0 100644 --- a/dialogs/imagelib/transforms/kpTransformRotateDialog.cpp +++ b/dialogs/imagelib/transforms/kpTransformRotateDialog.cpp @@ -1,313 +1,322 @@ /* Copyright (c) 2003-2007 Clarence Dang All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #define DEBUG_KP_TOOL_ROTATE 0 #include "kpTransformRotateDialog.h" #include "kpDefs.h" #include "document/kpDocument.h" #include "pixmapfx/kpPixmapFX.h" #include "tools/kpTool.h" #include "environments/dialogs/imagelib/transforms/kpTransformDialogEnvironment.h" #include "views/manager/kpViewManager.h" #include "kpLogCategories.h" #include #include #include #include #include #include #include #include #include #include #include #include // private static int kpTransformRotateDialog::s_lastWidth = -1, kpTransformRotateDialog::s_lastHeight = -1; // private static bool kpTransformRotateDialog::s_lastIsClockwise = true; int kpTransformRotateDialog::s_lastAngleCustom = 0; kpTransformRotateDialog::kpTransformRotateDialog (bool actOnSelection, kpTransformDialogEnvironment *_env, QWidget *parent) : kpTransformPreviewDialog (kpTransformPreviewDialog::AllFeatures, false/*don't reserve top row*/, actOnSelection ? i18nc ("@title:window", "Rotate Selection") : i18nc ("@title:window", "Rotate Image"), i18n ("After rotate:"), actOnSelection, _env, parent) { s_lastAngleCustom = 0; createDirectionGroupBox (); createAngleGroupBox (); - if (s_lastWidth > 0 && s_lastHeight > 0) + if (s_lastWidth > 0 && s_lastHeight > 0) { resize (s_lastWidth, s_lastHeight); + } slotAngleCustomRadioButtonToggled (m_angleCustomRadioButton->isChecked ()); slotUpdate (); } kpTransformRotateDialog::~kpTransformRotateDialog () { s_lastWidth = width (); s_lastHeight = height (); } // private void kpTransformRotateDialog::createDirectionGroupBox () { - QGroupBox *directionGroupBox = new QGroupBox (i18n ("Direction"), mainWidget ()); + auto *directionGroupBox = new QGroupBox (i18n ("Direction"), mainWidget ()); addCustomWidget (directionGroupBox); - QLabel *antiClockwisePixmapLabel = new QLabel (directionGroupBox); + auto *antiClockwisePixmapLabel = new QLabel (directionGroupBox); antiClockwisePixmapLabel->setPixmap (UserIcon ("image_rotate_anticlockwise")); - QLabel *clockwisePixmapLabel = new QLabel (directionGroupBox); + auto *clockwisePixmapLabel = new QLabel (directionGroupBox); clockwisePixmapLabel->setPixmap (UserIcon ("image_rotate_clockwise")); m_antiClockwiseRadioButton = new QRadioButton (i18n ("Cou&nterclockwise"), directionGroupBox); m_clockwiseRadioButton = new QRadioButton (i18n ("C&lockwise"), directionGroupBox); m_antiClockwiseRadioButton->setChecked (!s_lastIsClockwise); m_clockwiseRadioButton->setChecked (s_lastIsClockwise); - QGridLayout *directionLayout = new QGridLayout (directionGroupBox ); + auto *directionLayout = new QGridLayout (directionGroupBox ); directionLayout->addWidget (antiClockwisePixmapLabel, 0, 0, Qt::AlignCenter); directionLayout->addWidget (clockwisePixmapLabel, 0, 1, Qt::AlignCenter); directionLayout->addWidget (m_antiClockwiseRadioButton, 1, 0, Qt::AlignCenter); directionLayout->addWidget (m_clockwiseRadioButton, 1, 1, Qt::AlignCenter); connect (m_antiClockwiseRadioButton, &QRadioButton::toggled, this, &kpTransformRotateDialog::slotUpdate); connect (m_clockwiseRadioButton, &QRadioButton::toggled, this, &kpTransformRotateDialog::slotUpdate); } // private void kpTransformRotateDialog::createAngleGroupBox () { - QGroupBox *angleGroupBox = new QGroupBox (i18n ("Angle"), mainWidget ()); + auto *angleGroupBox = new QGroupBox (i18n ("Angle"), mainWidget ()); addCustomWidget (angleGroupBox); m_angle90RadioButton = new QRadioButton (i18n ("90 °rees"), angleGroupBox); m_angle180RadioButton = new QRadioButton (i18n ("180 d&egrees"), angleGroupBox); m_angle270RadioButton = new QRadioButton (i18n ("270 de&grees"), angleGroupBox); m_angleCustomRadioButton = new QRadioButton (i18n ("C&ustom:"), angleGroupBox); m_angleCustomInput = new QSpinBox; m_angleCustomInput->setMinimum(-359); m_angleCustomInput->setMaximum(+359); m_angleCustomInput->setValue(s_lastAngleCustom); - QLabel *degreesLabel = new QLabel (i18n ("degrees"), angleGroupBox); + auto *degreesLabel = new QLabel (i18n ("degrees"), angleGroupBox); m_angleCustomRadioButton->setChecked (true); - QGridLayout *angleLayout = new QGridLayout (angleGroupBox ); + auto *angleLayout = new QGridLayout (angleGroupBox ); angleLayout->addWidget (m_angle90RadioButton, 0, 0, 1, 3); angleLayout->addWidget (m_angle180RadioButton, 1, 0, 1, 3); angleLayout->addWidget (m_angle270RadioButton, 2, 0, 1, 3); angleLayout->addWidget (m_angleCustomRadioButton, 3, 0); angleLayout->addWidget (m_angleCustomInput, 3, 1); angleLayout->addWidget (degreesLabel, 3, 2); angleLayout->setColumnStretch (1, 2); // Stretch Custom Angle Input connect (m_angle90RadioButton, &QRadioButton::toggled, this, &kpTransformRotateDialog::slotUpdate); connect (m_angle180RadioButton, &QRadioButton::toggled, this, &kpTransformRotateDialog::slotUpdate); connect (m_angle270RadioButton, &QRadioButton::toggled, this, &kpTransformRotateDialog::slotUpdate); connect (m_angleCustomRadioButton, &QRadioButton::toggled, this, &kpTransformRotateDialog::slotAngleCustomRadioButtonToggled); connect (m_angleCustomRadioButton, &QRadioButton::toggled, this, &kpTransformRotateDialog::slotUpdate); connect (m_angleCustomInput, static_cast(&QSpinBox::valueChanged), this, &kpTransformRotateDialog::slotUpdate); } // public virtual [base kpTransformPreviewDialog] bool kpTransformRotateDialog::isNoOp () const { return (angle () == 0); } // public int kpTransformRotateDialog::angle () const { int retAngle; - if (m_angle90RadioButton->isChecked ()) + if (m_angle90RadioButton->isChecked ()) { retAngle = 90; - else if (m_angle180RadioButton->isChecked ()) + } + else if (m_angle180RadioButton->isChecked ()) { retAngle = 180; - else if (m_angle270RadioButton->isChecked ()) + } + else if (m_angle270RadioButton->isChecked ()) { retAngle = 270; - else // if (m_angleCustomRadioButton->isChecked ()) + } + else { // if (m_angleCustomRadioButton->isChecked ()) retAngle = m_angleCustomInput->value (); + } - if (m_antiClockwiseRadioButton->isChecked ()) + if (m_antiClockwiseRadioButton->isChecked ()) { retAngle *= -1; + } - if (retAngle < 0) + if (retAngle < 0) { retAngle += ((0 - retAngle) / 360 + 1) * 360; + } - if (retAngle >= 360) + if (retAngle >= 360) { retAngle -= ((retAngle - 360) / 360 + 1) * 360; + } return retAngle; } // private virtual [base kpTransformPreviewDialog] QSize kpTransformRotateDialog::newDimensions () const { QTransform matrix = kpPixmapFX::rotateMatrix (m_oldWidth, m_oldHeight, angle ()); QRect rect = matrix.mapRect (QRect (0, 0, m_oldWidth, m_oldHeight)); return rect.size (); } // private virtual [base kpTransformPreviewDialog] QImage kpTransformRotateDialog::transformPixmap (const QImage &image, int targetWidth, int targetHeight) const { return kpPixmapFX::rotate (image, angle (), m_environ->backgroundColor (m_actOnSelection), targetWidth, targetHeight); } // private slot void kpTransformRotateDialog::slotAngleCustomRadioButtonToggled (bool isChecked) { m_angleCustomInput->setEnabled (isChecked); - if (isChecked) + if (isChecked) { m_angleCustomInput->setFocus(); + } } // private slot virtual [base kpTransformPreviewDialog] void kpTransformRotateDialog::slotUpdate () { s_lastIsClockwise = m_clockwiseRadioButton->isChecked (); s_lastAngleCustom = m_angleCustomInput->value (); kpTransformPreviewDialog::slotUpdate (); } // private slot virtual [base QDialog] void kpTransformRotateDialog::accept () { KLocalizedString message; QString caption, continueButtonText; if (document ()->selection ()) { if (!document ()->textSelection ()) { message = ki18n ("

Rotating the selection to %1x%2" " may take a substantial amount of memory." " This can reduce system" " responsiveness and cause other application resource" " problems.

" "

Are you sure you want to rotate the selection?

"); caption = i18nc ("@title:window", "Rotate Selection?"); continueButtonText = i18n ("Rotat&e Selection"); } } else { message = ki18n ("

Rotating the image to %1x%2" " may take a substantial amount of memory." " This can reduce system" " responsiveness and cause other application resource" " problems.

" "

Are you sure you want to rotate the image?

"); caption = i18nc ("@title:window", "Rotate Image?"); continueButtonText = i18n ("Rotat&e Image"); } const int newWidth = newDimensions ().width (); const int newHeight = newDimensions ().height (); if (kpTool::warnIfBigImageSize (m_oldWidth, m_oldHeight, newWidth, newHeight, message.subs (newWidth).subs (newHeight).toString (), caption, continueButtonText, this)) { QDialog::accept (); } } diff --git a/dialogs/imagelib/transforms/kpTransformSkewDialog.cpp b/dialogs/imagelib/transforms/kpTransformSkewDialog.cpp index fa176713..29a983bd 100644 --- a/dialogs/imagelib/transforms/kpTransformSkewDialog.cpp +++ b/dialogs/imagelib/transforms/kpTransformSkewDialog.cpp @@ -1,297 +1,298 @@ /* Copyright (c) 2003-2007 Clarence Dang All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #define DEBUG_KP_TOOL_SKEW 0 #define DEBUG_KP_TOOL_SKEW_DIALOG 0 #include "dialogs/imagelib/transforms/kpTransformSkewDialog.h" #include #include #include #include #include #include #include #include #include #include "kpLogCategories.h" #include #include #include "kpDefs.h" #include "document/kpDocument.h" #include "pixmapfx/kpPixmapFX.h" #include "tools/kpTool.h" #include "environments/dialogs/imagelib/transforms/kpTransformDialogEnvironment.h" // private static int kpTransformSkewDialog::s_lastWidth = -1, kpTransformSkewDialog::s_lastHeight = -1; // private static int kpTransformSkewDialog::s_lastHorizontalAngle = 0, kpTransformSkewDialog::s_lastVerticalAngle = 0; kpTransformSkewDialog::kpTransformSkewDialog (bool actOnSelection, kpTransformDialogEnvironment *_env, QWidget *parent) : kpTransformPreviewDialog (kpTransformPreviewDialog::AllFeatures, false/*don't reserve top row*/, actOnSelection ? i18nc ("@title:window", "Skew Selection") : i18nc ("@title:window", "Skew Image"), i18n ("After skew:"), actOnSelection, _env, parent) { // Too confusing - disable for now s_lastHorizontalAngle = s_lastVerticalAngle = 0; createAngleGroupBox (); - if (s_lastWidth > 0 && s_lastHeight > 0) + if (s_lastWidth > 0 && s_lastHeight > 0) { resize (s_lastWidth, s_lastHeight); + } slotUpdate (); m_horizontalSkewInput->setFocus (); } kpTransformSkewDialog::~kpTransformSkewDialog () { s_lastWidth = width (); s_lastHeight = height (); } // private void kpTransformSkewDialog::createAngleGroupBox () { - QGroupBox *angleGroupBox = new QGroupBox (i18n ("Angle"), mainWidget ()); + auto *angleGroupBox = new QGroupBox (i18n ("Angle"), mainWidget ()); addCustomWidget (angleGroupBox); - QLabel *horizontalSkewPixmapLabel = new QLabel (angleGroupBox); + auto *horizontalSkewPixmapLabel = new QLabel (angleGroupBox); horizontalSkewPixmapLabel->setPixmap (UserIcon ("image_skew_horizontal")); - QLabel *horizontalSkewLabel = new QLabel (i18n ("&Horizontal:"), angleGroupBox); + auto *horizontalSkewLabel = new QLabel (i18n ("&Horizontal:"), angleGroupBox); m_horizontalSkewInput = new QSpinBox; m_horizontalSkewInput->setValue(s_lastHorizontalAngle); m_horizontalSkewInput->setMinimum(-89); m_horizontalSkewInput->setMaximum(+89); - QLabel *horizontalSkewDegreesLabel = new QLabel (i18n ("degrees"), angleGroupBox); + auto *horizontalSkewDegreesLabel = new QLabel (i18n ("degrees"), angleGroupBox); - QLabel *verticalSkewPixmapLabel = new QLabel (angleGroupBox); + auto *verticalSkewPixmapLabel = new QLabel (angleGroupBox); verticalSkewPixmapLabel->setPixmap (UserIcon ("image_skew_vertical")); - QLabel *verticalSkewLabel = new QLabel (i18n ("&Vertical:"), angleGroupBox); + auto *verticalSkewLabel = new QLabel (i18n ("&Vertical:"), angleGroupBox); m_verticalSkewInput = new QSpinBox; m_verticalSkewInput->setValue(s_lastVerticalAngle); m_verticalSkewInput->setMinimum(-89); m_verticalSkewInput->setMaximum(+89); - QLabel *verticalSkewDegreesLabel = new QLabel (i18n ("degrees"), angleGroupBox); + auto *verticalSkewDegreesLabel = new QLabel (i18n ("degrees"), angleGroupBox); horizontalSkewLabel->setBuddy (m_horizontalSkewInput); verticalSkewLabel->setBuddy (m_verticalSkewInput); - QGridLayout *angleLayout = new QGridLayout (angleGroupBox); + auto *angleLayout = new QGridLayout (angleGroupBox); angleLayout->addWidget (horizontalSkewPixmapLabel, 0, 0); angleLayout->addWidget (horizontalSkewLabel, 0, 1); angleLayout->addWidget (m_horizontalSkewInput, 0, 2, Qt::AlignVCenter); angleLayout->addWidget (horizontalSkewDegreesLabel, 0, 3); angleLayout->addWidget (verticalSkewPixmapLabel, 1, 0); angleLayout->addWidget (verticalSkewLabel, 1, 1); angleLayout->addWidget (m_verticalSkewInput, 1, 2, Qt::AlignVCenter); angleLayout->addWidget (verticalSkewDegreesLabel, 1, 3); connect (m_horizontalSkewInput, static_cast(&QSpinBox::valueChanged), this, &kpTransformSkewDialog::slotUpdate); connect (m_verticalSkewInput, static_cast(&QSpinBox::valueChanged), this, &kpTransformSkewDialog::slotUpdate); } // private virtual [base kpTransformPreviewDialog] QSize kpTransformSkewDialog::newDimensions () const { kpDocument *doc = document (); Q_ASSERT (doc); - QTransform skewMatrix = kpPixmapFX::skewMatrix (doc->image (), + auto skewMatrix = kpPixmapFX::skewMatrix (doc->image (), horizontalAngleForPixmapFX (), verticalAngleForPixmapFX ()); - QRect skewRect = skewMatrix.mapRect (doc->rect (m_actOnSelection)); + auto skewRect = skewMatrix.mapRect (doc->rect (m_actOnSelection)); - return QSize (skewRect.width (), skewRect.height ()); + return {skewRect.width (), skewRect.height ()}; } // private virtual [base kpTransformPreviewDialog] QImage kpTransformSkewDialog::transformPixmap (const QImage &image, int targetWidth, int targetHeight) const { return kpPixmapFX::skew (image, horizontalAngleForPixmapFX (), verticalAngleForPixmapFX (), m_environ->backgroundColor (m_actOnSelection), targetWidth, targetHeight); } // private void kpTransformSkewDialog::updateLastAngles () { s_lastHorizontalAngle = horizontalAngle (); s_lastVerticalAngle = verticalAngle (); } // private slot virtual [base kpTransformPreviewDialog] void kpTransformSkewDialog::slotUpdate () { updateLastAngles (); kpTransformPreviewDialog::slotUpdate (); } // public int kpTransformSkewDialog::horizontalAngle () const { return m_horizontalSkewInput->value (); } // public int kpTransformSkewDialog::verticalAngle () const { return m_verticalSkewInput->value (); } // public static int kpTransformSkewDialog::horizontalAngleForPixmapFX (int hangle) { return -hangle; } // public static int kpTransformSkewDialog::verticalAngleForPixmapFX (int vangle) { return -vangle; } // public int kpTransformSkewDialog::horizontalAngleForPixmapFX () const { return kpTransformSkewDialog::horizontalAngleForPixmapFX (horizontalAngle ()); } // public int kpTransformSkewDialog::verticalAngleForPixmapFX () const { return kpTransformSkewDialog::verticalAngleForPixmapFX (verticalAngle ()); } // public virtual [base kpTransformPreviewDialog] bool kpTransformSkewDialog::isNoOp () const { return (horizontalAngle () == 0) && (verticalAngle () == 0); } // private slot virtual [base QDialog] void kpTransformSkewDialog::accept () { KLocalizedString message; QString caption, continueButtonText; if (document ()->selection ()) { if (!document ()->textSelection ()) { message = ki18n ("

Skewing the selection to %1x%2" " may take a substantial amount of memory." " This can reduce system" " responsiveness and cause other application resource" " problems.

" "

Are you sure you want to skew the selection?

"); caption = i18nc ("@title:window", "Skew Selection?"); continueButtonText = i18n ("Sk&ew Selection"); } } else { message = ki18n ("

Skewing the image to %1x%2" " may take a substantial amount of memory." " This can reduce system" " responsiveness and cause other application resource" " problems.

" "

Are you sure you want to skew the image?

"); caption = i18nc ("@title:window", "Skew Image?"); continueButtonText = i18n ("Sk&ew Image"); } const int newWidth = newDimensions ().width (); const int newHeight = newDimensions ().height (); if (kpTool::warnIfBigImageSize (m_oldWidth, m_oldHeight, newWidth, newHeight, message.subs (newWidth).subs (newHeight).toString (), caption, continueButtonText, this)) { QDialog::accept (); } } diff --git a/dialogs/kpColorSimilarityDialog.cpp b/dialogs/kpColorSimilarityDialog.cpp index 8f717cb5..7a044b07 100644 --- a/dialogs/kpColorSimilarityDialog.cpp +++ b/dialogs/kpColorSimilarityDialog.cpp @@ -1,143 +1,141 @@ /* Copyright (c) 2003-2007 Clarence Dang All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include "kpColorSimilarityDialog.h" #include "widgets/colorSimilarity/kpColorSimilarityFrame.h" #include #include "../widgets/imagelib/effects/kpNumInput.h" #include #include #include #include #include #include #include kpColorSimilarityDialog::kpColorSimilarityDialog (QWidget *parent) : QDialog (parent) { setWindowTitle (i18nc ("@title:window", "Color Similarity")); - QDialogButtonBox *buttons = new QDialogButtonBox (QDialogButtonBox::Ok | + auto *buttons = new QDialogButtonBox (QDialogButtonBox::Ok | QDialogButtonBox::Cancel, this); connect (buttons, &QDialogButtonBox::accepted, this, &kpColorSimilarityDialog::accept); connect (buttons, &QDialogButtonBox::rejected, this, &kpColorSimilarityDialog::reject); - QWidget *baseWidget = new QWidget (this); + auto *baseWidget = new QWidget (this); - QVBoxLayout *dialogLayout = new QVBoxLayout (this); + auto *dialogLayout = new QVBoxLayout (this); dialogLayout->addWidget (baseWidget); dialogLayout->addWidget (buttons); - QGroupBox *cubeGroupBox = new QGroupBox (i18n ("Preview"), baseWidget); + auto *cubeGroupBox = new QGroupBox (i18n ("Preview"), baseWidget); m_colorSimilarityFrame = new kpColorSimilarityFrame(cubeGroupBox); m_colorSimilarityFrame->setMinimumSize (240, 180); - QPushButton *updatePushButton = new QPushButton (i18n ("&Update"), cubeGroupBox); + auto *updatePushButton = new QPushButton (i18n ("&Update"), cubeGroupBox); - QVBoxLayout *cubeLayout = new QVBoxLayout (cubeGroupBox); + auto *cubeLayout = new QVBoxLayout (cubeGroupBox); cubeLayout->addWidget (m_colorSimilarityFrame, 1/*stretch*/); cubeLayout->addWidget (updatePushButton, 0/*stretch*/, Qt::AlignHCenter); connect (updatePushButton, &QPushButton::clicked, this, &kpColorSimilarityDialog::slotColorSimilarityValueChanged); - QGroupBox *inputGroupBox = new QGroupBox (i18n ("&RGB Color Cube Distance"), + auto *inputGroupBox = new QGroupBox (i18n ("&RGB Color Cube Distance"), baseWidget); m_colorSimilarityInput = new kpIntNumInput (inputGroupBox); m_colorSimilarityInput->setRange (0, int (kpColorSimilarityHolder::MaxColorSimilarity * 100 + 0.1/*don't floor below target int*/), 5/*step*/); m_colorSimilarityInput->setSuffix (i18n ("%")); m_colorSimilarityInput->setSpecialValueText (i18n ("Exact Match")); // TODO: We have a good handbook section on this, which we should // somehow link to. m_whatIsLabel = new QLabel ( i18n ("" "What is Color Similarity?"), inputGroupBox); m_whatIsLabel->setAlignment (Qt::AlignHCenter); connect (m_whatIsLabel, &QLabel::linkActivated, this, &kpColorSimilarityDialog::slotWhatIsLabelClicked); - QVBoxLayout *inputLayout = new QVBoxLayout (inputGroupBox); + auto *inputLayout = new QVBoxLayout (inputGroupBox); inputLayout->addWidget (m_colorSimilarityInput); inputLayout->addWidget (m_whatIsLabel); // COMPAT: This is not firing properly when the user is typing in a // new value. connect (m_colorSimilarityInput, &kpIntNumInput::valueChanged, this, &kpColorSimilarityDialog::slotColorSimilarityValueChanged); - QVBoxLayout *baseLayout = new QVBoxLayout (baseWidget); + auto *baseLayout = new QVBoxLayout (baseWidget); baseLayout->setContentsMargins(0, 0, 0, 0); baseLayout->addWidget (cubeGroupBox, 1/*stretch*/); baseLayout->addWidget (inputGroupBox); } -kpColorSimilarityDialog::~kpColorSimilarityDialog () -{ -} +kpColorSimilarityDialog::~kpColorSimilarityDialog () = default; // public double kpColorSimilarityDialog::colorSimilarity () const { return m_colorSimilarityFrame->colorSimilarity (); } // public void kpColorSimilarityDialog::setColorSimilarity (double similarity) { m_colorSimilarityInput->setValue (qRound (similarity * 100)); } // private slot void kpColorSimilarityDialog::slotColorSimilarityValueChanged () { m_colorSimilarityFrame->setColorSimilarity (double (m_colorSimilarityInput->value ()) / 100); } // private slot void kpColorSimilarityDialog::slotWhatIsLabelClicked () { QWhatsThis::showText(QCursor::pos(), m_colorSimilarityFrame->whatsThis(), this); } diff --git a/dialogs/kpDocumentSaveOptionsPreviewDialog.cpp b/dialogs/kpDocumentSaveOptionsPreviewDialog.cpp index 98565e35..4736e58f 100644 --- a/dialogs/kpDocumentSaveOptionsPreviewDialog.cpp +++ b/dialogs/kpDocumentSaveOptionsPreviewDialog.cpp @@ -1,219 +1,214 @@ /* Copyright (c) 2003-2007 Clarence Dang All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #define DEBUG_KP_DOCUMENT_SAVE_OPTIONS_WIDGET 0 #include "kpDocumentSaveOptionsPreviewDialog.h" #include #include #include #include #include #include #include "kpLogCategories.h" #include #include "commands/kpCommandSize.h" #include "kpDefs.h" #include "document/kpDocument.h" #include "pixmapfx/kpPixmapFX.h" #include "generic/widgets/kpResizeSignallingLabel.h" #include "dialogs/imagelib/transforms/kpTransformPreviewDialog.h" // protected static const QSize kpDocumentSaveOptionsPreviewDialog::s_pixmapLabelMinimumSize (25, 25); kpDocumentSaveOptionsPreviewDialog::kpDocumentSaveOptionsPreviewDialog ( QWidget *parent ) : kpSubWindow (parent), m_filePixmap (nullptr), m_fileSize (0) { setWindowTitle (i18nc ("@title:window", "Save Preview")); - QWidget *baseWidget = this;//new QWidget (this); + auto *baseWidget = this;//new QWidget (this); //setMainWidget (baseWidget); - QGridLayout *lay = new QGridLayout ( baseWidget ); + auto *lay = new QGridLayout ( baseWidget ); m_filePixmapLabel = new kpResizeSignallingLabel (baseWidget); m_fileSizeLabel = new QLabel (baseWidget); m_filePixmapLabel->setMinimumSize (s_pixmapLabelMinimumSize); lay->addWidget (m_filePixmapLabel, 0, 0); lay->addWidget (m_fileSizeLabel, 1, 0, Qt::AlignHCenter); lay->setRowStretch (0, 1); connect (m_filePixmapLabel, &kpResizeSignallingLabel::resized, this, &kpDocumentSaveOptionsPreviewDialog::updatePixmapPreview); } kpDocumentSaveOptionsPreviewDialog::~kpDocumentSaveOptionsPreviewDialog () { delete m_filePixmap; } // public QSize kpDocumentSaveOptionsPreviewDialog::preferredMinimumSize () const { - const int contentsWidth = 180; - const int totalMarginsWidth = fontMetrics ().height (); + const auto contentsWidth = 180; + const auto totalMarginsWidth = fontMetrics ().height (); - return QSize (contentsWidth + totalMarginsWidth, - contentsWidth * 3 / 4 + totalMarginsWidth); + return {contentsWidth + totalMarginsWidth, contentsWidth * 3 / 4 + totalMarginsWidth}; } // public slot void kpDocumentSaveOptionsPreviewDialog::setFilePixmapAndSize (const QImage &pixmap, qint64 fileSize) { delete m_filePixmap; m_filePixmap = new QImage (pixmap); updatePixmapPreview (); m_fileSize = fileSize; const kpCommandSize::SizeType pixmapSize = kpCommandSize::PixmapSize (pixmap); // (int cast is safe as long as the file size is not more than 20 million // -- i.e. INT_MAX / 100 -- times the pixmap size) const int percent = pixmapSize ? qMax (1, static_cast (static_cast (fileSize * 100 / pixmapSize))) : 0; qCDebug(kpLogDialogs) << "kpDocumentSaveOptionsPreviewDialog::setFilePixmapAndSize()" << " pixmapSize=" << pixmapSize << " fileSize=" << fileSize << " raw fileSize/pixmapSize%=" - << (pixmapSize ? (kpCommandSize::SizeType) fileSize * 100 / pixmapSize : 0) - << endl; + << (pixmapSize ? (kpCommandSize::SizeType) fileSize * 100 / pixmapSize : 0); m_fileSizeLabel->setText (i18np ("1 byte (approx. %2%)", "%1 bytes (approx. %2%)", m_fileSize, percent)); } // public slot void kpDocumentSaveOptionsPreviewDialog::updatePixmapPreview () { qCDebug(kpLogDialogs) << "kpDocumentSaveOptionsPreviewDialog::updatePreviewPixmap()" << " filePixmapLabel.size=" << m_filePixmapLabel->size () - << " filePixmap.size=" << m_filePixmap->size () - << endl; + << " filePixmap.size=" << m_filePixmap->size (); if (m_filePixmap) { int maxNewWidth = qMin (m_filePixmap->width (), m_filePixmapLabel->width ()), maxNewHeight = qMin (m_filePixmap->height (), m_filePixmapLabel->height ()); double keepsAspect = kpTransformPreviewDialog::aspectScale ( maxNewWidth, maxNewHeight, m_filePixmap->width (), m_filePixmap->height ()); qCDebug(kpLogDialogs) << "\tmaxNewWidth=" << maxNewWidth << " maxNewHeight=" << maxNewHeight - << " keepsAspect=" << keepsAspect - << endl; + << " keepsAspect=" << keepsAspect; const int newWidth = kpTransformPreviewDialog::scaleDimension ( m_filePixmap->width (), keepsAspect, 1, maxNewWidth); const int newHeight = kpTransformPreviewDialog::scaleDimension ( m_filePixmap->height (), keepsAspect, 1, maxNewHeight); qCDebug(kpLogDialogs) << "\tnewWidth=" << newWidth - << " newHeight=" << newHeight - << endl; + << " newHeight=" << newHeight; QImage transformedPixmap = kpPixmapFX::scale (*m_filePixmap, newWidth, newHeight); QImage labelPixmap (m_filePixmapLabel->width (), m_filePixmapLabel->height (), QImage::Format_ARGB32_Premultiplied); labelPixmap.fill(QColor(Qt::transparent).rgba()); kpPixmapFX::setPixmapAt (&labelPixmap, (labelPixmap.width () - transformedPixmap.width ()) / 2, (labelPixmap.height () - transformedPixmap.height ()) / 2, transformedPixmap); m_filePixmapLabel->setPixmap (QPixmap::fromImage(labelPixmap)); } else { m_filePixmapLabel->setPixmap (QPixmap ()); } } // protected virtual [base QWidget] void kpDocumentSaveOptionsPreviewDialog::closeEvent (QCloseEvent *e) { qCDebug(kpLogDialogs) << "kpDocumentSaveOptionsPreviewDialog::closeEvent()"; QWidget::closeEvent (e); emit finished (); } // protected virtual [base QWidget] void kpDocumentSaveOptionsPreviewDialog::moveEvent (QMoveEvent *e) { qCDebug(kpLogDialogs) << "kpDocumentSaveOptionsPreviewDialog::moveEvent()"; QWidget::moveEvent (e); emit moved (); } // protected virtual [base QWidget] void kpDocumentSaveOptionsPreviewDialog::resizeEvent (QResizeEvent *e) { qCDebug(kpLogDialogs) << "kpDocumentSaveOptionsPreviewDialog::resizeEvent()"; QWidget::resizeEvent (e); emit resized (); } diff --git a/document/kpDocument.cpp b/document/kpDocument.cpp index 60de8ff8..4f712168 100644 --- a/document/kpDocument.cpp +++ b/document/kpDocument.cpp @@ -1,450 +1,448 @@ /* Copyright (c) 2003-2007 Clarence Dang All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #define DEBUG_KP_DOCUMENT 0 #include "kpDocument.h" #include "kpDocumentPrivate.h" #include "layers/selections/kpAbstractSelection.h" #include "layers/selections/image/kpAbstractImageSelection.h" #include "imagelib/kpColor.h" #include "widgets/toolbars/kpColorToolBar.h" #include "kpDefs.h" #include "environments/document/kpDocumentEnvironment.h" #include "document/kpDocumentSaveOptions.h" #include "imagelib/kpDocumentMetaInfo.h" #include "imagelib/effects/kpEffectReduceColors.h" #include "pixmapfx/kpPixmapFX.h" #include "tools/kpTool.h" #include "widgets/toolbars/kpToolToolBar.h" #include "lgpl/generic/kpUrlFormatter.h" #include "kpLogCategories.h" #include // kdelibs4support #include #include #include #include #include #include #include #include #include #include #include #include //--------------------------------------------------------------------- kpDocument::kpDocument (int w, int h, kpDocumentEnvironment *environ) : QObject (), m_constructorWidth (w), m_constructorHeight (h), m_isFromURL (false), m_savedAtLeastOnceBefore (false), m_saveOptions (new kpDocumentSaveOptions ()), m_metaInfo (new kpDocumentMetaInfo ()), m_modified (false), m_selection (nullptr), m_oldWidth (-1), m_oldHeight (-1), d (new kpDocumentPrivate ()) { #if DEBUG_KP_DOCUMENT && 0 qCDebug(kpLogDocument) << "kpDocument::kpDocument (" << w << "," << h << ")"; #endif m_image = new kpImage(w, h, QImage::Format_ARGB32_Premultiplied); m_image->fill(QColor(Qt::white).rgb()); d->environ = environ; } //--------------------------------------------------------------------- kpDocument::~kpDocument () { delete d; delete m_image; delete m_saveOptions; delete m_metaInfo; delete m_selection; } //--------------------------------------------------------------------- // public kpDocumentEnvironment *kpDocument::environ () const { return d->environ; } //--------------------------------------------------------------------- // public void kpDocument::setEnviron (kpDocumentEnvironment *environ) { d->environ = environ; } //--------------------------------------------------------------------- // public bool kpDocument::savedAtLeastOnceBefore () const { return m_savedAtLeastOnceBefore; } //--------------------------------------------------------------------- // public QUrl kpDocument::url () const { return m_url; } //--------------------------------------------------------------------- // public void kpDocument::setURL (const QUrl &url, bool isFromURL) { m_url = url; m_isFromURL = isFromURL; } //--------------------------------------------------------------------- // public bool kpDocument::isFromURL (bool checkURLStillExists) const { - if (!m_isFromURL) + if (!m_isFromURL) { return false; + } - if (!checkURLStillExists) + if (!checkURLStillExists) { return true; + } return (!m_url.isEmpty () && KIO::NetAccess::exists (m_url, KIO::NetAccess::SourceSide/*open*/, d->environ->dialogParent ())); } //--------------------------------------------------------------------- // public QString kpDocument::prettyUrl () const { return kpUrlFormatter::PrettyUrl (m_url); } //--------------------------------------------------------------------- // public QString kpDocument::prettyFilename () const { return kpUrlFormatter::PrettyFilename (m_url); } //--------------------------------------------------------------------- // public const kpDocumentSaveOptions *kpDocument::saveOptions () const { return m_saveOptions; } //--------------------------------------------------------------------- // public void kpDocument::setSaveOptions (const kpDocumentSaveOptions &saveOptions) { *m_saveOptions = saveOptions; } //--------------------------------------------------------------------- // public const kpDocumentMetaInfo *kpDocument::metaInfo () const { return m_metaInfo; } //--------------------------------------------------------------------- // public void kpDocument::setMetaInfo (const kpDocumentMetaInfo &metaInfo) { *m_metaInfo = metaInfo; } //--------------------------------------------------------------------- /* * Properties */ void kpDocument::setModified (bool yes) { - if (yes == m_modified) + if (yes == m_modified) { return; + } m_modified = yes; - if (yes) + if (yes) { emit documentModified (); + } } //--------------------------------------------------------------------- bool kpDocument::isModified () const { return m_modified; } //--------------------------------------------------------------------- bool kpDocument::isEmpty () const { return url ().isEmpty () && !isModified (); } //--------------------------------------------------------------------- int kpDocument::constructorWidth () const { return m_constructorWidth; } //--------------------------------------------------------------------- int kpDocument::width (bool ofSelection) const { - if (ofSelection && m_selection) - return m_selection->width (); - else - return m_image->width (); + return (ofSelection && m_selection) ? m_selection->width() : m_image->width(); } //--------------------------------------------------------------------- int kpDocument::oldWidth () const { return m_oldWidth; } //--------------------------------------------------------------------- void kpDocument::setWidth (int w, const kpColor &backgroundColor) { resize (w, height (), backgroundColor); } //--------------------------------------------------------------------- int kpDocument::constructorHeight () const { return m_constructorHeight; } //--------------------------------------------------------------------- int kpDocument::height (bool ofSelection) const -{ - if (ofSelection && m_selection) - return m_selection->height (); - else - return m_image->height (); +{ + return (ofSelection && m_selection) ? m_selection->height() : m_image->height(); } //--------------------------------------------------------------------- int kpDocument::oldHeight () const { return m_oldHeight; } //--------------------------------------------------------------------- void kpDocument::setHeight (int h, const kpColor &backgroundColor) { resize (width (), h, backgroundColor); } //--------------------------------------------------------------------- QRect kpDocument::rect (bool ofSelection) const -{ - if (ofSelection && m_selection) - return m_selection->boundingRect (); - else - return m_image->rect (); +{ + return (ofSelection && m_selection) ? m_selection->boundingRect() : m_image->rect(); } //--------------------------------------------------------------------- // public kpImage kpDocument::getImageAt (const QRect &rect) const { return kpPixmapFX::getPixmapAt (*m_image, rect); } //--------------------------------------------------------------------- // public void kpDocument::setImageAt (const kpImage &image, const QPoint &at) { qCDebug(kpLogDocument) << "kpDocument::setImageAt (image (w=" << image.width () << ",h=" << image.height () << "), x=" << at.x () - << ",y=" << at.y () - << endl; + << ",y=" << at.y (); kpPixmapFX::setPixmapAt (m_image, at, image); slotContentsChanged (QRect (at.x (), at.y (), image.width (), image.height ())); } //--------------------------------------------------------------------- // public kpImage kpDocument::image (bool ofSelection) const { kpImage ret; if (ofSelection) { kpAbstractImageSelection *imageSel = imageSelection (); Q_ASSERT (imageSel); ret = imageSel->baseImage (); } - else + else { ret = *m_image; + } return ret; } //--------------------------------------------------------------------- // public kpImage *kpDocument::imagePointer () const { return m_image; } //--------------------------------------------------------------------- // public void kpDocument::setImage (const kpImage &image) { m_oldWidth = width (); m_oldHeight = height (); *m_image = image; - if (m_oldWidth == width () && m_oldHeight == height ()) + if (m_oldWidth == width () && m_oldHeight == height ()) { slotContentsChanged (image.rect ()); - else + } + else { slotSizeChanged (QSize (width (), height ())); + } } //--------------------------------------------------------------------- // public void kpDocument::setImage (bool ofSelection, const kpImage &image) { if (ofSelection) { kpAbstractImageSelection *imageSel = imageSelection (); // Have to have an image selection in order to set its pixmap. Q_ASSERT (imageSel); imageSel->setBaseImage (image); } - else + else { setImage (image); + } } //--------------------------------------------------------------------- void kpDocument::fill (const kpColor &color) { qCDebug(kpLogDocument) << "kpDocument::fill ()"; m_image->fill(color.toQRgb()); slotContentsChanged (m_image->rect ()); } //--------------------------------------------------------------------- void kpDocument::resize (int w, int h, const kpColor &backgroundColor) { qCDebug(kpLogDocument) << "kpDocument::resize (" << w << "," << h << ")"; m_oldWidth = width (); m_oldHeight = height (); qCDebug(kpLogDocument) << "\toldWidth=" << m_oldWidth - << " oldHeight=" << m_oldHeight - << endl; + << " oldHeight=" << m_oldHeight; - if (w == m_oldWidth && h == m_oldHeight) + if (w == m_oldWidth && h == m_oldHeight) { return; + } kpPixmapFX::resize (m_image, w, h, backgroundColor); slotSizeChanged (QSize (width (), height ())); } //--------------------------------------------------------------------- void kpDocument::slotContentsChanged (const QRect &rect) { setModified (); emit contentsChanged (rect); } //--------------------------------------------------------------------- void kpDocument::slotSizeChanged (const QSize &newSize) { setModified (); emit sizeChanged (newSize.width(), newSize.height()); emit sizeChanged (newSize); } //--------------------------------------------------------------------- diff --git a/document/kpDocumentSaveOptions.cpp b/document/kpDocumentSaveOptions.cpp index 7b54a65f..57828e86 100644 --- a/document/kpDocumentSaveOptions.cpp +++ b/document/kpDocumentSaveOptions.cpp @@ -1,623 +1,618 @@ /* Copyright (c) 2003-2007 Clarence Dang All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #define DEBUG_KP_DOCUMENT_SAVE_OPTIONS 0 #include "kpDocumentSaveOptions.h" #include "kpDefs.h" #include "pixmapfx/kpPixmapFX.h" #include #include "kpLogCategories.h" #include #include #include #include //--------------------------------------------------------------------- class kpDocumentSaveOptionsPrivate { public: QString m_mimeType; - int m_colorDepth; - bool m_dither; - int m_quality; + int m_colorDepth{}; + bool m_dither{}; + int m_quality{}; }; //--------------------------------------------------------------------- kpDocumentSaveOptions::kpDocumentSaveOptions () : d (new kpDocumentSaveOptionsPrivate ()) { d->m_mimeType = invalidMimeType (); d->m_colorDepth = invalidColorDepth (); d->m_dither = initialDither (); d->m_quality = invalidQuality (); } //--------------------------------------------------------------------- kpDocumentSaveOptions::kpDocumentSaveOptions (const kpDocumentSaveOptions &rhs) : d (new kpDocumentSaveOptionsPrivate ()) { d->m_mimeType = rhs.mimeType (); d->m_colorDepth = rhs.colorDepth (); d->m_dither = rhs.dither (); d->m_quality = rhs.quality (); } //--------------------------------------------------------------------- kpDocumentSaveOptions::kpDocumentSaveOptions (QString mimeType, int colorDepth, bool dither, int quality) : d (new kpDocumentSaveOptionsPrivate ()) { d->m_mimeType = mimeType; d->m_colorDepth = colorDepth; d->m_dither = dither; d->m_quality = quality; } //--------------------------------------------------------------------- kpDocumentSaveOptions::~kpDocumentSaveOptions () { delete d; } //--------------------------------------------------------------------- // public bool kpDocumentSaveOptions::operator== (const kpDocumentSaveOptions &rhs) const { return (mimeType () == rhs.mimeType () && colorDepth () == rhs.colorDepth () && dither () == rhs.dither () && quality () == rhs.quality ()); } //--------------------------------------------------------------------- // public bool kpDocumentSaveOptions::operator!= (const kpDocumentSaveOptions &rhs) const { return !(*this == rhs); } //--------------------------------------------------------------------- // public kpDocumentSaveOptions &kpDocumentSaveOptions::operator= (const kpDocumentSaveOptions &rhs) { setMimeType (rhs.mimeType ()); setColorDepth (rhs.colorDepth ()); setDither (rhs.dither ()); setQuality (rhs.quality ()); return *this; } //--------------------------------------------------------------------- // public void kpDocumentSaveOptions::printDebug (const QString &prefix) const { const QString usedPrefix = !prefix.isEmpty () ? prefix + QLatin1String (": ") : QString(); qCDebug(kpLogDocument) << usedPrefix << "mimeType=" << mimeType () << " colorDepth=" << colorDepth () << " dither=" << dither () - << " quality=" << quality () - << endl; + << " quality=" << quality (); } //--------------------------------------------------------------------- // public QString kpDocumentSaveOptions::mimeType () const { return d->m_mimeType; } //--------------------------------------------------------------------- // public void kpDocumentSaveOptions::setMimeType (const QString &mimeType) { d->m_mimeType = mimeType; } //--------------------------------------------------------------------- // public static QString kpDocumentSaveOptions::invalidMimeType () { return QString(); } //--------------------------------------------------------------------- // public static bool kpDocumentSaveOptions::mimeTypeIsInvalid (const QString &mimeType) { return (mimeType == invalidMimeType ()); } //--------------------------------------------------------------------- // public bool kpDocumentSaveOptions::mimeTypeIsInvalid () const { return mimeTypeIsInvalid (mimeType ()); } //--------------------------------------------------------------------- // public int kpDocumentSaveOptions::colorDepth () const { return d->m_colorDepth; } // public void kpDocumentSaveOptions::setColorDepth (int depth) { d->m_colorDepth = depth; } // public static int kpDocumentSaveOptions::invalidColorDepth () { return -1; } // public static bool kpDocumentSaveOptions::colorDepthIsInvalid (int colorDepth) { return (colorDepth != 1 && colorDepth != 8 && colorDepth != 32); } // public bool kpDocumentSaveOptions::colorDepthIsInvalid () const { return colorDepthIsInvalid (colorDepth ()); } // public bool kpDocumentSaveOptions::dither () const { return d->m_dither; } // public void kpDocumentSaveOptions::setDither (bool dither) { d->m_dither = dither; } // public static int kpDocumentSaveOptions::initialDither () { return false; // to avoid accidental double dithering } // public int kpDocumentSaveOptions::quality () const { return d->m_quality; } // public void kpDocumentSaveOptions::setQuality (int quality) { d->m_quality = quality; } // public static int kpDocumentSaveOptions::invalidQuality () { return -2; } // public static bool kpDocumentSaveOptions::qualityIsInvalid (int quality) { return (quality < -1 || quality > 100); } // public bool kpDocumentSaveOptions::qualityIsInvalid () const { return qualityIsInvalid (quality ()); } // public static QString kpDocumentSaveOptions::defaultMimeType (const KConfigGroup &config) { return config.readEntry (kpSettingForcedMimeType, QString::fromLatin1 ("image/png")); } // public static void kpDocumentSaveOptions::saveDefaultMimeType (KConfigGroup &config, const QString &mimeType) { config.writeEntry (kpSettingForcedMimeType, mimeType); } // public static int kpDocumentSaveOptions::defaultColorDepth (const KConfigGroup &config) { int colorDepth = config.readEntry (kpSettingForcedColorDepth, -1); if (colorDepthIsInvalid (colorDepth)) { // (not screen depth, in case of transparency) colorDepth = 32; } return colorDepth; } //--------------------------------------------------------------------- // public static void kpDocumentSaveOptions::saveDefaultColorDepth (KConfigGroup &config, int colorDepth) { config.writeEntry (kpSettingForcedColorDepth, colorDepth); } //--------------------------------------------------------------------- // public static int kpDocumentSaveOptions::defaultDither (const KConfigGroup &config) { return config.readEntry (kpSettingForcedDither, initialDither ()); } //--------------------------------------------------------------------- // public static void kpDocumentSaveOptions::saveDefaultDither (KConfigGroup &config, bool dither) { config.writeEntry (kpSettingForcedDither, dither); } //--------------------------------------------------------------------- // public static int kpDocumentSaveOptions::defaultQuality (const KConfigGroup &config) { int val = config.readEntry (kpSettingForcedQuality, -1); - if (qualityIsInvalid (val)) - val = -1; - return val; + return qualityIsInvalid (val) ? -1 : val; } //--------------------------------------------------------------------- // public static void kpDocumentSaveOptions::saveDefaultQuality (KConfigGroup &config, int quality) { config.writeEntry (kpSettingForcedQuality, quality); } //--------------------------------------------------------------------- // public static kpDocumentSaveOptions kpDocumentSaveOptions::defaultDocumentSaveOptions (const KConfigGroup &config) { kpDocumentSaveOptions saveOptions; saveOptions.setMimeType (defaultMimeType (config)); saveOptions.setColorDepth (defaultColorDepth (config)); saveOptions.setDither (defaultDither (config)); saveOptions.setQuality (defaultQuality (config)); saveOptions.printDebug ("kpDocumentSaveOptions::defaultDocumentSaveOptions()"); return saveOptions; } //--------------------------------------------------------------------- // public static bool kpDocumentSaveOptions::saveDefaultDifferences (KConfigGroup &config, const kpDocumentSaveOptions &oldDocInfo, const kpDocumentSaveOptions &newDocInfo) { bool savedSomething = false; qCDebug(kpLogDocument) << "kpDocumentSaveOptions::saveDefaultDifferences()"; oldDocInfo.printDebug ("\told"); newDocInfo.printDebug ("\tnew"); if (newDocInfo.mimeType () != oldDocInfo.mimeType ()) { saveDefaultMimeType (config, newDocInfo.mimeType ()); savedSomething = true; } if (newDocInfo.colorDepth () != oldDocInfo.colorDepth ()) { saveDefaultColorDepth (config, newDocInfo.colorDepth ()); savedSomething = true; } if (newDocInfo.dither () != oldDocInfo.dither ()) { saveDefaultDither (config, newDocInfo.dither ()); savedSomething = true; } if (newDocInfo.quality () != oldDocInfo.quality ()) { saveDefaultQuality (config, newDocInfo.quality ()); savedSomething = true; } return savedSomething; } //--------------------------------------------------------------------- static QStringList mimeTypesSupportingProperty (const QString &property, const QStringList &defaultMimeTypesWithPropertyList) { QStringList mimeTypeList; KConfigGroup cfg (KSharedConfig::openConfig (), kpSettingsGroupMimeTypeProperties); if (cfg.hasKey (property)) { mimeTypeList = cfg.readEntry (property, QStringList ()); } else { mimeTypeList = defaultMimeTypesWithPropertyList; cfg.writeEntry (property, mimeTypeList); cfg.sync (); } return mimeTypeList; } //--------------------------------------------------------------------- static bool mimeTypeSupportsProperty (const QString &mimeType, const QString &property, const QStringList &defaultMimeTypesWithPropertyList) { - const QStringList mimeTypeList = mimeTypesSupportingProperty ( + const auto mimeTypeList = mimeTypesSupportingProperty ( property, defaultMimeTypesWithPropertyList); return mimeTypeList.contains (mimeType); } //--------------------------------------------------------------------- // SYNC: update mime info // // Only care about writable mimetypes. // // Run: // // branches/kolourpaint/control/scripts/gen_mimetype_line.sh Write | // branches/kolourpaint/control/scripts/split_mimetype_line.pl // // in the version of kdelibs/kimgio/ (e.g. KDE 4.0) KolourPaint is shipped with, // to check for any new mimetypes to add info for. In the methods below, // you can specify this info (maximum color depth, whether it's lossy etc.). // // Update the below list and if you do change any of that info, bump up // "kpSettingsGroupMimeTypeProperties" in kpDefs.h. // // Currently, Depth and Quality settings are mutually exclusive with // Depth overriding Quality. I've currently favoured Quality with the // below mimetypes (i.e. all lossy mimetypes are only given Quality settings, // no Depth settings). // // Mimetypes done: // image/bmp // image/jpeg // image/jp2 // image/png // image/tiff // image/x-eps // image/x-pcx // image/x-portable-bitmap // image/x-portable-graymap // image/x-portable-pixmap // image/x-rgb // image/x-tga // image/x-xbitmap // image/x-xpixmap // video/x-mng [COULD NOT TEST] // // To test whether depth is configurable, write an image in the new // mimetype with all depths and read each one back. See what // kpDocument thinks the depth is when it gets QImage to read it. // public static int kpDocumentSaveOptions::mimeTypeMaximumColorDepth (const QString &mimeType) { QStringList defaultList; // SYNC: update mime info here // Grayscale actually (unenforced since depth not set to configurable) defaultList << QLatin1String ("image/x-eps:32"); defaultList << QLatin1String ("image/x-portable-bitmap:1"); // Grayscale actually (unenforced since depth not set to configurable) defaultList << QLatin1String ("image/x-portable-graymap:8"); defaultList << QLatin1String ("image/x-xbitmap:1"); - const QStringList mimeTypeList = mimeTypesSupportingProperty ( + const auto mimeTypeList = mimeTypesSupportingProperty ( kpSettingMimeTypeMaximumColorDepth, defaultList); const QString mimeTypeColon = mimeType + QLatin1String (":"); - for (QStringList::const_iterator it = mimeTypeList.begin (); - it != mimeTypeList.end (); - ++it) + for (const auto & it : mimeTypeList) { - if ((*it).startsWith (mimeTypeColon)) + if (it.startsWith (mimeTypeColon)) { - int number = (*it).mid (mimeTypeColon.length ()).toInt (); + int number = it.mid (mimeTypeColon.length ()).toInt (); if (!colorDepthIsInvalid (number)) { return number; } } } return 32; } //--------------------------------------------------------------------- // public int kpDocumentSaveOptions::mimeTypeMaximumColorDepth () const { return mimeTypeMaximumColorDepth (mimeType ()); } //--------------------------------------------------------------------- // public static bool kpDocumentSaveOptions::mimeTypeHasConfigurableColorDepth (const QString &mimeType) { QStringList defaultMimeTypes; // SYNC: update mime info here defaultMimeTypes << QLatin1String ("image/png"); defaultMimeTypes << QLatin1String ("image/bmp"); defaultMimeTypes << QLatin1String ("image/x-pcx"); // TODO: Only 1, 24 not 8; Qt only sees 32 but "file" cmd realizes // it's either 1 or 24. defaultMimeTypes << QLatin1String ("image/x-rgb"); // TODO: Only 8 and 24 - no 1. defaultMimeTypes << QLatin1String ("image/x-xpixmap"); return mimeTypeSupportsProperty (mimeType, kpSettingMimeTypeHasConfigurableColorDepth, defaultMimeTypes); } //--------------------------------------------------------------------- // public bool kpDocumentSaveOptions::mimeTypeHasConfigurableColorDepth () const { return mimeTypeHasConfigurableColorDepth (mimeType ()); } //--------------------------------------------------------------------- // public static bool kpDocumentSaveOptions::mimeTypeHasConfigurableQuality (const QString &mimeType) { QStringList defaultMimeTypes; // SYNC: update mime info here defaultMimeTypes << QLatin1String ("image/jp2"); defaultMimeTypes << QLatin1String ("image/jpeg"); defaultMimeTypes << QLatin1String ("image/x-webp"); return mimeTypeSupportsProperty (mimeType, kpSettingMimeTypeHasConfigurableQuality, defaultMimeTypes); } //--------------------------------------------------------------------- // public bool kpDocumentSaveOptions::mimeTypeHasConfigurableQuality () const { return mimeTypeHasConfigurableQuality (mimeType ()); } //--------------------------------------------------------------------- // public int kpDocumentSaveOptions::isLossyForSaving (const QImage &image) const { - int ret = 0; + auto ret = 0; if (mimeTypeMaximumColorDepth () < image.depth ()) { ret |= MimeTypeMaximumColorDepthLow; } if (mimeTypeHasConfigurableColorDepth () && !colorDepthIsInvalid () /*REFACTOR: guarantee it is valid*/ && ((colorDepth () < image.depth ()) || (colorDepth () < 32 && image.hasAlphaChannel()))) { ret |= ColorDepthLow; } if (mimeTypeHasConfigurableQuality () && !qualityIsInvalid ()) { ret |= Quality; } return ret; } //--------------------------------------------------------------------- diff --git a/document/kpDocument_Open.cpp b/document/kpDocument_Open.cpp index 8ab44f53..cac002e1 100644 --- a/document/kpDocument_Open.cpp +++ b/document/kpDocument_Open.cpp @@ -1,229 +1,233 @@ /* Copyright (c) 2003-2007 Clarence Dang All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #define DEBUG_KP_DOCUMENT 0 #include "kpDocument.h" #include "kpDocumentPrivate.h" #include "imagelib/kpColor.h" #include "widgets/toolbars/kpColorToolBar.h" #include "kpDefs.h" #include "environments/document/kpDocumentEnvironment.h" #include "document/kpDocumentSaveOptions.h" #include "imagelib/kpDocumentMetaInfo.h" #include "imagelib/effects/kpEffectReduceColors.h" #include "pixmapfx/kpPixmapFX.h" #include "tools/kpTool.h" #include "lgpl/generic/kpUrlFormatter.h" #include "views/manager/kpViewManager.h" #include #include #include #include #include "kpLogCategories.h" #include // kdelibs4support #include #include //--------------------------------------------------------------------- void kpDocument::getDataFromImage(const QImage &image, kpDocumentSaveOptions &saveOptions, kpDocumentMetaInfo &metaInfo) { saveOptions.setColorDepth(image.depth()); saveOptions.setDither(false); // avoid double dithering when saving metaInfo.setDotsPerMeterX(image.dotsPerMeterX()); metaInfo.setDotsPerMeterY(image.dotsPerMeterY()); metaInfo.setOffset(image.offset()); QStringList keys = image.textKeys(); - for (int i = 0; i < keys.count(); i++) - metaInfo.setText(keys[i], image.text(keys[i])); + for (int i = 0; i < keys.count(); i++) { + metaInfo.setText(keys[i], image.text(keys[i])); + } } //--------------------------------------------------------------------- // public static QImage kpDocument::getPixmapFromFile(const QUrl &url, bool suppressDoesntExistDialog, QWidget *parent, kpDocumentSaveOptions *saveOptions, kpDocumentMetaInfo *metaInfo) { qCDebug(kpLogDocument) << "kpDocument::getPixmapFromFile(" << url << "," << parent << ")"; - if (saveOptions) + if (saveOptions) { *saveOptions = kpDocumentSaveOptions (); + } - if (metaInfo) + if (metaInfo) { *metaInfo = kpDocumentMetaInfo (); + } QString tempFile; if (url.isEmpty () || !KIO::NetAccess::download (url, tempFile, parent)) { if (!suppressDoesntExistDialog) { // TODO: Use "Cannot" instead of "Could not" in all dialogs in KolourPaint. // Or at least choose one consistently. // // TODO: Have captions for all dialogs in KolourPaint. KMessageBox::sorry (parent, i18n ("Could not open \"%1\".", kpUrlFormatter::PrettyFilename (url))); } return QImage (); } QMimeDatabase db; QMimeType mimeType = db.mimeTypeForFile(tempFile); - if (saveOptions) + if (saveOptions) { saveOptions->setMimeType(mimeType.name()); + } qCDebug(kpLogDocument) << "\ttempFile=" << tempFile; qCDebug(kpLogDocument) << "\tmimetype=" << mimeType.name(); qCDebug(kpLogDocument) << "\tsrc=" << url.path (); QImageReader reader(tempFile); reader.setAutoTransform(true); reader.setDecideFormatFromContent(true); QImage image = reader.read(); KIO::NetAccess::removeTempFile(tempFile); if (image.isNull ()) { KMessageBox::sorry (parent, i18n ("Could not open \"%1\" - unsupported image format.\n" "The file may be corrupt.", kpUrlFormatter::PrettyFilename (url))); return QImage (); } qCDebug(kpLogDocument) << "\tpixmap: depth=" << image.depth () - << " hasAlphaChannel=" << image.hasAlphaChannel () - << endl; + << " hasAlphaChannel=" << image.hasAlphaChannel (); - if ( saveOptions && metaInfo ) - getDataFromImage(image, *saveOptions, *metaInfo); + if ( saveOptions && metaInfo ) { + getDataFromImage(image, *saveOptions, *metaInfo); + } // make sure we always have Format_ARGB32_Premultiplied as this is the fastest to draw on // and Qt can not draw onto Format_Indexed8 (Qt-4.7) - if ( image.format() != QImage::Format_ARGB32_Premultiplied ) + if ( image.format() != QImage::Format_ARGB32_Premultiplied ) { image = image.convertToFormat(QImage::Format_ARGB32_Premultiplied); + } return image; } //--------------------------------------------------------------------- void kpDocument::openNew (const QUrl &url) { qCDebug(kpLogDocument) << "kpDocument::openNew (" << url << ")"; m_image->fill(QColor(Qt::white).rgb()); setURL (url, false/*not from url*/); *m_saveOptions = kpDocumentSaveOptions (); if ( !url.isEmpty() ) { // guess the mimetype from url's filename extension. // // That way "kolourpaint doesnotexist.bmp" automatically // selects the BMP file format when the save dialog comes up for // the first time. QMimeDatabase mimeDb; m_saveOptions->setMimeType(mimeDb.mimeTypeForUrl(url).name()); } *m_metaInfo = kpDocumentMetaInfo (); m_modified = false; emit documentOpened (); } //--------------------------------------------------------------------- bool kpDocument::open (const QUrl &url, bool newDocSameNameIfNotExist) { qCDebug(kpLogDocument) << "kpDocument::open (" << url << ")"; kpDocumentSaveOptions newSaveOptions; kpDocumentMetaInfo newMetaInfo; QImage newPixmap = kpDocument::getPixmapFromFile (url, newDocSameNameIfNotExist/*suppress "doesn't exist" dialog*/, d->environ->dialogParent (), &newSaveOptions, &newMetaInfo); if (!newPixmap.isNull ()) { delete m_image; m_image = new kpImage (newPixmap); setURL (url, true/*is from url*/); *m_saveOptions = newSaveOptions; *m_metaInfo = newMetaInfo; m_modified = false; emit documentOpened (); return true; } if (newDocSameNameIfNotExist) { if (!url.isEmpty () && // not just a permission error? !KIO::NetAccess::exists (url, KIO::NetAccess::SourceSide/*open*/, d->environ->dialogParent ())) { openNew (url); } else { openNew (QUrl ()); } return true; } - else - { - return false; - } + + return false; + } //--------------------------------------------------------------------- diff --git a/document/kpDocument_Save.cpp b/document/kpDocument_Save.cpp index c95256a7..c65ffd1f 100644 --- a/document/kpDocument_Save.cpp +++ b/document/kpDocument_Save.cpp @@ -1,466 +1,466 @@ /* Copyright (c) 2003-2007 Clarence Dang All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #define DEBUG_KP_DOCUMENT 0 #include "kpDocument.h" #include "kpDocumentPrivate.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "kpLogCategories.h" #include // kdelibs4support #include // kdelibs4support #include #include #include "imagelib/kpColor.h" #include "widgets/toolbars/kpColorToolBar.h" #include "kpDefs.h" #include "environments/document/kpDocumentEnvironment.h" #include "document/kpDocumentSaveOptions.h" #include "imagelib/kpDocumentMetaInfo.h" #include "imagelib/effects/kpEffectReduceColors.h" #include "pixmapfx/kpPixmapFX.h" #include "tools/kpTool.h" #include "widgets/toolbars/kpToolToolBar.h" #include "lgpl/generic/kpUrlFormatter.h" #include "views/manager/kpViewManager.h" bool kpDocument::save (bool overwritePrompt, bool lossyPrompt) { qCDebug(kpLogDocument) << "kpDocument::save(" << "overwritePrompt=" << overwritePrompt << ",lossyPrompt=" << lossyPrompt << ") url=" << m_url - << " savedAtLeastOnceBefore=" << savedAtLeastOnceBefore () - << endl; + << " savedAtLeastOnceBefore=" << savedAtLeastOnceBefore (); // TODO: check feels weak if (m_url.isEmpty () || m_saveOptions->mimeType ().isEmpty ()) { KMessageBox::detailedError (d->environ->dialogParent (), i18n ("Could not save image - insufficient information."), i18n ("URL: %1\n" "Mimetype: %2", prettyUrl (), m_saveOptions->mimeType ().isEmpty () ? i18n ("") : m_saveOptions->mimeType ()), i18nc ("@title:window", "Internal Error")); return false; } return saveAs (m_url, *m_saveOptions, overwritePrompt, lossyPrompt); } //--------------------------------------------------------------------- // public static bool kpDocument::lossyPromptContinue (const QImage &pixmap, const kpDocumentSaveOptions &saveOptions, QWidget *parent) { qCDebug(kpLogDocument) << "kpDocument::lossyPromptContinue()"; #define QUIT_IF_CANCEL(messageBoxCommand) \ { \ if (messageBoxCommand != KMessageBox::Continue) \ { \ return false; \ } \ } const int lossyType = saveOptions.isLossyForSaving (pixmap); if (lossyType & (kpDocumentSaveOptions::MimeTypeMaximumColorDepthLow | kpDocumentSaveOptions::Quality)) { QMimeDatabase db; QUIT_IF_CANCEL ( KMessageBox::warningContinueCancel (parent, i18n ("

The %1 format may not be able" " to preserve all of the image's color information.

" "

Are you sure you want to save in this format?

", db.mimeTypeForName(saveOptions.mimeType()).comment()), // TODO: caption misleading for lossless formats that have // low maximum colour depth i18nc ("@title:window", "Lossy File Format"), KStandardGuiItem::save (), KStandardGuiItem::cancel(), QLatin1String ("SaveInLossyMimeTypeDontAskAgain"))); } else if (lossyType & kpDocumentSaveOptions::ColorDepthLow) { QUIT_IF_CANCEL ( KMessageBox::warningContinueCancel (parent, i18n ("

Saving the image at the low color depth of %1-bit" " may result in the loss of color information." // TODO: It looks like 8-bit QImage's now support alpha. // Update kpDocumentSaveOptions::isLossyForSaving() // and change "might" to "will". " Any transparency might also be removed.

" "

Are you sure you want to save at this color depth?

", saveOptions.colorDepth ()), i18nc ("@title:window", "Low Color Depth"), KStandardGuiItem::save (), KStandardGuiItem::cancel(), QLatin1String ("SaveAtLowColorDepthDontAskAgain"))); } #undef QUIT_IF_CANCEL return true; } //--------------------------------------------------------------------- // public static bool kpDocument::savePixmapToDevice (const QImage &image, QIODevice *device, const kpDocumentSaveOptions &saveOptions, const kpDocumentMetaInfo &metaInfo, bool lossyPrompt, QWidget *parent, bool *userCancelled) { - if (userCancelled) + if (userCancelled) { *userCancelled = false; + } QStringList types = KImageIO::typeForMime (saveOptions.mimeType ()); qCDebug(kpLogDocument) << "\ttypes=" << types; - if (types.isEmpty ()) + if (types.isEmpty ()) { return false; - + } // It's safe to arbitrarily choose the 0th type as any type in the list // should invoke the same KImageIO image loader. const QString type = types [0]; qCDebug(kpLogDocument) << "\tmimeType=" << saveOptions.mimeType () - << " type=" << type << endl; + << " type=" << type; if (lossyPrompt && !lossyPromptContinue (image, saveOptions, parent)) { - if (userCancelled) + if (userCancelled) { *userCancelled = true; + } qCDebug(kpLogDocument) << "\treturning false because of lossyPrompt"; return false; } // TODO: fix dup with kpDocumentSaveOptions::isLossyForSaving() const bool useSaveOptionsColorDepth = (saveOptions.mimeTypeHasConfigurableColorDepth () && !saveOptions.colorDepthIsInvalid ()); const bool useSaveOptionsQuality = (saveOptions.mimeTypeHasConfigurableQuality () && !saveOptions.qualityIsInvalid ()); // // Reduce colors if required // qCDebug(kpLogDocument) << "\tuseSaveOptionsColorDepth=" << useSaveOptionsColorDepth << "current image depth=" << image.depth () << "save options depth=" << saveOptions.colorDepth (); QImage imageToSave(image); if (useSaveOptionsColorDepth && imageToSave.depth () != saveOptions.colorDepth ()) { // TODO: I think this erases the mask! // // I suspect this doesn't matter since this is only called to // reduce color depth and QImage's with depth < 32 don't // support masks anyway. // // Later: I think the mask is preserved for 8-bit since Qt4 // seems to support it for QImage. imageToSave = kpEffectReduceColors::convertImageDepth (imageToSave, saveOptions.colorDepth (), saveOptions.dither ()); } // // Write Meta Info // imageToSave.setDotsPerMeterX (metaInfo.dotsPerMeterX ()); imageToSave.setDotsPerMeterY (metaInfo.dotsPerMeterY ()); imageToSave.setOffset (metaInfo.offset ()); QList keyList = metaInfo.textKeys (); for (QList ::const_iterator it = keyList.constBegin (); it != keyList.constEnd (); ++it) { imageToSave.setText (*it, metaInfo.text (*it)); } // // Save at required quality // int quality = -1; // default - if (useSaveOptionsQuality) + if (useSaveOptionsQuality) { quality = saveOptions.quality (); + } qCDebug(kpLogDocument) << "\tsaving"; if (!imageToSave.save (device, type.toLatin1 (), quality)) { qCDebug(kpLogDocument) << "\tQImage::save() returned false"; return false; } qCDebug(kpLogDocument) << "\tsave OK"; return true; } //--------------------------------------------------------------------- static void CouldNotCreateTemporaryFileDialog (QWidget *parent) { KMessageBox::error (parent, i18n ("Could not save image - unable to create temporary file.")); } //--------------------------------------------------------------------- static void CouldNotSaveDialog (const QUrl &url, QWidget *parent) { // TODO: use file.errorString() KMessageBox::error (parent, i18n ("Could not save as \"%1\".", kpUrlFormatter::PrettyFilename (url))); } //--------------------------------------------------------------------- // public static bool kpDocument::savePixmapToFile (const QImage &pixmap, const QUrl &url, const kpDocumentSaveOptions &saveOptions, const kpDocumentMetaInfo &metaInfo, bool overwritePrompt, bool lossyPrompt, QWidget *parent) { // TODO: Use KIO::NetAccess:mostLocalURL() for accessing home:/ (and other // such local URLs) for efficiency and because only local writes // are atomic. qCDebug(kpLogDocument) << "kpDocument::savePixmapToFile (" << url << ",overwritePrompt=" << overwritePrompt << ",lossyPrompt=" << lossyPrompt - << ")" << endl; + << ")"; saveOptions.printDebug (QLatin1String ("\tsaveOptions")); metaInfo.printDebug (QLatin1String ("\tmetaInfo")); if (overwritePrompt && KIO::NetAccess::exists (url, KIO::NetAccess::DestinationSide/*write*/, parent)) { int result = KMessageBox::warningContinueCancel (parent, i18n ("A document called \"%1\" already exists.\n" "Do you want to overwrite it?", kpUrlFormatter::PrettyFilename (url)), QString(), KStandardGuiItem::overwrite ()); if (result != KMessageBox::Continue) { qCDebug(kpLogDocument) << "\tuser doesn't want to overwrite"; return false; } } if (lossyPrompt && !lossyPromptContinue (pixmap, saveOptions, parent)) { qCDebug(kpLogDocument) << "\treturning false because of lossyPrompt"; return false; } // Local file? if (url.isLocalFile ()) { const QString filename = url.toLocalFile (); // sync: All failure exit paths _must_ call QSaveFile::cancelWriting() or // else, the QSaveFile destructor will overwrite the file, // , despite the failure. QSaveFile atomicFileWriter (filename); { if (!atomicFileWriter.open (QIODevice::WriteOnly)) { // We probably don't need this as has not been // opened. atomicFileWriter.cancelWriting (); qCDebug(kpLogDocument) << "\treturning false because could not open QSaveFile" << " error=" << atomicFileWriter.error (); ::CouldNotCreateTemporaryFileDialog (parent); return false; } // Write to local temporary file. if (!savePixmapToDevice (pixmap, &atomicFileWriter, saveOptions, metaInfo, false/*no lossy prompt*/, parent)) { atomicFileWriter.cancelWriting (); qCDebug(kpLogDocument) << "\treturning false because could not save pixmap to device"; ::CouldNotSaveDialog (url, parent); return false; } // Atomically overwrite local file with the temporary file // we saved to. if (!atomicFileWriter.commit ()) { atomicFileWriter.cancelWriting (); qCDebug(kpLogDocument) << "\tcould not close QSaveFile"; ::CouldNotSaveDialog (url, parent); return false; } } // sync QSaveFile.cancelWriting() } // Remote file? else { // Create temporary file that is deleted when the variable goes // out of scope. QTemporaryFile tempFile; if (!tempFile.open ()) { qCDebug(kpLogDocument) << "\treturning false because could not open tempFile"; ::CouldNotCreateTemporaryFileDialog (parent); return false; } // Write to local temporary file. if (!savePixmapToDevice (pixmap, &tempFile, saveOptions, metaInfo, false/*no lossy prompt*/, parent)) { qCDebug(kpLogDocument) << "\treturning false because could not save pixmap to device"; ::CouldNotSaveDialog (url, parent); return false; } // Collect name of temporary file now, as QTemporaryFile::fileName() // stops working after close() is called. const QString tempFileName = tempFile.fileName (); qCDebug(kpLogDocument) << "\ttempFileName='" << tempFileName << "'"; Q_ASSERT (!tempFileName.isEmpty ()); tempFile.close (); if (tempFile.error () != QFile::NoError) { qCDebug(kpLogDocument) << "\treturning false because could not close"; ::CouldNotSaveDialog (url, parent); return false; } // Copy local temporary file to overwrite remote. // TODO: No one seems to know how to do this atomically // [http://lists.kde.org/?l=kde-core-devel&m=117845162728484&w=2]. // At least, fish:// (ssh) is definitely not atomic. if (!KIO::NetAccess::upload (tempFileName, url, parent)) { qCDebug(kpLogDocument) << "\treturning false because could not upload"; KMessageBox::error (parent, i18n ("Could not save image - failed to upload.")); return false; } } return true; } //--------------------------------------------------------------------- bool kpDocument::saveAs (const QUrl &url, const kpDocumentSaveOptions &saveOptions, bool overwritePrompt, bool lossyPrompt) { qCDebug(kpLogDocument) << "kpDocument::saveAs (" << url << "," << saveOptions.mimeType () << ")"; if (kpDocument::savePixmapToFile (imageWithSelection (), url, saveOptions, *metaInfo (), overwritePrompt, lossyPrompt, d->environ->dialogParent ())) { setURL (url, true/*is from url*/); *m_saveOptions = saveOptions; m_modified = false; m_savedAtLeastOnceBefore = true; emit documentSaved (); return true; } - else - { - return false; - } + + return false; } //--------------------------------------------------------------------- diff --git a/document/kpDocument_Selection.cpp b/document/kpDocument_Selection.cpp index e7ba1fd2..2a86bc8b 100644 --- a/document/kpDocument_Selection.cpp +++ b/document/kpDocument_Selection.cpp @@ -1,327 +1,336 @@ /* Copyright (c) 2003-2007 Clarence Dang All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #define DEBUG_KP_DOCUMENT 0 #include "kpDocument.h" #include "kpDocumentPrivate.h" #include #include #include #include "kpLogCategories.h" #include #include "imagelib/kpColor.h" #include "kpDefs.h" #include "environments/document/kpDocumentEnvironment.h" #include "layers/selections/kpAbstractSelection.h" #include "layers/selections/image/kpAbstractImageSelection.h" #include "layers/selections/text/kpTextSelection.h" // public kpAbstractSelection *kpDocument::selection () const { return m_selection; } //--------------------------------------------------------------------- // public kpAbstractImageSelection *kpDocument::imageSelection () const { return dynamic_cast (m_selection); } //--------------------------------------------------------------------- // public kpTextSelection *kpDocument::textSelection () const { return dynamic_cast (m_selection); } //--------------------------------------------------------------------- // public void kpDocument::setSelection (const kpAbstractSelection &selection) { qCDebug(kpLogDocument) << "kpDocument::setSelection() sel boundingRect=" - << selection.boundingRect () - << endl; + << selection.boundingRect (); d->environ->setQueueViewUpdates (); { const bool hadSelection = static_cast (m_selection); - kpAbstractSelection *oldSelection = m_selection; + auto *oldSelection = m_selection; // (must be called before giving the document a new selection, to // avoid a potential mess where switchToCompatibleTool() ends // the current selection tool, killing the new selection) bool isTextChanged = false; d->environ->switchToCompatibleTool (selection, &isTextChanged); Q_ASSERT (m_selection == oldSelection); m_selection = selection.clone (); // There's no need to uninitialize the old selection // (e.g. call disconnect()) since we delete it later. connect (m_selection, &kpAbstractSelection::changed, this, &kpDocument::slotContentsChanged); // // Now all kpDocument state has been set. // We can _only_ change the environment after that, as the environment // may access the document. Exception is above with // switchToCompatibleTool(). // d->environ->assertMatchingUIState (selection); // // Now all kpDocument and environment state has been set. // We can _only_ fire signals after that, as the signal receivers (the // "wider environment") may access the document and the environment. // qCDebug(kpLogDocument) << "\tcheck sel " << (int *) m_selection - << " boundingRect=" << m_selection->boundingRect () - << endl; + << " boundingRect=" << m_selection->boundingRect (); if (oldSelection) { - if (oldSelection->hasContent ()) + if (oldSelection->hasContent ()) { slotContentsChanged (oldSelection->boundingRect ()); - else + } + else { emit contentsChanged (oldSelection->boundingRect ()); + } delete oldSelection; oldSelection = nullptr; } - if (m_selection->hasContent ()) + if (m_selection->hasContent ()) { slotContentsChanged (m_selection->boundingRect ()); - else + } + else { emit contentsChanged (m_selection->boundingRect ()); + } - if (!hadSelection) + if (!hadSelection) { emit selectionEnabled (true); + } - if (isTextChanged) + if (isTextChanged) { emit selectionIsTextChanged (textSelection ()); + } } d->environ->restoreQueueViewUpdates (); qCDebug(kpLogDocument) << "\tkpDocument::setSelection() ended"; } //--------------------------------------------------------------------- // public kpImage kpDocument::getSelectedBaseImage () const { - kpAbstractImageSelection *imageSel = imageSelection (); + auto *imageSel = imageSelection (); Q_ASSERT (imageSel); // Easy if we already have it :) - const kpImage image = imageSel->baseImage (); - if (!image.isNull ()) + const auto image = imageSel->baseImage (); + if (!image.isNull ()) { return image; + } - const QRect boundingRect = imageSel->boundingRect (); + const auto boundingRect = imageSel->boundingRect (); Q_ASSERT (boundingRect.isValid ()); // OPT: This is very slow. Image / More Effects ... calls us twice // unnecessarily. return imageSel->givenImageMaskedByShape (getImageAt (boundingRect)); } //--------------------------------------------------------------------- // public void kpDocument::imageSelectionPullFromDocument (const kpColor &backgroundColor) { - kpAbstractImageSelection *imageSel = imageSelection (); + auto *imageSel = imageSelection (); Q_ASSERT (imageSel); // Should not already have an image or we would not be pulling. Q_ASSERT (!imageSel->hasContent ()); - const QRect boundingRect = imageSel->boundingRect (); + const auto boundingRect = imageSel->boundingRect (); Q_ASSERT (boundingRect.isValid ()); // // Get selection image from document // - kpImage selectedImage = getSelectedBaseImage (); + auto selectedImage = getSelectedBaseImage (); d->environ->setQueueViewUpdates (); imageSel->setBaseImage (selectedImage); // // Fill opaque bits of the hole in the document // #if !defined (QT_NO_DEBUG) && !defined (NDEBUG) if (imageSel->transparency ().isTransparent ()) { Q_ASSERT (backgroundColor == imageSel->transparency ().transparentColor ()); } else { // If this method is begin called by a tool, the assert does not // have to hold since transparentColor() might not be defined in Opaque // Mode. // // If we were called by a tricky sequence of undo/redo commands, the assert // does not have to hold for additional reason, which is that // kpMainWindow::setImageSelectionTransparency() does not have to // set in Opaque Mode. // // In practice, it probably does hold but I wouldn't bet on it. } #endif kpImage eraseImage(boundingRect.size(), QImage::Format_ARGB32_Premultiplied); eraseImage.fill(backgroundColor.toQRgb()); // only paint the region of the shape of the selection QPainter painter(m_image); painter.setClipRegion(imageSel->shapeRegion()); painter.setCompositionMode(QPainter::CompositionMode_Source); painter.drawImage(boundingRect.topLeft(), eraseImage); slotContentsChanged(boundingRect); d->environ->restoreQueueViewUpdates (); } //--------------------------------------------------------------------- // public void kpDocument::selectionDelete () { - if ( !m_selection ) - return; + if ( !m_selection ) { + return; + } - const QRect boundingRect = m_selection->boundingRect (); + const auto boundingRect = m_selection->boundingRect (); Q_ASSERT (boundingRect.isValid ()); - const bool selectionHadContent = m_selection->hasContent (); + const auto selectionHadContent = m_selection->hasContent (); delete m_selection; m_selection = nullptr; // HACK to prevent document from being modified when // user cancels dragging out a new selection // REFACTOR: Extract this out into a method. - if (selectionHadContent) + if (selectionHadContent) { slotContentsChanged (boundingRect); - else + } + else { emit contentsChanged (boundingRect); + } emit selectionEnabled (false); } //--------------------------------------------------------------------- // public void kpDocument::selectionCopyOntoDocument (bool applySelTransparency) { // Empty selection, just doing nothing - if ( !m_selection || !m_selection->hasContent() ) - return; + if ( !m_selection || !m_selection->hasContent() ) { + return; + } const QRect boundingRect = m_selection->boundingRect (); Q_ASSERT (boundingRect.isValid ()); if (imageSelection ()) { - if (applySelTransparency) + if (applySelTransparency) { imageSelection ()->paint (m_image, rect ()); - else + } + else { imageSelection ()->paintWithBaseImage (m_image, rect ()); + } } else { // (for antialiasing with background) m_selection->paint (m_image, rect ()); } slotContentsChanged (boundingRect); } //--------------------------------------------------------------------- // public void kpDocument::selectionPushOntoDocument (bool applySelTransparency) { selectionCopyOntoDocument (applySelTransparency); selectionDelete (); } //--------------------------------------------------------------------- // public kpImage kpDocument::imageWithSelection () const { qCDebug(kpLogDocument) << "kpDocument::imageWithSelection()"; // Have selection? // // It need not have any content because e.g. a text box with an opaque // background, but no content, is still visually there. if (m_selection) { qCDebug(kpLogDocument) << "\tselection @ " << m_selection->boundingRect (); - kpImage output = *m_image; + auto output = *m_image; // (this is a NOP for image selections without content) m_selection->paint (&output, rect ()); return output; } - else - { - qCDebug(kpLogDocument) << "\tno selection"; - return *m_image; - } + + qCDebug(kpLogDocument) << "\tno selection"; + return *m_image; } //--------------------------------------------------------------------- diff --git a/environments/document/kpDocumentEnvironment.cpp b/environments/document/kpDocumentEnvironment.cpp index 44691881..ed8d6425 100644 --- a/environments/document/kpDocumentEnvironment.cpp +++ b/environments/document/kpDocumentEnvironment.cpp @@ -1,195 +1,194 @@ /* Copyright (c) 2003-2007 Clarence Dang All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include "environments/document/kpDocumentEnvironment.h" #include "kpLogCategories.h" #include "mainWindow/kpMainWindow.h" #include "layers/selections/kpAbstractSelection.h" #include "document/kpDocument.h" #include "layers/selections/image/kpEllipticalImageSelection.h" #include "layers/selections/image/kpFreeFormImageSelection.h" #include "layers/selections/image/kpImageSelectionTransparency.h" #include "layers/selections/image/kpRectangularImageSelection.h" #include "layers/selections/text/kpTextSelection.h" #include "layers/selections/text/kpTextStyle.h" #include "tools/kpTool.h" #include "views/manager/kpViewManager.h" struct kpDocumentEnvironmentPrivate { }; kpDocumentEnvironment::kpDocumentEnvironment (kpMainWindow *mainWindow) : kpEnvironmentBase (mainWindow), d (new kpDocumentEnvironmentPrivate ()) { } kpDocumentEnvironment::~kpDocumentEnvironment () { delete d; } // public QWidget *kpDocumentEnvironment::dialogParent () const { return mainWindow (); } static kpViewManager *ViewManager (kpMainWindow *mw) { return mw->viewManager (); } // public void kpDocumentEnvironment::setQueueViewUpdates () const { ::ViewManager (mainWindow ())->setQueueUpdates (); } // public void kpDocumentEnvironment::restoreQueueViewUpdates () const { ::ViewManager (mainWindow ())->restoreQueueUpdates (); } //--------------------------------------------------------------------- // public void kpDocumentEnvironment::switchToCompatibleTool (const kpAbstractSelection &selection, bool *isTextChanged) const { qCDebug(kpLogEnvironments) << "kpDocumentEnvironment::switchToCompatibleTool(" << &selection << ")" << " mainwindow.tool=" - << (mainWindow ()->tool () ? mainWindow ()->tool ()->objectName () : 0) + << (mainWindow ()->tool () ? mainWindow ()->tool ()->objectName () : nullptr) << " mainWindow.toolIsTextTool=" << mainWindow ()->toolIsTextTool () << " current selection=" << document ()->selection () << " new selection is text=" - << dynamic_cast (&selection) - << endl; + << dynamic_cast (&selection); *isTextChanged = (mainWindow ()->toolIsTextTool () != (dynamic_cast (&selection) != nullptr)); // We don't change the Selection Tool if the new selection's // shape is merely different to the current tool's (e.g. rectangular // vs elliptical) because: // // 1. All image selection tools support editing selections of all the // different shapes anyway. // 2. Suppose the user is trying out different drags of selection borders // and then decides to paste a differently shaped selection before continuing // to try out different borders. If the pasting were to switch to // a differently shaped tool, the borders drawn after the paste would // be using a new shape rather than the shape before the paste. This // could get irritating so we don't do the switch. if (!mainWindow ()->toolIsASelectionTool () || *isTextChanged) { // See kpDocument::setSelection() APIDoc for this assumption. Q_ASSERT (!document ()->selection ()); // Switch to the appropriately shaped selection tool // _before_ we change the selection // (all selection tool's ::end() functions nuke the current selection) if (dynamic_cast (&selection)) { qCDebug(kpLogEnvironments) << "\tswitch to rect selection tool"; mainWindow ()->slotToolRectSelection (); } else if (dynamic_cast (&selection)) { qCDebug(kpLogEnvironments) << "\tswitch to elliptical selection tool"; mainWindow ()->slotToolEllipticalSelection (); } else if (dynamic_cast (&selection)) { qCDebug(kpLogEnvironments) << "\tswitch to free form selection tool"; mainWindow ()->slotToolFreeFormSelection (); } else if (dynamic_cast (&selection)) { qCDebug(kpLogEnvironments) << "\tswitch to text selection tool"; mainWindow ()->slotToolText (); } - else + else { Q_ASSERT (!"Unknown selection type"); + } } qCDebug(kpLogEnvironments) << "kpDocumentEnvironment::switchToCompatibleTool(" << &selection << ") finished"; } //--------------------------------------------------------------------- // public void kpDocumentEnvironment::assertMatchingUIState (const kpAbstractSelection &selection) const { // Trap and try to recover from bugs. // TODO: See kpDocument::setSelection() API comment and determine best fix. - const kpAbstractImageSelection *imageSelection = - dynamic_cast (&selection); - const kpTextSelection *textSelection = - dynamic_cast (&selection); + const auto *imageSelection = dynamic_cast (&selection); + const auto *textSelection = dynamic_cast (&selection); + if (imageSelection) { if (imageSelection->transparency () != mainWindow ()->imageSelectionTransparency ()) { qCCritical(kpLogEnvironments) << "kpDocument::setSelection() sel's transparency differs " "from mainWindow's transparency - setting mainWindow's transparency " - "to sel" - << endl; + "to sel"; + qCCritical(kpLogEnvironments) << "\tisOpaque: sel=" << imageSelection->transparency ().isOpaque () - << " mainWindow=" << mainWindow ()->imageSelectionTransparency ().isOpaque () - << endl; + << " mainWindow=" << mainWindow ()->imageSelectionTransparency ().isOpaque (); + mainWindow ()->setImageSelectionTransparency (imageSelection->transparency ()); } } else if (textSelection) { if (textSelection->textStyle () != mainWindow ()->textStyle ()) { qCCritical(kpLogEnvironments) << "kpDocument::setSelection() sel's textStyle differs " "from mainWindow's textStyle - setting mainWindow's textStyle " - "to sel" - << endl; + "to sel"; + mainWindow ()->setTextStyle (textSelection->textStyle ()); } } else { Q_ASSERT (!"Unknown selection type"); } } diff --git a/environments/tools/kpToolEnvironment.cpp b/environments/tools/kpToolEnvironment.cpp index 206ca452..f0346fce 100644 --- a/environments/tools/kpToolEnvironment.cpp +++ b/environments/tools/kpToolEnvironment.cpp @@ -1,216 +1,217 @@ /* Copyright (c) 2003-2007 Clarence Dang All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include "kpToolEnvironment.h" #include "imagelib/kpColor.h" #include "widgets/toolbars/kpColorToolBar.h" #include "mainWindow/kpMainWindow.h" #include "widgets/toolbars/kpToolToolBar.h" #include #include #include #include //-------------------------------------------------------------------------------- bool kpToolEnvironment::drawAntiAliased = true; //-------------------------------------------------------------------------------- struct kpToolEnvironmentPrivate { }; kpToolEnvironment::kpToolEnvironment (kpMainWindow *mainWindow) : kpEnvironmentBase (mainWindow), d (new kpToolEnvironmentPrivate ()) { } kpToolEnvironment::~kpToolEnvironment () { delete d; } // public KActionCollection *kpToolEnvironment::actionCollection () const { return mainWindow ()->actionCollection (); } // public kpCommandHistory *kpToolEnvironment::commandHistory () const { return mainWindow ()->commandHistory (); } // public QActionGroup *kpToolEnvironment::toolsActionGroup () const { return mainWindow ()->toolsActionGroup (); } // public kpToolToolBar *kpToolEnvironment::toolToolBar () const { return mainWindow ()->toolToolBar (); } // public void kpToolEnvironment::hideAllToolWidgets () const { toolToolBar ()->hideAllToolWidgets (); } // public bool kpToolEnvironment::selectPreviousTool () const { kpToolToolBar *tb = toolToolBar (); // (don't end up with no tool selected) - if (!tb->previousTool ()) + if (!tb->previousTool ()) { return false; + } // endInternal() will be called by kpMainWindow (thanks to this line) // so we won't have the view anymore // TODO: Update comment. tb->selectPreviousTool (); return true; } static kpColorToolBar *ColorToolBar (kpMainWindow *mw) { return mw->colorToolBar (); } // public kpColor kpToolEnvironment::color (int which) const { return ::ColorToolBar (mainWindow ())->color (which); } // public double kpToolEnvironment::colorSimilarity () const { return ::ColorToolBar (mainWindow ())->colorSimilarity (); } // public int kpToolEnvironment::processedColorSimilarity () const { return ::ColorToolBar (mainWindow ())->processedColorSimilarity (); } // public kpColor kpToolEnvironment::oldForegroundColor () const { return ::ColorToolBar (mainWindow ())->oldForegroundColor (); } // public kpColor kpToolEnvironment::oldBackgroundColor () const { return ::ColorToolBar (mainWindow ())->oldBackgroundColor (); } // public double kpToolEnvironment::oldColorSimilarity () const { return ::ColorToolBar (mainWindow ())->oldColorSimilarity (); } // public void kpToolEnvironment::flashColorSimilarityToolBarItem () const { ::ColorToolBar (mainWindow ())->flashColorSimilarityToolBarItem (); } // public void kpToolEnvironment::setColor (int which, const kpColor &color) const { kpColorToolBar *toolBar = mainWindow ()->colorToolBar (); Q_ASSERT (toolBar); toolBar->setColor (which, color); } // public void kpToolEnvironment::deleteSelection () const { mainWindow ()->slotDelete (); } // public void kpToolEnvironment::pasteTextAt (const QString &text, const QPoint &point, bool allowNewTextSelectionPointShift) const { mainWindow ()->pasteTextAt (text, point, allowNewTextSelectionPointShift); } // public void kpToolEnvironment::zoomIn (bool centerUnderCursor) const { mainWindow ()->zoomIn (centerUnderCursor); } // public void kpToolEnvironment::zoomOut (bool centerUnderCursor) const { mainWindow ()->zoomOut (centerUnderCursor); } // public void kpToolEnvironment::zoomToRect ( const QRect &normalizedDocRect, bool accountForGrips, bool careAboutWidth, bool careAboutHeight) const { mainWindow ()->zoomToRect ( normalizedDocRect, accountForGrips, careAboutWidth, careAboutHeight); } // public void kpToolEnvironment::fitToPage () const { mainWindow ()->slotFitToPage (); } diff --git a/generic/kpWidgetMapper.cpp b/generic/kpWidgetMapper.cpp index f4ae8982..3483665c 100644 --- a/generic/kpWidgetMapper.cpp +++ b/generic/kpWidgetMapper.cpp @@ -1,76 +1,80 @@ /* Copyright (c) 2003-2007 Clarence Dang All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include "kpWidgetMapper.h" #include #include #include namespace kpWidgetMapper { QPoint fromGlobal (const QWidget *widget, const QPoint &point) { - if (!widget) + if (!widget) { return point; + } return widget->mapFromGlobal (point); } QRect fromGlobal (const QWidget *widget, const QRect &rect) { - if (!widget || !rect.isValid ()) + if (!widget || !rect.isValid ()) { return rect; + } - QPoint topLeft = fromGlobal (widget, rect.topLeft ()); - return QRect (topLeft.x (), topLeft.y (), rect.width (), rect.height ()); + auto topLeft = fromGlobal (widget, rect.topLeft ()); + return {topLeft.x (), topLeft.y (), rect.width (), rect.height ()}; } QPoint toGlobal (const QWidget *widget, const QPoint &point) { - if (!widget) + if (!widget) { return point; + } return widget->mapToGlobal (point); } QRect toGlobal (const QWidget *widget, const QRect &rect) { - if (!widget || !rect.isValid ()) + if (!widget || !rect.isValid ()) { return rect; + } - QPoint topLeft = toGlobal (widget, rect.topLeft ()); - return QRect (topLeft.x (), topLeft.y (), rect.width (), rect.height ()); + auto topLeft = toGlobal (widget, rect.topLeft ()); + return {topLeft.x (), topLeft.y (), rect.width (), rect.height ()}; } -} // namespace kpWidgetMapper { +} // namespace kpWidgetMapper diff --git a/generic/widgets/kpResizeSignallingLabel.cpp b/generic/widgets/kpResizeSignallingLabel.cpp index f08723b8..4990e9ee 100644 --- a/generic/widgets/kpResizeSignallingLabel.cpp +++ b/generic/widgets/kpResizeSignallingLabel.cpp @@ -1,62 +1,60 @@ /* Copyright (c) 2003-2007 Clarence Dang All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include "generic/widgets/kpResizeSignallingLabel.h" #include #include #include "kpLogCategories.h" kpResizeSignallingLabel::kpResizeSignallingLabel (const QString &string, QWidget *parent ) : QLabel (string, parent) { } kpResizeSignallingLabel::kpResizeSignallingLabel (QWidget *parent ) : QLabel (parent) { } -kpResizeSignallingLabel::~kpResizeSignallingLabel () -{ -} +kpResizeSignallingLabel::~kpResizeSignallingLabel () = default; // protected virtual [base QLabel] void kpResizeSignallingLabel::resizeEvent (QResizeEvent *e) { qCDebug(kpLogMisc) << "kpResizeSignallingLabel::resizeEvent() newSize=" << e->size () - << " oldSize=" << e->oldSize () << endl; + << " oldSize=" << e->oldSize (); QLabel::resizeEvent (e); emit resized (); } diff --git a/imagelib/effects/blitz.cpp b/imagelib/effects/blitz.cpp index 6866cf1c..aa00150c 100644 --- a/imagelib/effects/blitz.cpp +++ b/imagelib/effects/blitz.cpp @@ -1,674 +1,691 @@ // functions taken from qimageblitz (no longer maintained) /* Copyright (C) 1998, 1999, 2001, 2002, 2004, 2005, 2007 Daniel M. Duley (C) 2004 Zack Rusin (C) 2000 Josef Weidendorfer (C) 1999 Geert Jansen (C) 1998, 1999 Christian Tibirna (C) 1998, 1999 Dirk Mueller Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ /* Portions of this software were originally based on ImageMagick's algorithms. ImageMagick is copyrighted under the following conditions: Copyright (C) 2003 ImageMagick Studio, a non-profit organization dedicated to making software imaging solutions freely available. Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files ("ImageMagick"), to deal in ImageMagick without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of ImageMagick, and to permit persons to whom the ImageMagick is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of ImageMagick. The software is provided "as is", without warranty of any kind, express or implied, including but not limited to the warranties of merchantability, fitness for a particular purpose and noninfringement. In no event shall ImageMagick Studio be liable for any claim, damages or other liability, whether in an action of contract, tort or otherwise, arising from, out of or in connection with ImageMagick or the use or other dealings in ImageMagick. Except as contained in this notice, the name of the ImageMagick Studio shall not be used in advertising or otherwise to promote the sale, use or other dealings in ImageMagick without prior written authorization from the ImageMagick Studio. */ #include "blitz.h" #include #include #define M_SQ2PI 2.50662827463100024161235523934010416269302368164062 #define M_EPSILON 1.0e-6 #define CONVOLVE_ACC(weight, pixel) \ r+=((weight))*(qRed((pixel))); g+=((weight))*(qGreen((pixel))); \ b+=((weight))*(qBlue((pixel))); //-------------------------------------------------------------------------------- inline QRgb convertFromPremult(QRgb p) { int alpha = qAlpha(p); return(!alpha ? 0 : qRgba(255*qRed(p)/alpha, 255*qGreen(p)/alpha, 255*qBlue(p)/alpha, alpha)); } //-------------------------------------------------------------------------------- inline QRgb convertToPremult(QRgb p) { unsigned int a = p >> 24; unsigned int t = (p & 0xff00ff) * a; t = (t + ((t >> 8) & 0xff00ff) + 0x800080) >> 8; t &= 0xff00ff; p = ((p >> 8) & 0xff) * a; p = (p + ((p >> 8) & 0xff) + 0x80); p &= 0xff00; p |= t | (a << 24); return(p); } //-------------------------------------------------------------------------------- // These are used as accumulators typedef struct { quint32 red, green, blue, alpha; } IntegerPixel; typedef struct { // Yes, a normal pixel can be used instead but this is easier to read // and no shifts to get components. quint8 red, green, blue, alpha; } CharPixel; typedef struct { quint32 red, green, blue, alpha; } HistogramListItem; bool equalize(QImage &img) { - if(img.isNull()) + if(img.isNull()) { return(false); + } HistogramListItem *histogram; IntegerPixel *map; IntegerPixel intensity, high, low; CharPixel *equalize_map; int i, count; QRgb pixel, *dest; unsigned char r, g, b; if(img.depth() < 32){ img = img.convertToFormat(img.hasAlphaChannel() ? QImage::Format_ARGB32 : QImage::Format_RGB32); } count = img.width()*img.height(); map = new IntegerPixel[256]; histogram = new HistogramListItem[256]; equalize_map = new CharPixel[256]; // form histogram memset(histogram, 0, 256*sizeof(HistogramListItem)); dest = (QRgb *)img.bits(); if(img.format() == QImage::Format_ARGB32_Premultiplied){ for(i=0; i < count; ++i, ++dest){ pixel = convertFromPremult(*dest); histogram[qRed(pixel)].red++; histogram[qGreen(pixel)].green++; histogram[qBlue(pixel)].blue++; histogram[qAlpha(pixel)].alpha++; } } else{ for(i=0; i < count; ++i){ pixel = *dest++; histogram[qRed(pixel)].red++; histogram[qGreen(pixel)].green++; histogram[qBlue(pixel)].blue++; histogram[qAlpha(pixel)].alpha++; } } // integrate the histogram to get the equalization map memset(&intensity, 0, sizeof(IntegerPixel)); for(i=0; i < 256; ++i){ intensity.red += histogram[i].red; intensity.green += histogram[i].green; intensity.blue += histogram[i].blue; map[i] = intensity; } low = map[0]; high = map[255]; memset(equalize_map, 0, 256*sizeof(CharPixel)); for(i=0; i < 256; ++i){ - if(high.red != low.red) + if(high.red != low.red) { equalize_map[i].red = static_cast - ((255*(map[i].red-low.red))/(high.red-low.red)); - if(high.green != low.green) + ((255*(map[i].red-low.red))/(high.red-low.red)); + } + if(high.green != low.green) { equalize_map[i].green = static_cast - ((255*(map[i].green-low.green))/(high.green-low.green)); - if(high.blue != low.blue) + ((255*(map[i].green-low.green))/(high.green-low.green)); + } + if(high.blue != low.blue) { equalize_map[i].blue = static_cast - ((255*(map[i].blue-low.blue))/(high.blue-low.blue)); + ((255*(map[i].blue-low.blue))/(high.blue-low.blue)); + } } // stretch the histogram and write dest = (QRgb *)img.bits(); if(img.format() == QImage::Format_ARGB32_Premultiplied){ for(i=0; i < count; ++i, ++dest){ pixel = convertFromPremult(*dest); r = static_cast ((low.red != high.red) ? equalize_map[qRed(pixel)].red : qRed(pixel)); g = static_cast ((low.green != high.green) ? equalize_map[qGreen(pixel)].green : qGreen(pixel)); b = static_cast ((low.blue != high.blue) ? equalize_map[qBlue(pixel)].blue : qBlue(pixel)); *dest = convertToPremult(qRgba(r, g, b, qAlpha(pixel))); } } else{ for(i=0; i < count; ++i){ pixel = *dest; r = static_cast ((low.red != high.red) ? equalize_map[qRed(pixel)].red : qRed(pixel)); g = static_cast ((low.green != high.green) ? equalize_map[qGreen(pixel)].green : qGreen(pixel)); b = static_cast ((low.blue != high.blue) ? equalize_map[qBlue(pixel)].blue : qBlue(pixel)); *dest++ = qRgba(r, g, b, qAlpha(pixel)); } } delete[] histogram; delete[] map; delete[] equalize_map; return(true); } //-------------------------------------------------------------------------------- QImage Blitz::blur(QImage &img, int radius) { QRgb *p1, *p2; int x, y, w, h, mx, my, mw, mh, mt, xx, yy; int a, r, g, b; int *as, *rs, *gs, *bs; - if(radius < 1 || img.isNull() || img.width() < (radius << 1)) + if(radius < 1 || img.isNull() || img.width() < (radius << 1)) { return(img); + } w = img.width(); h = img.height(); - if(img.depth() < 8) + if(img.depth() < 8) { img = img.convertToFormat(QImage::Format_Indexed8); + } QImage buffer(w, h, img.hasAlphaChannel() ? QImage::Format_ARGB32 : QImage::Format_RGB32); as = new int[w]; rs = new int[w]; gs = new int[w]; bs = new int[w]; QVector colorTable; - if(img.format() == QImage::Format_Indexed8) + if(img.format() == QImage::Format_Indexed8) { colorTable = img.colorTable(); + } for(y = 0; y < h; y++){ my = y - radius; mh = (radius << 1) + 1; if(my < 0){ mh += my; my = 0; } - if((my + mh) > h) + if((my + mh) > h) { mh = h - my; + } p1 = (QRgb *)buffer.scanLine(y); memset(as, 0, static_cast (w) * sizeof(int)); memset(rs, 0, static_cast (w) * sizeof(int)); memset(gs, 0, static_cast (w) * sizeof(int)); memset(bs, 0, static_cast (w) * sizeof(int)); if(img.format() == QImage::Format_ARGB32_Premultiplied){ QRgb pixel; for(yy = 0; yy < mh; yy++){ p2 = (QRgb *)img.scanLine(yy + my); for(x = 0; x < w; x++, p2++){ pixel = convertFromPremult(*p2); as[x] += qAlpha(pixel); rs[x] += qRed(pixel); gs[x] += qGreen(pixel); bs[x] += qBlue(pixel); } } } else if(img.format() == QImage::Format_Indexed8){ QRgb pixel; unsigned char *ptr; for(yy = 0; yy < mh; yy++){ ptr = img.scanLine(yy + my); for(x = 0; x < w; x++, ptr++){ pixel = colorTable[*ptr]; as[x] += qAlpha(pixel); rs[x] += qRed(pixel); gs[x] += qGreen(pixel); bs[x] += qBlue(pixel); } } } else{ for(yy = 0; yy < mh; yy++){ p2 = (QRgb *)img.scanLine(yy + my); for(x = 0; x < w; x++, p2++){ as[x] += qAlpha(*p2); rs[x] += qRed(*p2); gs[x] += qGreen(*p2); bs[x] += qBlue(*p2); } } } for(x = 0; x < w; x++){ a = r = g = b = 0; mx = x - radius; mw = (radius << 1) + 1; if(mx < 0){ mw += mx; mx = 0; } - if((mx + mw) > w) + if((mx + mw) > w) { mw = w - mx; + } mt = mw * mh; for(xx = mx; xx < (mw + mx); xx++){ a += as[xx]; r += rs[xx]; g += gs[xx]; b += bs[xx]; } a = a / mt; r = r / mt; g = g / mt; b = b / mt; *p1++ = qRgba(r, g, b, a); } } delete[] as; delete[] rs; delete[] gs; delete[] bs; return(buffer); } //-------------------------------------------------------------------------------- int defaultConvolveMatrixSize(float radius, float sigma, bool quality) { int i, matrix_size; float normalize, value; float sigma2 = sigma*sigma*2.0f; float sigmaSQ2PI = static_cast(M_SQ2PI) * sigma; int max = quality ? 65535 : 255; if(sigma == 0.0f){ qWarning("Blitz::defaultConvolveMatrixSize(): Zero sigma is invalid!"); return(5); } - if(radius > 0.0f) + if(radius > 0.0f) { return(static_cast(2.0f * std::ceil(radius) + 1.0f)); + } matrix_size = 5; do{ normalize = 0.0; - for(i=(-matrix_size/2); i <= (matrix_size/2); ++i) + for(i=(-matrix_size/2); i <= (matrix_size/2); ++i) { normalize += std::exp(-(static_cast (i*i))/sigma2) / sigmaSQ2PI; + } i = matrix_size/2; value = std::exp(-(static_cast (i*i))/sigma2) / sigmaSQ2PI / normalize; matrix_size += 2; } while(static_cast(max*value) > 0); matrix_size-=4; return(matrix_size); } //-------------------------------------------------------------------------------- QImage convolve(QImage &img, int matrix_size, float *matrix) { int i, x, y, w, h, matrix_x, matrix_y; int edge = matrix_size/2; QRgb *dest, *src, *s, **scanblock; float *m, *normalize_matrix, normalize; if(!(matrix_size % 2)){ qWarning("Blitz::convolve(): kernel width must be an odd number!"); return(img); } w = img.width(); h = img.height(); if(w < 3 || h < 3){ qWarning("Blitz::convolve(): Image is too small!"); return(img); } - if(img.format() == QImage::Format_ARGB32_Premultiplied) + if(img.format() == QImage::Format_ARGB32_Premultiplied) { img = img.convertToFormat(QImage::Format_ARGB32); + } else if(img.depth() < 32){ img = img.convertToFormat(img.hasAlphaChannel() ? QImage::Format_ARGB32 : QImage::Format_RGB32); } QImage buffer(w, h, img.format()); scanblock = new QRgb* [matrix_size]; normalize_matrix = new float[matrix_size*matrix_size]; // create normalized matrix normalize = 0.0; - for(i=0; i < matrix_size*matrix_size; ++i) + for(i=0; i < matrix_size*matrix_size; ++i) { normalize += matrix[i]; - if(std::abs(normalize) <= static_cast (M_EPSILON)) + } + if(std::abs(normalize) <= static_cast (M_EPSILON)) { normalize = 1.0f; + } normalize = 1.0f/normalize; for(i=0; i < matrix_size*matrix_size; ++i){ normalize_matrix[i] = normalize*matrix[i]; } // apply { // // // Non-MMX version // // float r, g, b; for(y=0; y < h; ++y){ src = (QRgb *)img.scanLine(y); dest = (QRgb *)buffer.scanLine(y); // Read in scanlines to pixel neighborhood. If the scanline is outside // the image use the top or bottom edge. for(x=y-edge, i=0; x <= y+edge; ++i, ++x){ scanblock[i] = (QRgb *) img.scanLine((x < 0) ? 0 : (x > h-1) ? h-1 : x); } // Now we are about to start processing scanlines. First handle the // part where the pixel neighborhood extends off the left edge. for(x=0; x-edge < 0 ; ++x){ r = g = b = 0.0; m = normalize_matrix; for(matrix_y = 0; matrix_y < matrix_size; ++matrix_y){ s = scanblock[matrix_y]; matrix_x = -edge; while(x+matrix_x < 0){ CONVOLVE_ACC(*m, *s); ++matrix_x; ++m; } while(matrix_x <= edge){ CONVOLVE_ACC(*m, *s); ++matrix_x; ++m; ++s; } } r = r < 0.0f ? 0.0f : r > 255.0f ? 255.0f : r + 0.5f; g = g < 0.0f ? 0.0f : g > 255.0f ? 255.0f : g + 0.5f; b = b < 0.0f ? 0.0f : b > 255.0f ? 255.0f : b + 0.5f; *dest++ = qRgba(static_cast (r), static_cast (g), static_cast (b), qAlpha(*src++)); } // Okay, now process the middle part where the entire neighborhood // is on the image. for(; x+edge < w; ++x){ m = normalize_matrix; r = g = b = 0.0; for(matrix_y = 0; matrix_y < matrix_size; ++matrix_y){ s = scanblock[matrix_y] + (x-edge); for(matrix_x = -edge; matrix_x <= edge; ++matrix_x, ++m, ++s){ CONVOLVE_ACC(*m, *s); } } r = r < 0.0f ? 0.0f : r > 255.0f ? 255.0f : r + 0.5f; g = g < 0.0f ? 0.0f : g > 255.0f ? 255.0f : g + 0.5f; b = b < 0.0f ? 0.0f : b > 255.0f ? 255.0f : b + 0.5f; *dest++ = qRgba(static_cast (r), static_cast (g), static_cast (b), qAlpha(*src++)); } // Finally process the right part where the neighborhood extends off // the right edge of the image for(; x < w; ++x){ r = g = b = 0.0; m = normalize_matrix; for(matrix_y = 0; matrix_y < matrix_size; ++matrix_y){ s = scanblock[matrix_y]; s += x-edge; matrix_x = -edge; while(x+matrix_x < w){ CONVOLVE_ACC(*m, *s); ++matrix_x; ++m; ++s; } --s; while(matrix_x <= edge){ CONVOLVE_ACC(*m, *s); ++matrix_x; ++m; } } r = r < 0.0f ? 0.0f : r > 255.0f ? 255.0f : r + 0.5f; g = g < 0.0f ? 0.0f : g > 255.0f ? 255.0f : g + 0.5f; b = b < 0.0f ? 0.0f : b > 255.0f ? 255.0f : b + 0.5f; *dest++ = qRgba(static_cast (r), static_cast (g), static_cast (b), qAlpha(*src++)); } } } delete[] scanblock; delete[] normalize_matrix; return(buffer); } //-------------------------------------------------------------------------------- QImage Blitz::gaussianSharpen(QImage &img, float radius, float sigma) { if(sigma == 0.0f){ qWarning("Blitz::gaussianSharpen(): Zero sigma is invalid!"); return(img); } int matrix_size = defaultConvolveMatrixSize(radius, sigma, true); int len = matrix_size*matrix_size; float alpha, *matrix = new float[len]; float sigma2 = sigma*sigma*2.0f; float sigmaPI2 = 2.0f*static_cast (M_PI)*sigma*sigma; int half = matrix_size/2; int x, y, i=0, j=half; float normalize=0.0; for(y=(-half); y <= half; ++y, --j){ for(x=(-half); x <= half; ++x, ++i){ alpha = std::exp(-(static_cast (x*x+y*y))/sigma2); matrix[i] = alpha/sigmaPI2; normalize += matrix[i]; } } matrix[i/2]=(-2.0f)*normalize; QImage result(convolve(img, matrix_size, matrix)); delete[] matrix; return(result); } //-------------------------------------------------------------------------------- QImage Blitz::emboss(QImage &img, float radius, float sigma) { if(sigma == 0.0f){ qWarning("Blitz::emboss(): Zero sigma is invalid!"); return(img); } int matrix_size = defaultConvolveMatrixSize(radius, sigma, true); int len = matrix_size*matrix_size; float alpha, *matrix = new float[len]; float sigma2 = sigma*sigma*2.0f; float sigmaPI2 = 2.0f*static_cast (M_PI)*sigma*sigma; int half = matrix_size/2; int x, y, i=0, j=half; for(y=(-half); y <= half; ++y, --j){ for(x=(-half); x <= half; ++x, ++i){ alpha = std::exp(-(static_cast (x*x+y*y))/sigma2); matrix[i]=((x < 0) || (y < 0) ? -8.0f : 8.0f)*alpha/sigmaPI2; - if(x == j) + if(x == j) { matrix[i]=0.0; + } } } QImage result(convolve(img, matrix_size, matrix)); delete[] matrix; equalize(result); return(result); } //-------------------------------------------------------------------------------- QImage& Blitz::flatten(QImage &img, const QColor &ca, const QColor &cb) { - if(img.isNull()) + if(img.isNull()) { return(img); + } if(img.depth() == 1) { img.setColor(0, ca.rgb()); img.setColor(1, cb.rgb()); return(img); } int r1 = ca.red(); int r2 = cb.red(); int g1 = ca.green(); int g2 = cb.green(); int b1 = ca.blue(); int b2 = cb.blue(); int min = 0, max = 255; QRgb *data, *end; QVector cTable; if(img.format() == QImage::Format_Indexed8){ cTable = img.colorTable(); data = static_cast (cTable.data()); end = data + img.colorCount(); } else{ data = (unsigned int *)img.scanLine(0); end = data + (img.width()*img.height()); } // get minimum and maximum graylevel QRgb *ptr = data; int mean; if(img.format() != QImage::Format_ARGB32_Premultiplied){ while(ptr != end){ mean = (qRed(*ptr) + qGreen(*ptr) + qBlue(*ptr)) / 3; min = qMin(min, mean); max = qMax(max, mean); ++ptr; } } else{ QRgb pixel; while(ptr != end){ pixel = convertFromPremult(*ptr); mean = (qRed(pixel) + qGreen(pixel) + qBlue(pixel)) / 3; min = qMin(min, mean); max = qMax(max, mean); ++ptr; } } // conversion factors float sr = (static_cast (r2 - r1) / (max - min)); float sg = (static_cast (g2 - g1) / (max - min)); float sb = (static_cast (b2 - b1) / (max - min)); if(img.format() != QImage::Format_ARGB32_Premultiplied){ while(data != end){ mean = (qRed(*data) + qGreen(*data) + qBlue(*data)) / 3; *data = qRgba(static_cast (sr * (mean - min) + r1 + 0.5f), static_cast (sg * (mean - min) + g1 + 0.5f), static_cast (sb * (mean - min) + b1 + 0.5f), qAlpha(*data)); ++data; } } else{ QRgb pixel; while(data != end){ pixel = convertFromPremult(*data); mean = (qRed(pixel) + qGreen(pixel) + qBlue(pixel)) / 3; *data = convertToPremult(qRgba(static_cast (sr * (mean - min) + r1 + 0.5f), static_cast (sg * (mean - min) + g1 + 0.5f), static_cast (sb * (mean - min) + b1 + 0.5f), qAlpha(*data))); ++data; } } - if(img.format() == QImage::Format_Indexed8) + if(img.format() == QImage::Format_Indexed8) { img.setColorTable(cTable); + } return(img); } //-------------------------------------------------------------------------------- diff --git a/imagelib/effects/kpEffectBalance.cpp b/imagelib/effects/kpEffectBalance.cpp index ba525ebe..d2712723 100644 --- a/imagelib/effects/kpEffectBalance.cpp +++ b/imagelib/effects/kpEffectBalance.cpp @@ -1,180 +1,192 @@ /* Copyright (c) 2003-2007 Clarence Dang All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #define DEBUG_KP_EFFECT_BALANCE 0 #include "kpEffectBalance.h" #include #include #include "kpLogCategories.h" #include "pixmapfx/kpPixmapFX.h" #include static inline int between0And255 (int val) { - if (val < 0) + if (val < 0) { return 0; - else if (val > 255) + } + + if (val > 255) { return 255; - else - return val; + } + + return val; } static inline int brightness (int base, int strength) { return between0And255 (base + strength * 255 / 50); } static inline int contrast (int base, int strength) { return between0And255 ((base - 127) * (strength + 50) / 50 + 127); } static inline int gamma (int base, int strength) { return between0And255 (qRound (255.0 * std::pow (base / 255.0, 1.0 / std::pow (10., strength / 50.0)))); } static inline int brightnessContrastGamma (int base, int newBrightness, int newContrast, int newGamma) { return gamma (contrast (brightness (base, newBrightness), newContrast), newGamma); } static inline QRgb brightnessContrastGammaForRGB (QRgb rgb, int channels, int brightness, int contrast, int gamma) { int red = qRed (rgb); int green = qGreen (rgb); int blue = qBlue (rgb); - if (channels & kpEffectBalance::Red) + if (channels & kpEffectBalance::Red) { red = brightnessContrastGamma (red, brightness, contrast, gamma); - if (channels & kpEffectBalance::Green) + } + if (channels & kpEffectBalance::Green) { green = brightnessContrastGamma (green, brightness, contrast, gamma); - if (channels & kpEffectBalance::Blue) + } + if (channels & kpEffectBalance::Blue) { blue = brightnessContrastGamma (blue, brightness, contrast, gamma); + } return qRgba (red, green, blue, qAlpha (rgb)); } // public static kpImage kpEffectBalance::applyEffect (const kpImage &image, int channels, int brightness, int contrast, int gamma) { qCDebug(kpLogImagelib) << "kpEffectBalance::applyEffect(" << "channels=" << channels << ",brightness=" << brightness << ",contrast=" << contrast << ",gamma=" << gamma - << ")" << endl; + << ")"; QTime timer; timer.start (); QImage qimage = image; qCDebug(kpLogImagelib) << "\tconvertToImage=" << timer.restart (); quint8 transformRed [256], transformGreen [256], transformBlue [256]; for (int i = 0; i < 256; i++) { - quint8 applied = static_cast (brightnessContrastGamma (i, brightness, contrast, gamma)); + auto applied = static_cast (brightnessContrastGamma (i, brightness, contrast, gamma)); - if (channels & kpEffectBalance::Red) + if (channels & kpEffectBalance::Red) { transformRed [i] = applied; - else + } + else { transformRed [i] = static_cast (i); + } - if (channels & kpEffectBalance::Green) + if (channels & kpEffectBalance::Green) { transformGreen [i] = applied; - else + } + else { transformGreen [i] = static_cast (i); + } - if (channels & kpEffectBalance::Blue) + if (channels & kpEffectBalance::Blue) { transformBlue [i] = applied; - else + } + else { transformBlue [i] = static_cast (i); + } } qCDebug(kpLogImagelib) << "\tbuild lookup=" << timer.restart (); if (qimage.depth () > 8) { for (int y = 0; y < qimage.height (); y++) { for (int x = 0; x < qimage.width (); x++) { const QRgb rgb = qimage.pixel (x, y); - const quint8 red = static_cast (qRed (rgb)); - const quint8 green = static_cast (qGreen (rgb)); - const quint8 blue = static_cast (qBlue (rgb)); - const quint8 alpha = static_cast (qAlpha (rgb)); + const auto red = static_cast (qRed (rgb)); + const auto green = static_cast (qGreen (rgb)); + const auto blue = static_cast (qBlue (rgb)); + const auto alpha = static_cast (qAlpha (rgb)); qimage.setPixel (x, y, qRgba (transformRed [red], transformGreen [green], transformBlue [blue], alpha)); } } } else { for (int i = 0; i < qimage.colorCount (); i++) { const QRgb rgb = qimage.color (i); - const quint8 red = static_cast (qRed (rgb)); - const quint8 green = static_cast (qGreen (rgb)); - const quint8 blue = static_cast (qBlue (rgb)); - const quint8 alpha = static_cast (qAlpha (rgb)); + const auto red = static_cast (qRed (rgb)); + const auto green = static_cast (qGreen (rgb)); + const auto blue = static_cast (qBlue (rgb)); + const auto alpha = static_cast (qAlpha (rgb)); qimage.setColor (i, qRgba (transformRed [red], transformGreen [green], transformBlue [blue], alpha)); } } return qimage; } diff --git a/imagelib/effects/kpEffectBlurSharpen.cpp b/imagelib/effects/kpEffectBlurSharpen.cpp index 04c338a6..f5c81741 100644 --- a/imagelib/effects/kpEffectBlurSharpen.cpp +++ b/imagelib/effects/kpEffectBlurSharpen.cpp @@ -1,163 +1,166 @@ /* Copyright (c) 2003-2007 Clarence Dang All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #define DEBUG_KP_EFFECT_BLUR_SHARPEN 0 #include "kpEffectBlurSharpen.h" #include "blitz.h" #include "kpLogCategories.h" #include "pixmapfx/kpPixmapFX.h" #include //--------------------------------------------------------------------- // // For info on "radius" and "sigma", see http://redskiesatnight.com/Articles/IMsharpen/ // // Daniel Duley says: // // // I don't think I can describe it any better than the article: The radius // controls many how pixels are taken into account when determining the value // of the center pixel. This controls the quality [and speed] of the result but not // necessarily the strength. The sigma controls how those neighboring pixels // are weighted depending on how far the are from the center one. This is // closer to strength, but not exactly >:) // // static QImage BlurQImage(const QImage &qimage, int strength) { - if (strength == 0) + if (strength == 0) { return qimage; + } // The numbers that follow were picked by experimentation to try to get // an effect linearly proportional to and at the same time, // be fast enough. // // I still have no idea what "radius" means. const double RadiusMin = 1; const double RadiusMax = 10; const double radius = RadiusMin + (strength - 1) * (RadiusMax - RadiusMin) / (kpEffectBlurSharpen::MaxStrength - 1); qCDebug(kpLogImagelib) << "kpEffectBlurSharpen.cpp:BlurQImage(strength=" << strength << ")" - << " radius=" << radius - << endl; + << " radius=" << radius; QImage img(qimage); return Blitz::blur(img, qRound(radius)); } //--------------------------------------------------------------------- static QImage SharpenQImage (const QImage &qimage_, int strength) { QImage qimage = qimage_; - if (strength == 0) + if (strength == 0) { return qimage; + } // The numbers that follow were picked by experimentation to try to get // an effect linearly proportional to and at the same time, // be fast enough. // // I still have no idea what "radius" and "sigma" mean. const double RadiusMin = 0.1; const double RadiusMax = 2.5; const double radius = RadiusMin + (strength - 1) * (RadiusMax - RadiusMin) / (kpEffectBlurSharpen::MaxStrength - 1); const double SigmaMin = 0.5; const double SigmaMax = 3.0; const double sigma = SigmaMin + (strength - 1) * (SigmaMax - SigmaMin) / (kpEffectBlurSharpen::MaxStrength - 1); const double RepeatMin = 1; const double RepeatMax = 2; const double repeat = qRound (RepeatMin + (strength - 1) * (RepeatMax - RepeatMin) / (kpEffectBlurSharpen::MaxStrength - 1)); qCDebug(kpLogImagelib) << "kpEffectBlurSharpen.cpp:SharpenQImage(strength=" << strength << ")" << " radius=" << radius << " sigma=" << sigma - << " repeat=" << repeat - << endl; + << " repeat=" << repeat; for (int i = 0; i < repeat; i++) { QTime timer; timer.start (); qimage = Blitz::gaussianSharpen (qimage, static_cast (radius), static_cast (sigma)); qCDebug(kpLogImagelib) << "\titeration #" + QString::number (i) - << ": " + QString::number (timer.elapsed ()) << "ms" << endl; + << ": " + QString::number (timer.elapsed ()) << "ms"; } return qimage; } //--------------------------------------------------------------------- // public static kpImage kpEffectBlurSharpen::applyEffect (const kpImage &image, Type type, int strength) { qCDebug(kpLogImagelib) << "kpEffectBlurSharpen::applyEffect(image.rect=" << image.rect () << ",type=" << int (type) << ",strength=" << strength - << ")" << endl; + << ")"; Q_ASSERT (strength >= MinStrength && strength <= MaxStrength); - if (type == Blur) + if (type == Blur) { return ::BlurQImage (image, strength); - else if (type == Sharpen) + } + + if (type == Sharpen) { return ::SharpenQImage (image, strength); - else if (type == MakeConfidential) - { + } + + if (type == MakeConfidential) { QImage img(image); return Blitz::blur(img, qMin(20, img.width() / 2)); } - else - return kpImage(); + + return kpImage(); } diff --git a/imagelib/effects/kpEffectEmboss.cpp b/imagelib/effects/kpEffectEmboss.cpp index 91157530..d3a3e499 100644 --- a/imagelib/effects/kpEffectEmboss.cpp +++ b/imagelib/effects/kpEffectEmboss.cpp @@ -1,77 +1,78 @@ /* Copyright (c) 2003-2007 Clarence Dang All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #define DEBUG_KP_EFFECT_EMBOSS 0 #include "kpEffectEmboss.h" #include "blitz.h" #include "kpLogCategories.h" #include "pixmapfx/kpPixmapFX.h" static QImage EmbossQImage (const QImage &qimage_, int strength) { QImage qimage = qimage_; - if (strength == 0) + if (strength == 0) { return qimage; + } // The numbers that follow were picked by experimentation to try to get // an effect linearly proportional to and at the same time, // be fast enough. // // I still have no idea what "radius" and "sigma" mean. - const double radius = 0; + const auto radius = 0.0; - const double sigma = 1; + const auto sigma = 1.0; - const int repeat = 1; + const auto repeat = 1; for (int i = 0; i < repeat; i++) { qimage = Blitz::emboss (qimage, radius, sigma); } return qimage; } // public static kpImage kpEffectEmboss::applyEffect (const kpImage &image, int strength) { qCDebug(kpLogImagelib) << "kpEffectEmboss::applyEffect(strength=" << strength << ")"; Q_ASSERT (strength >= MinStrength && strength <= MaxStrength); return ::EmbossQImage (image, strength); } diff --git a/imagelib/effects/kpEffectFlatten.cpp b/imagelib/effects/kpEffectFlatten.cpp index c3c8ae12..e0c541b4 100644 --- a/imagelib/effects/kpEffectFlatten.cpp +++ b/imagelib/effects/kpEffectFlatten.cpp @@ -1,53 +1,54 @@ /* Copyright (c) 2003-2007 Clarence Dang All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include "kpEffectFlatten.h" #include "blitz.h" //-------------------------------------------------------------------------------- // public static void kpEffectFlatten::applyEffect (QImage *destImagePtr, const QColor &color1, const QColor &color2) { - if (!destImagePtr) + if (!destImagePtr) { return; + } Blitz::flatten (*destImagePtr/*ref*/, color1, color2); } //-------------------------------------------------------------------------------- // public static QImage kpEffectFlatten::applyEffect (const QImage &img, const QColor &color1, const QColor &color2) { QImage retImage = img; applyEffect (&retImage, color1, color2); return retImage; } //-------------------------------------------------------------------------------- diff --git a/imagelib/effects/kpEffectGrayscale.cpp b/imagelib/effects/kpEffectGrayscale.cpp index dde6b094..b657fb35 100644 --- a/imagelib/effects/kpEffectGrayscale.cpp +++ b/imagelib/effects/kpEffectGrayscale.cpp @@ -1,74 +1,75 @@ /* Copyright (c) 2003-2007 Clarence Dang All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #define DEBUG_KP_PIXMAP_FX 0 #include "kpEffectGrayscale.h" #include "pixmapfx/kpPixmapFX.h" static QRgb toGray (QRgb rgb) { // naive way that doesn't preserve brightness // int gray = (qRed (rgb) + qGreen (rgb) + qBlue (rgb)) / 3; // over-exaggerates red & blue // int gray = qGray (rgb); int gray = (212671 * qRed (rgb) + 715160 * qGreen (rgb) + 72169 * qBlue (rgb)) / 1000000; return qRgba (gray, gray, gray, qAlpha (rgb)); } // public static kpImage kpEffectGrayscale::applyEffect (const kpImage &image) { kpImage qimage(image); // TODO: Why not just write to the kpImage directly? if (qimage.depth () > 8) { for (int y = 0; y < qimage.height (); y++) { for (int x = 0; x < qimage.width (); x++) { qimage.setPixel (x, y, toGray (qimage.pixel (x, y))); } } } else { // 1- & 8- bit images use a color table - for (int i = 0; i < qimage.colorCount (); i++) + for (int i = 0; i < qimage.colorCount (); i++) { qimage.setColor (i, toGray (qimage.color (i))); + } } return qimage; } diff --git a/imagelib/effects/kpEffectHSV.cpp b/imagelib/effects/kpEffectHSV.cpp index e3b36c77..4131b1a8 100644 --- a/imagelib/effects/kpEffectHSV.cpp +++ b/imagelib/effects/kpEffectHSV.cpp @@ -1,190 +1,191 @@ /* Copyright (c) 2007 Mike Gashler All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ // TODO: Clarence's code review #include "kpEffectHSV.h" #include #include #include #include "kpLogCategories.h" #include "pixmapfx/kpPixmapFX.h" static void ColorToHSV(unsigned int c, float* pHue, float* pSaturation, float* pValue) { int r = qRed(c); int g = qGreen(c); int b = qBlue(c); - int min; + int min{}; if(b >= g && b >= r) { // Blue min = qMin(r, g); if(b != min) { *pHue = static_cast (r - g) / ((b - min) * 6) + static_cast (2) / 3; *pSaturation = 1.0f - static_cast (min) / static_cast (b); } else { *pHue = 0; *pSaturation = 0; } *pValue = static_cast (b) / 255; } else if(g >= r) { // Green min = qMin(b, r); if(g != min) { *pHue = static_cast (b - r) / ((g - min) * 6) + static_cast (1) / 3; *pSaturation = 1.0f - static_cast (min) / static_cast (g); } else { *pHue = 0; *pSaturation = 0; } *pValue = static_cast (g) / 255; } else { // Red min = qMin(g, b); if(r != min) { *pHue = static_cast (g - b) / ((r - min) * 6); - if(*pHue < 0) + if(*pHue < 0) { (*pHue) += 1.0f; + } *pSaturation = 1.0f - static_cast (min) / static_cast (r); } else { *pHue = 0; *pSaturation = 0; } *pValue = static_cast (r) / 255; } } static unsigned int HSVToColor(int alpha, float hue, float saturation, float value) { //Q_ASSERT (hue >= 0 && hue <= 1 && saturation >= 0 && saturation <= 1 && value >= 0 && value <= 1); hue *= 5.999999f; int h = static_cast (hue); float f = hue - h; float p = value * (1.0f - saturation); float q = value * (1.0f - ((h & 1) == 0 ? 1.0f - f : f) * saturation); switch(h) { case 0: return qRgba(static_cast (value * 255.999999f), static_cast (q * 255.999999f), static_cast (p * 255.999999f), alpha); case 1: return qRgba(static_cast (q * 255.999999f), static_cast (value * 255.999999f), static_cast (p * 255.999999f), alpha); case 2: return qRgba(static_cast (p * 255.999999f), static_cast (value * 255.999999f), static_cast (q * 255.999999f), alpha); case 3: return qRgba(static_cast (p * 255.999999f), static_cast (q * 255.999999f), static_cast (value * 255.999999f), alpha); case 4: return qRgba(static_cast (q * 255.999999f), static_cast (p * 255.999999f), static_cast (value * 255.999999f), alpha); case 5: return qRgba(static_cast (value * 255.999999f), static_cast (p * 255.999999f), static_cast (q * 255.999999f), alpha); } return qRgba(0, 0, 0, alpha); } static QRgb AdjustHSVInternal (QRgb pix, double hueDiv360, double saturation, double value) { float h, s, v; ::ColorToHSV(pix, &h, &s, &v); const int alpha = qAlpha(pix); h += static_cast (hueDiv360); h -= std::floor(h); s = qMax(0.0f, qMin(1.0f, s + static_cast (saturation))); v = qMax(0.0f, qMin(1.0f, v + static_cast (value))); return ::HSVToColor(alpha, h, s, v); } static void AdjustHSV (QImage* pImage, double hue, double saturation, double value) { hue /= 360; if (pImage->depth () > 8) { for (int y = 0; y < pImage->height (); y++) { for (int x = 0; x < pImage->width (); x++) { QRgb pix = pImage->pixel (x, y); pix = ::AdjustHSVInternal (pix, hue, saturation, value); pImage->setPixel (x, y, pix); } } } else { for (int i = 0; i < pImage->colorCount (); i++) { QRgb pix = pImage->color (i); pix = ::AdjustHSVInternal (pix, hue, saturation, value); pImage->setColor (i, pix); } } } // public static kpImage kpEffectHSV::applyEffect (const kpImage &image, double hue, double saturation, double value) { QImage qimage(image); ::AdjustHSV (&qimage, hue, saturation, value); return qimage; } diff --git a/imagelib/effects/kpEffectInvert.cpp b/imagelib/effects/kpEffectInvert.cpp index 20b229af..d0b8b96e 100644 --- a/imagelib/effects/kpEffectInvert.cpp +++ b/imagelib/effects/kpEffectInvert.cpp @@ -1,83 +1,82 @@ /* Copyright (c) 2003-2007 Clarence Dang All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #define DEBUG_KP_EFFECT_INVERT 0 #include "kpEffectInvert.h" #include #include #include "kpLogCategories.h" #include "pixmapfx/kpPixmapFX.h" // public static void kpEffectInvert::applyEffect (QImage *destImagePtr, int channels) { QRgb mask = qRgba ((channels & Red) ? 0xFF : 0, (channels & Green) ? 0xFF : 0, (channels & Blue) ? 0xFF : 0, 0/*don't invert alpha*/); qCDebug(kpLogImagelib) << "kpEffectInvert::applyEffect(channels=" << channels - << ") mask=" << (int *) mask - << endl; + << ") mask=" << (int *) mask; if (destImagePtr->depth () > 8) { // Above version works for Qt 3.2 at least. // But this version will always work (slower, though) and supports // inverting particular channels. for (int y = 0; y < destImagePtr->height (); y++) { for (int x = 0; x < destImagePtr->width (); x++) { destImagePtr->setPixel (x, y, destImagePtr->pixel (x, y) ^ mask); } } } else { for (int i = 0; i < destImagePtr->colorCount (); i++) { destImagePtr->setColor (i, destImagePtr->color (i) ^ mask); } } } // public static QImage kpEffectInvert::applyEffect (const QImage &img, int channels) { QImage retImage = img; applyEffect (&retImage, channels); return retImage; } diff --git a/imagelib/effects/kpEffectReduceColors.cpp b/imagelib/effects/kpEffectReduceColors.cpp index fb27b8cc..a703e0c3 100644 --- a/imagelib/effects/kpEffectReduceColors.cpp +++ b/imagelib/effects/kpEffectReduceColors.cpp @@ -1,217 +1,221 @@ /* Copyright (c) 2003-2007 Clarence Dang Copyright (c) 2011 Martin Koller All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #define DEBUG_KP_EFFECT_REDUCE_COLORS 0 #include "imagelib/effects/kpEffectReduceColors.h" #include "kpLogCategories.h" //--------------------------------------------------------------------- static QImage::Format DepthToFormat (int depth) { // These values are QImage's supported depths. switch (depth) { case 1: // (can be MSB instead, I suppose) return QImage::Format_MonoLSB; case 8: return QImage::Format_Indexed8; case 16: return QImage::Format_ARGB4444_Premultiplied; case 24: return QImage::Format_ARGB6666_Premultiplied; case 32: return QImage::Format_ARGB32_Premultiplied; default: Q_ASSERT (!"unknown depth"); return QImage::Format_Invalid; } } //--------------------------------------------------------------------- // public static QImage kpEffectReduceColors::convertImageDepth (const QImage &image, int depth, bool dither) { qCDebug(kpLogImagelib) << "kpeffectreducecolors.cpp:ConvertImageDepth() changing image (w=" << image.width () << ",h=" << image.height () << ") depth from " << image.depth () << " to " << depth << " (dither=" << dither << ")"; - if (image.isNull ()) + if (image.isNull ()) { return image; + } - if (depth == image.depth ()) + if (depth == image.depth ()) { return image; + } for (int y = 0; y < image.height (); y++) { for (int x = 0; x < image.width (); x++) { fprintf (stderr, " %08X", image.pixel (x, y)); } fprintf (stderr, "\n"); } // Hack around Qt's braindead QImage::convertToFormat(QImage::Format_MonoLSB, ...) // (with dithering off) which produces pathetic results with an image that // only has 2 colors - sometimes it just gives a completely black // result (try yellow and white as input). Instead, we simply preserve // the 2 colours. // // One use case is resaving a "color monochrome" image (<= 2 colors but // not necessarily black & white). if (depth == 1 && !dither) { qCDebug(kpLogImagelib) << "\tinvoking convert-to-depth 1 hack"; QRgb color0 = 0, color1 = 0; bool color0Valid = false, color1Valid = false; bool moreThan2Colors = false; QImage monoImage (image.width (), image.height (), QImage::Format_MonoLSB); monoImage.setColorCount (2); qCDebug(kpLogImagelib) << "\t\tinitialising output image w=" << monoImage.width () << ",h=" << monoImage.height () - << ",d=" << monoImage.depth () - << endl; + << ",d=" << monoImage.depth (); for (int y = 0; y < image.height (); y++) { for (int x = 0; x < image.width (); x++) { // (this can be transparent) QRgb imagePixel = image.pixel (x, y); - if (color0Valid && imagePixel == color0) + if (color0Valid && imagePixel == color0) { monoImage.setPixel (x, y, 0); - else if (color1Valid && imagePixel == color1) + } + else if (color1Valid && imagePixel == color1) { monoImage.setPixel (x, y, 1); - else if (!color0Valid) - { + } + else if (!color0Valid) { color0 = imagePixel; color0Valid = true; monoImage.setPixel (x, y, 0); qCDebug(kpLogImagelib) << "\t\t\tcolor0=" << (int *) color0 - << " at x=" << x << ",y=" << y << endl; + << " at x=" << x << ",y=" << y; } else if (!color1Valid) { color1 = imagePixel; color1Valid = true; monoImage.setPixel (x, y, 1); qCDebug(kpLogImagelib) << "\t\t\tcolor1=" << (int *) color1 - << " at x=" << x << ",y=" << y << endl; + << " at x=" << x << ",y=" << y; } else { qCDebug(kpLogImagelib) << "\t\t\timagePixel=" << (int *) imagePixel << " at x=" << x << ",y=" << y - << " moreThan2Colors - abort hack" << endl; + << " moreThan2Colors - abort hack"; moreThan2Colors = true; // Dijkstra, this is clearer than double break'ing or // a check in both loops goto exit_loop; } } } exit_loop: if (!moreThan2Colors) { monoImage.setColor (0, color0Valid ? color0 : 0xFFFFFF); monoImage.setColor (1, color1Valid ? color1 : 0x000000); return monoImage; } } QImage retImage = image.convertToFormat (::DepthToFormat (depth), Qt::AutoColor | (dither ? Qt::DiffuseDither : Qt::ThresholdDither) | Qt::ThresholdAlphaDither | (dither ? Qt::PreferDither : Qt::AvoidDither)); qCDebug(kpLogImagelib) << "\tformat: before=" << image.format () << "after=" << retImage.format (); qCDebug(kpLogImagelib) << "After colour reduction:"; for (int y = 0; y < image.height (); y++) { for (int x = 0; x < image.width (); x++) { fprintf (stderr, " %08X", image.pixel (x, y)); } fprintf (stderr, "\n"); } return retImage; } //--------------------------------------------------------------------- // public static void kpEffectReduceColors::applyEffect (QImage *destPtr, int depth, bool dither) { - if (!destPtr) + if (!destPtr) { return; + } // You can't "reduce" to 32-bit since it's the highest depth. - if (depth != 1 && depth != 8) + if (depth != 1 && depth != 8) { return; + } *destPtr = convertImageDepth(*destPtr, depth, dither); // internally we always use QImage::Format_ARGB32_Premultiplied and // this effect is just an "effect" in that it changes the image (the look) somehow // When one wants a different depth on the file, then he needs to save the image // in that depth *destPtr = destPtr->convertToFormat(QImage::Format_ARGB32_Premultiplied); } //--------------------------------------------------------------------- QImage kpEffectReduceColors::applyEffect (const QImage &pm, int depth, bool dither) { QImage ret = pm; applyEffect (&ret, depth, dither); return ret; } //--------------------------------------------------------------------- diff --git a/imagelib/effects/kpEffectToneEnhance.cpp b/imagelib/effects/kpEffectToneEnhance.cpp index 6e47e9f7..13680203 100644 --- a/imagelib/effects/kpEffectToneEnhance.cpp +++ b/imagelib/effects/kpEffectToneEnhance.cpp @@ -1,291 +1,308 @@ /* Copyright (c) 2003-2007 Clarence Dang Copyright (c) 2006 Mike Gashler All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ // TODO: Clarence's code review #include "kpEffectToneEnhance.h" #include #include "kpLogCategories.h" #include "pixmapfx/kpPixmapFX.h" #define RED_WEIGHT 77 #define GREEN_WEIGHT 150 #define BLUE_WEIGHT 29 #define MAX_TONE_VALUE ((RED_WEIGHT + GREEN_WEIGHT + BLUE_WEIGHT) * 255) #define TONE_DROP_BITS 5 #define TONE_MAP_SIZE ((MAX_TONE_VALUE >> TONE_DROP_BITS) + 1) #define MAX_GRANULARITY 25 #define MIN_IMAGE_DIM 3 //--------------------------------------------------------------------- inline unsigned int ComputeTone(unsigned int color) { return RED_WEIGHT * static_cast (qRed(color)) + GREEN_WEIGHT * static_cast (qGreen(color)) + BLUE_WEIGHT * static_cast (qBlue(color)); } //--------------------------------------------------------------------- inline unsigned int AdjustTone(unsigned int color, unsigned int oldTone, unsigned int newTone, double amount) { return qRgba( qMax(0, qMin(255, static_cast (amount * qRed(color) * newTone / oldTone + (1.0 - amount) * qRed(color)))), qMax(0, qMin(255, static_cast (amount * qGreen(color) * newTone / oldTone + (1.0 - amount) * qGreen(color)))), qMax(0, qMin(255, static_cast (amount * qBlue(color) * newTone / oldTone + (1.0 - amount) * qBlue(color)))), qAlpha(color) ); } //--------------------------------------------------------------------- class kpEffectToneEnhanceApplier { public: kpEffectToneEnhanceApplier (); ~kpEffectToneEnhanceApplier (); void BalanceImageTone(QImage* pImage, double granularity, double amount); protected: int m_nToneMapGranularity, m_areaWid, m_areaHgt; unsigned int m_nComputedWid, m_nComputedHgt; // LOTODO: Use less error-prone QTL containers instead. unsigned int* m_pHistogram; unsigned int** m_pToneMaps; void DeleteToneMaps(); unsigned int* MakeToneMap(QImage* pImage, int x, int y, int nGranularity); void ComputeToneMaps(QImage* pImage, int nGranularity); unsigned int InterpolateNewTone(QImage* pImage, unsigned int oldTone, int x, int y, int nGranularity); }; //--------------------------------------------------------------------- kpEffectToneEnhanceApplier::kpEffectToneEnhanceApplier () { m_nToneMapGranularity = 0; m_areaWid = 0; m_areaHgt = 0; m_nComputedWid = 0; m_nComputedHgt = 0; m_pHistogram = new unsigned int[TONE_MAP_SIZE]; m_pToneMaps = nullptr; } //--------------------------------------------------------------------- kpEffectToneEnhanceApplier::~kpEffectToneEnhanceApplier () { DeleteToneMaps(); delete[] m_pHistogram; } //--------------------------------------------------------------------- // protected void kpEffectToneEnhanceApplier::DeleteToneMaps() { int nToneMaps = m_nToneMapGranularity * m_nToneMapGranularity; - for(int i = 0; i < nToneMaps; i++) - delete[] m_pToneMaps[i]; + for(int i = 0; i < nToneMaps; i++) { + delete[] m_pToneMaps[i]; + } delete[] m_pToneMaps; m_pToneMaps = nullptr; m_nToneMapGranularity = 0; } //--------------------------------------------------------------------- // protected unsigned int* kpEffectToneEnhanceApplier::MakeToneMap(QImage* pImage, int u, int v, int nGranularity) { - // Compute the region to make the tone map for - int xx, yy; - if(nGranularity > 1) - { - xx = u * (pImage->width() - 1) / (nGranularity - 1) - m_areaWid / 2; - if(xx < 0) - xx = 0; - else if(xx + m_areaWid > pImage->width()) - xx = pImage->width() - m_areaWid; - yy = v * (pImage->width() - 1) / (nGranularity - 1) - m_areaHgt / 2; - if(yy < 0) - yy = 0; - else if(yy + m_areaHgt > pImage->height()) - yy = pImage->height() - m_areaHgt; - } - else - { - xx = 0; - yy = 0; - } + // Compute the region to make the tone map for + int xx, yy; + if(nGranularity > 1) + { + xx = u * (pImage->width() - 1) / (nGranularity - 1) - m_areaWid / 2; + if(xx < 0) { + xx = 0; + } + else if(xx + m_areaWid > pImage->width()) { + xx = pImage->width() - m_areaWid; + } + + yy = v * (pImage->width() - 1) / (nGranularity - 1) - m_areaHgt / 2; + + if(yy < 0) { + yy = 0; + } + else if(yy + m_areaHgt > pImage->height()) { + yy = pImage->height() - m_areaHgt; + } + } + else + { + xx = 0; + yy = 0; + } // Make a tone histogram for the region memset(m_pHistogram, '\0', sizeof(unsigned int) * TONE_MAP_SIZE); int x, y; unsigned int tone; for(y = 0; y < m_areaHgt; y++) { for(x = 0; x < m_areaWid; x++) { tone = ComputeTone(pImage->pixel(xx + x, yy + y)); m_pHistogram[tone >> TONE_DROP_BITS]++; } } // Forward sum the tone histogram - int i; - for(i = 1; i < TONE_MAP_SIZE; i++) - m_pHistogram[i] += m_pHistogram[i - 1]; + int i{}; + for(i = 1; i < TONE_MAP_SIZE; i++) { + m_pHistogram[i] += m_pHistogram[i - 1]; + } // Compute the forward contribution to the tone map - unsigned int total = m_pHistogram[i - 1]; - unsigned int* pToneMap = new unsigned int[TONE_MAP_SIZE]; - for(i = 0; i < TONE_MAP_SIZE; i++) - pToneMap[i] = static_cast (static_cast (m_pHistogram[i] * MAX_TONE_VALUE / total)); + auto total = m_pHistogram[i - 1]; + auto *pToneMap = new unsigned int[TONE_MAP_SIZE]; + for(i = 0; i < TONE_MAP_SIZE; i++) { + pToneMap[i] = static_cast (static_cast (m_pHistogram[i] * MAX_TONE_VALUE / total)); + } /* // Undo the forward sum and reverse sum the tone histogram m_pHistogram[TONE_MAP_SIZE - 1] -= m_pHistogram[TONE_MAP_SIZE - 2]; for(i = TONE_MAP_SIZE - 2; i > 0; i--) { m_pHistogram[i] -= m_pHistogram[i - 1]; m_pHistogram[i] += m_pHistogram[i + 1]; } m_pHistogram[0] += m_pHistogram[1]; */ return pToneMap; } //--------------------------------------------------------------------- // protected void kpEffectToneEnhanceApplier::ComputeToneMaps(QImage* pImage, int nGranularity) { if(nGranularity == m_nToneMapGranularity && pImage->width() == static_cast (m_nComputedWid) && pImage->height() == static_cast (m_nComputedHgt)) { return; // We've already computed tone maps for this granularity } DeleteToneMaps(); m_pToneMaps = new unsigned int*[nGranularity * nGranularity]; m_nToneMapGranularity = nGranularity; m_nComputedWid = static_cast (pImage->width()); m_nComputedHgt = static_cast (pImage->height()); int u, v; for(v = 0; v < nGranularity; v++) { - for(u = 0; u < nGranularity; u++) - m_pToneMaps[nGranularity * v + u] = MakeToneMap(pImage, u, v, nGranularity); + for(u = 0; u < nGranularity; u++) { + m_pToneMaps[nGranularity * v + u] = MakeToneMap(pImage, u, v, nGranularity); + } } } //--------------------------------------------------------------------- // protected unsigned int kpEffectToneEnhanceApplier::InterpolateNewTone(QImage* pImage, unsigned int oldTone, int x, int y, int nGranularity) { oldTone = (oldTone >> TONE_DROP_BITS); - if(m_nToneMapGranularity <= 1) - return m_pToneMaps[0][oldTone]; - int u = x * (nGranularity - 1) / pImage->width(); - int v = y * (nGranularity - 1) / pImage->height(); - unsigned int x1y1 = m_pToneMaps[m_nToneMapGranularity * v + u][oldTone]; - unsigned int x2y1 = m_pToneMaps[m_nToneMapGranularity * v + u + 1][oldTone]; - unsigned int x1y2 = m_pToneMaps[m_nToneMapGranularity * (v + 1) + u][oldTone]; - unsigned int x2y2 = m_pToneMaps[m_nToneMapGranularity * (v + 1) + u + 1][oldTone]; - int hFac = x - (u * (pImage->width() - 1) / (nGranularity - 1)); - if(hFac > m_areaWid) - hFac = m_areaWid; + if(m_nToneMapGranularity <= 1) { + return m_pToneMaps[0][oldTone]; + } + auto u = x * (nGranularity - 1) / pImage->width(); + auto v = y * (nGranularity - 1) / pImage->height(); + auto x1y1 = m_pToneMaps[m_nToneMapGranularity * v + u][oldTone]; + auto x2y1 = m_pToneMaps[m_nToneMapGranularity * v + u + 1][oldTone]; + auto x1y2 = m_pToneMaps[m_nToneMapGranularity * (v + 1) + u][oldTone]; + auto x2y2 = m_pToneMaps[m_nToneMapGranularity * (v + 1) + u + 1][oldTone]; + auto hFac = x - (u * (pImage->width() - 1) / (nGranularity - 1)); + if(hFac > m_areaWid) { + hFac = m_areaWid; + } unsigned int y1 = (x1y1 * (static_cast (m_areaWid) - static_cast (hFac)) + x2y1 * static_cast (hFac)) / static_cast (m_areaWid); unsigned int y2 = (x1y2 * (static_cast (m_areaWid) - static_cast (hFac)) + x2y2 * static_cast (hFac)) / static_cast (m_areaWid); int vFac = y - (v * (pImage->height() - 1) / (nGranularity - 1)); - if(vFac > m_areaHgt) - vFac = m_areaHgt; + if(vFac > m_areaHgt) { + vFac = m_areaHgt; + } return (y1 * (static_cast (m_areaHgt) - static_cast (vFac)) + y2 * static_cast (vFac)) / static_cast (m_areaHgt); } //--------------------------------------------------------------------- // public void kpEffectToneEnhanceApplier::BalanceImageTone(QImage* pImage, double granularity, double amount) { - if(pImage->width() < MIN_IMAGE_DIM || pImage->height() < MIN_IMAGE_DIM) - return; // the image is not big enough to perform this operation + if(pImage->width() < MIN_IMAGE_DIM || pImage->height() < MIN_IMAGE_DIM) { + return; // the image is not big enough to perform this operation + } int nGranularity = static_cast (granularity * (MAX_GRANULARITY - 2)) + 1; m_areaWid = pImage->width() / nGranularity; - if(m_areaWid < MIN_IMAGE_DIM) + if(m_areaWid < MIN_IMAGE_DIM) { m_areaWid = MIN_IMAGE_DIM; + } m_areaHgt = pImage->height() / nGranularity; - if(m_areaHgt < MIN_IMAGE_DIM) + if(m_areaHgt < MIN_IMAGE_DIM) { m_areaHgt = MIN_IMAGE_DIM; + } ComputeToneMaps(pImage, nGranularity); int x, y; unsigned int oldTone, newTone, col; for(y = 0; y < pImage->height(); y++) { for(x = 0; x < pImage->width(); x++) { col = pImage->pixel(x, y); oldTone = ComputeTone(col); newTone = InterpolateNewTone(pImage, oldTone, x, y, nGranularity); pImage->setPixel(x, y, AdjustTone(col, oldTone, newTone, amount)); } } } //--------------------------------------------------------------------- // public static kpImage kpEffectToneEnhance::applyEffect (const kpImage &image, double granularity, double amount) { - if (amount == 0.0) + if (amount == 0.0) { return image; + } QImage qimage(image); // OPT: Cache the calculated values? kpEffectToneEnhanceApplier applier; applier.BalanceImageTone (&qimage, granularity, amount); return qimage; } //--------------------------------------------------------------------- diff --git a/imagelib/kpColor.cpp b/imagelib/kpColor.cpp index 4c4a8ecd..aaa04c09 100644 --- a/imagelib/kpColor.cpp +++ b/imagelib/kpColor.cpp @@ -1,304 +1,311 @@ /* Copyright (c) 2003-2007 Clarence Dang All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #define DEBUG_KP_COLOR 0 #include "kpColor.h" #include #include "kpLogCategories.h" //--------------------------------------------------------------------- kpColor::kpColor() : m_rgbaIsValid(false), m_rgba(0), m_colorCacheIsValid(false) { } //--------------------------------------------------------------------- kpColor::kpColor (int red, int green, int blue, bool isTransparent) : m_rgba(0), m_colorCacheIsValid(false) { qCDebug(kpLogImagelib) << "kpColor::(r=" << red << ",g=" << green << ",b=" << blue - << ",isTrans=" << isTransparent << ")" << endl; + << ",isTrans=" << isTransparent << ")"; if (red < 0 || red > 255 || green < 0 || green > 255 || blue < 0 || blue > 255) { qCCritical(kpLogImagelib) << "kpColor::(r=" << red << ",g=" << green << ",b=" << blue << ",t=" << isTransparent - << ") passed out of range values" << endl; + << ") passed out of range values"; m_rgbaIsValid = false; return; } m_rgba = qRgba (red, green, blue, isTransparent ? 0 : 255/*opaque*/); m_rgbaIsValid = true; } //--------------------------------------------------------------------- kpColor::kpColor (const QRgb &rgba) : m_colorCacheIsValid (false) { qCDebug(kpLogImagelib) << "kpColor::(rgba=" << (int *) rgba << ")"; m_rgba = rgba; m_rgbaIsValid = true; } //--------------------------------------------------------------------- kpColor::kpColor (const kpColor &rhs) : m_rgbaIsValid (rhs.m_rgbaIsValid), m_rgba (rhs.m_rgba), m_colorCacheIsValid (rhs.m_colorCacheIsValid), m_colorCache (rhs.m_colorCache) { qCDebug(kpLogImagelib) << "kpColor::()"; } //--------------------------------------------------------------------- // friend QDataStream &operator<< (QDataStream &stream, const kpColor &color) { stream << int (color.m_rgbaIsValid) << int (color.m_rgba); return stream; } //--------------------------------------------------------------------- // friend QDataStream &operator>> (QDataStream &stream, kpColor &color) { int a, b; stream >> a >> b; color.m_rgbaIsValid = a; color.m_rgba = static_cast (b); color.m_colorCacheIsValid = false; return stream; } //--------------------------------------------------------------------- kpColor &kpColor::operator= (const kpColor &rhs) { // (as soon as you add a ptr, you won't be complaining to me that this // method was unnecessary :)) - if (this == &rhs) + if (this == &rhs) { return *this; + } m_rgbaIsValid = rhs.m_rgbaIsValid; m_rgba = rhs.m_rgba; m_colorCacheIsValid = rhs.m_colorCacheIsValid; m_colorCache = rhs.m_colorCache; return *this; } bool kpColor::operator== (const kpColor &rhs) const { return isSimilarTo (rhs, kpColor::Exact); } bool kpColor::operator!= (const kpColor &rhs) const { return !(*this == rhs); } //--------------------------------------------------------------------- template inline dtype square (dtype val) { return val * val; } //--------------------------------------------------------------------- // public static int kpColor::processSimilarity (double colorSimilarity) { // sqrt (dr ^ 2 + dg ^ 2 + db ^ 2) <= colorSimilarity * sqrt (255 ^ 2 * 3) // dr ^ 2 + dg ^ 2 + db ^ 2 <= (colorSimilarity ^ 2) * (255 ^ 2 * 3) return int (square (colorSimilarity) * (square (255) * 3)); } //--------------------------------------------------------------------- bool kpColor::isSimilarTo (const kpColor &rhs, int processedSimilarity) const { // Are we the same? - if (this == &rhs) + if (this == &rhs) { return true; + } // Do we dither in terms of validity? - if (isValid () != rhs.isValid ()) + if (isValid () != rhs.isValid ()) { return false; + } // Are both of us invalid? - if (!isValid ()) + if (!isValid ()) { return true; + } // --- both are now valid --- - if (m_rgba == rhs.m_rgba) + if (m_rgba == rhs.m_rgba) { return true; + } - if (processedSimilarity == kpColor::Exact) + if (processedSimilarity == kpColor::Exact) { return false; - else - { - return (square (qRed (m_rgba) - qRed (rhs.m_rgba)) + - square (qGreen (m_rgba) - qGreen (rhs.m_rgba)) + - square (qBlue (m_rgba) - qBlue (rhs.m_rgba)) - <= processedSimilarity); } + + + return (square (qRed (m_rgba) - qRed (rhs.m_rgba)) + + square (qGreen (m_rgba) - qGreen (rhs.m_rgba)) + + square (qBlue (m_rgba) - qBlue (rhs.m_rgba)) + <= processedSimilarity); + } //--------------------------------------------------------------------- // public bool kpColor::isValid () const { return m_rgbaIsValid; } //--------------------------------------------------------------------- // public int kpColor::red () const { if (!m_rgbaIsValid) { - qCCritical(kpLogImagelib) << "kpColor::red() called with invalid kpColor" << endl; + qCCritical(kpLogImagelib) << "kpColor::red() called with invalid kpColor"; return 0; } return qRed (m_rgba); } //--------------------------------------------------------------------- // public int kpColor::green () const { if (!m_rgbaIsValid) { - qCCritical(kpLogImagelib) << "kpColor::green() called with invalid kpColor" << endl; + qCCritical(kpLogImagelib) << "kpColor::green() called with invalid kpColor"; return 0; } return qGreen (m_rgba); } //--------------------------------------------------------------------- // public int kpColor::blue () const { if (!m_rgbaIsValid) { - qCCritical(kpLogImagelib) << "kpColor::blue() called with invalid kpColor" << endl; + qCCritical(kpLogImagelib) << "kpColor::blue() called with invalid kpColor"; return 0; } return qBlue (m_rgba); } //--------------------------------------------------------------------- // public int kpColor::alpha () const { if (!m_rgbaIsValid) { - qCCritical(kpLogImagelib) << "kpColor::alpha() called with invalid kpColor" << endl; + qCCritical(kpLogImagelib) << "kpColor::alpha() called with invalid kpColor"; return 0; } return qAlpha (m_rgba); } //--------------------------------------------------------------------- // public bool kpColor::isTransparent () const { return (alpha () == 0); } //--------------------------------------------------------------------- // public QRgb kpColor::toQRgb () const { if (!m_rgbaIsValid) { - qCCritical(kpLogImagelib) << "kpColor::toQRgb() called with invalid kpColor" << endl; + qCCritical(kpLogImagelib) << "kpColor::toQRgb() called with invalid kpColor"; return 0; } return m_rgba; } //--------------------------------------------------------------------- // public QColor kpColor::toQColor () const { if (!m_rgbaIsValid) { - qCCritical(kpLogImagelib) << "kpColor::toQColor() called with invalid kpColor" << endl; + qCCritical(kpLogImagelib) << "kpColor::toQColor() called with invalid kpColor"; return Qt::black; } - if (m_colorCacheIsValid) + if (m_colorCacheIsValid) { return m_colorCache; + } m_colorCache = QColor(qRed(m_rgba), qGreen(m_rgba), qBlue(m_rgba), qAlpha(m_rgba)); m_colorCacheIsValid = true; return m_colorCache; } //--------------------------------------------------------------------- diff --git a/imagelib/kpDocumentMetaInfo.cpp b/imagelib/kpDocumentMetaInfo.cpp index d1b54c64..18ed450e 100644 --- a/imagelib/kpDocumentMetaInfo.cpp +++ b/imagelib/kpDocumentMetaInfo.cpp @@ -1,282 +1,284 @@ /* Copyright (c) 2003-2007 Clarence Dang All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include "kpDocumentMetaInfo.h" #include #include #include #include "kpLogCategories.h" #include "kpDefs.h" // // Constants which "ought to be enough for anybody" // LOTODO: Maybe there are some QImage constants somewhere? // // public static // (round up to guarantee at least 1 dot per inch) const int kpDocumentMetaInfo::MinDotsPerMeter = int (std::ceil (1/*single dot per inch - a very low DPI*/ * KP_INCHES_PER_METER) + 0.1); const int kpDocumentMetaInfo::MaxDotsPerMeter = int ((600 * 100)/*a lot of DPI*/ * KP_INCHES_PER_METER); // public static const int kpDocumentMetaInfo::MaxOffset = (4000/*big image*/ * 100)/*a very big image*/; const int kpDocumentMetaInfo::MinOffset = -kpDocumentMetaInfo::MaxOffset; //--------------------------------------------------------------------- struct kpDocumentMetaInfoPrivate { - int m_dotsPerMeterX, m_dotsPerMeterY; + int m_dotsPerMeterX{}, m_dotsPerMeterY{}; QPoint m_offset; QMap m_textMap; }; //--------------------------------------------------------------------- // public kpDocumentMetaInfo::kpDocumentMetaInfo () : d (new kpDocumentMetaInfoPrivate ()) { d->m_dotsPerMeterX = 0; d->m_dotsPerMeterY = 0; d->m_offset = QPoint (0, 0); } //--------------------------------------------------------------------- kpDocumentMetaInfo::kpDocumentMetaInfo (const kpDocumentMetaInfo &rhs) : d (new kpDocumentMetaInfoPrivate ()) { d->m_dotsPerMeterX = rhs.dotsPerMeterX (); d->m_dotsPerMeterY = rhs.dotsPerMeterY (); d->m_offset = rhs.offset (); d->m_textMap = rhs.textMap (); } //--------------------------------------------------------------------- // public kpDocumentMetaInfo::~kpDocumentMetaInfo () { delete d; } //--------------------------------------------------------------------- // public bool kpDocumentMetaInfo::operator== (const kpDocumentMetaInfo &rhs) const { return (d->m_dotsPerMeterX == rhs.d->m_dotsPerMeterX && d->m_dotsPerMeterY == rhs.d->m_dotsPerMeterY && d->m_offset == rhs.d->m_offset && d->m_textMap == rhs.d->m_textMap); } //--------------------------------------------------------------------- // public bool kpDocumentMetaInfo::operator!= (const kpDocumentMetaInfo &rhs) const { return !(*this == rhs); } //--------------------------------------------------------------------- // public kpDocumentMetaInfo &kpDocumentMetaInfo::operator= (const kpDocumentMetaInfo &rhs) { - if (this == &rhs) + if (this == &rhs) { return *this; + } d->m_dotsPerMeterX = rhs.dotsPerMeterX (); d->m_dotsPerMeterY = rhs.dotsPerMeterY (); d->m_offset = rhs.offset (); d->m_textMap = rhs.textMap (); return *this; } //--------------------------------------------------------------------- // public void kpDocumentMetaInfo::printDebug (const QString &prefix) const { const QString usedPrefix = !prefix.isEmpty() ? QString(prefix + QLatin1String(":")) : QString(); qCDebug(kpLogImagelib) << usedPrefix; qCDebug(kpLogImagelib) << "dotsPerMeter X=" << dotsPerMeterX () << " Y=" << dotsPerMeterY () - << " offset=" << offset () << endl; + << " offset=" << offset (); QList keyList = textKeys (); for (QList ::const_iterator it = keyList.constBegin (); it != keyList.constEnd (); ++it) { qCDebug(kpLogImagelib) << "key=" << (*it) - << " text=" << text (*it) - << endl; + << " text=" << text (*it); } qCDebug(kpLogImagelib) << usedPrefix << "ENDS"; } //--------------------------------------------------------------------- // public kpCommandSize::SizeType kpDocumentMetaInfo::size () const { kpCommandSize::SizeType ret = 0; - foreach (const QString &key, d->m_textMap.keys ()) + for (const auto &key : d->m_textMap.keys ()) { ret += kpCommandSize::StringSize (key) + kpCommandSize::StringSize (d->m_textMap [key]); } // We don't know what the QMap size overhead is so overestimate the size // rather than underestimating it. // LOTODO: Find the proper size in bytes. return ret * 3; } //--------------------------------------------------------------------- // public int kpDocumentMetaInfo::dotsPerMeterX () const { return d->m_dotsPerMeterX; } //--------------------------------------------------------------------- // public void kpDocumentMetaInfo::setDotsPerMeterX (int val) { // Unspecified resolution? if (val == 0) { d->m_dotsPerMeterX = 0; return; } d->m_dotsPerMeterX = qBound (MinDotsPerMeter, val, MaxDotsPerMeter); } //--------------------------------------------------------------------- // public int kpDocumentMetaInfo::dotsPerMeterY () const { return d->m_dotsPerMeterY; } //--------------------------------------------------------------------- // public void kpDocumentMetaInfo::setDotsPerMeterY (int val) { // Unspecified resolution? if (val == 0) { d->m_dotsPerMeterY = 0; return; } d->m_dotsPerMeterY = qBound (MinDotsPerMeter, val, MaxDotsPerMeter); } //--------------------------------------------------------------------- // public QPoint kpDocumentMetaInfo::offset () const { return d->m_offset; } //--------------------------------------------------------------------- // public void kpDocumentMetaInfo::setOffset (const QPoint &point) { const int x = qBound (MinOffset, point.x (), MaxOffset); const int y = qBound (MinOffset, point.y (), MaxOffset); d->m_offset = QPoint (x, y); } //--------------------------------------------------------------------- // public QMap kpDocumentMetaInfo::textMap () const { return d->m_textMap; } //--------------------------------------------------------------------- // public QList kpDocumentMetaInfo::textKeys () const { return d->m_textMap.keys (); } //--------------------------------------------------------------------- // public QString kpDocumentMetaInfo::text (const QString &key) const { - if (key.isEmpty ()) - return QString (); + if (key.isEmpty ()) { + return {}; + } return d->m_textMap [key]; } //--------------------------------------------------------------------- // public void kpDocumentMetaInfo::setText (const QString &key, const QString &value) { - if (key.isEmpty ()) + if (key.isEmpty ()) { return; + } d->m_textMap [key] = value; } //--------------------------------------------------------------------- diff --git a/imagelib/kpFloodFill.cpp b/imagelib/kpFloodFill.cpp index af7fca62..a28e9652 100644 --- a/imagelib/kpFloodFill.cpp +++ b/imagelib/kpFloodFill.cpp @@ -1,397 +1,412 @@ /* Copyright (c) 2003-2007 Clarence Dang All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #define DEBUG_KP_FLOOD_FILL 0 #include "kpFloodFill.h" #include #include #include #include #include #include "kpLogCategories.h" #include "kpColor.h" #include "kpImage.h" #include "kpDefs.h" #include "pixmapfx/kpPixmapFX.h" #include "tools/kpTool.h" //--------------------------------------------------------------------- class kpFillLine { public: kpFillLine (int y = -1, int x1 = -1, int x2 = -1) : m_y (y), m_x1 (x1), m_x2 (x2) { } static kpCommandSize::SizeType size () { return sizeof (kpFillLine); } int m_y, m_x1, m_x2; }; //--------------------------------------------------------------------- static kpCommandSize::SizeType FillLinesListSize (const QLinkedList &fillLines) { return (fillLines.size () * kpFillLine::size ()); } //--------------------------------------------------------------------- struct kpFloodFillPrivate { // // Copy of whatever was passed to the constructor. // - kpImage *imagePtr; - int x, y; + kpImage *imagePtr{}; + int x{}, y{}; kpColor color; - int processedColorSimilarity; + int processedColorSimilarity{}; // // Set by Step 1. // kpColor colorToChange; // // Set by Step 2. // QLinkedList fillLines; QList < QLinkedList > fillLinesCache; QRect boundingRect; - bool prepared; + bool prepared{}; }; //--------------------------------------------------------------------- kpFloodFill::kpFloodFill (kpImage *image, int x, int y, const kpColor &color, int processedColorSimilarity) : d (new kpFloodFillPrivate ()) { d->imagePtr = image; d->x = x; d->y = y; d->color = color; d->processedColorSimilarity = processedColorSimilarity; d->prepared = false; } //--------------------------------------------------------------------- kpFloodFill::~kpFloodFill () { delete d; } //--------------------------------------------------------------------- // public kpColor kpFloodFill::color () const { return d->color; } //--------------------------------------------------------------------- // public int kpFloodFill::processedColorSimilarity () const { return d->processedColorSimilarity; } //--------------------------------------------------------------------- // public kpCommandSize::SizeType kpFloodFill::size () const { kpCommandSize::SizeType fillLinesCacheSize = 0; - foreach (const QLinkedList &linesList, d->fillLinesCache) + for (const auto &linesList : d->fillLinesCache) { fillLinesCacheSize += ::FillLinesListSize (linesList); } return ::FillLinesListSize(d->fillLines) + kpCommandSize::QImageSize(d->imagePtr) + fillLinesCacheSize; } //--------------------------------------------------------------------- // public void kpFloodFill::prepareColorToChange () { - if (d->colorToChange.isValid ()) + if (d->colorToChange.isValid ()) { return; + } qCDebug(kpLogImagelib) << "kpFloodFill::prepareColorToChange()"; d->colorToChange = kpPixmapFX::getColorAtPixel (*d->imagePtr, QPoint (d->x, d->y)); } //--------------------------------------------------------------------- // public kpColor kpFloodFill::colorToChange () { prepareColorToChange (); return d->colorToChange; } //--------------------------------------------------------------------- // Derived from the zSprite2 Graphics Engine // private kpColor kpFloodFill::pixelColor (int x, int y, bool *beenHere) const { - if (beenHere) + if (beenHere) { *beenHere = false; + } Q_ASSERT (y >= 0 && y < static_cast (d->fillLinesCache.count ())); - foreach (const kpFillLine &line, d->fillLinesCache [y]) + for (const auto &line : d->fillLinesCache [y]) { if (x >= line.m_x1 && x <= line.m_x2) { - if (beenHere) + if (beenHere) { *beenHere = true; + } return d->color; } } return kpPixmapFX::getColorAtPixel (*(d->imagePtr), QPoint (x, y)); } //--------------------------------------------------------------------- // private bool kpFloodFill::shouldGoTo (int x, int y) const { bool beenThere; const kpColor col = pixelColor (x, y, &beenThere); return (!beenThere && col.isSimilarTo (d->colorToChange, d->processedColorSimilarity)); } //--------------------------------------------------------------------- // private int kpFloodFill::findMinX (int y, int x) const { for (;;) { - if (x < 0) + if (x < 0) { return 0; + } - if (shouldGoTo (x, y)) + if (shouldGoTo (x, y)) { x--; - else + } + else { return x + 1; + } } } //--------------------------------------------------------------------- // private int kpFloodFill::findMaxX (int y, int x) const { for (;;) { - if (x > d->imagePtr->width () - 1) + if (x > d->imagePtr->width () - 1) { return d->imagePtr->width () - 1; + } - if (shouldGoTo (x, y)) + if (shouldGoTo (x, y)) { x++; - else + } + else { return x - 1; + } } } //--------------------------------------------------------------------- // private void kpFloodFill::addLine (int y, int x1, int x2) { qCDebug(kpLogImagelib) << "kpFillCommand::fillAddLine (" << y << "," << x1 << "," << x2 << ")"; d->fillLines.append (kpFillLine (y, x1, x2)); d->fillLinesCache [y].append ( kpFillLine (y/*OPT: can determine from array index*/, x1, x2)); d->boundingRect = d->boundingRect.united (QRect (QPoint (x1, y), QPoint (x2, y))); } //--------------------------------------------------------------------- // private void kpFloodFill::findAndAddLines (const kpFillLine &fillLine, int dy) { // out of bounds? - if (fillLine.m_y + dy < 0 || fillLine.m_y + dy >= d->imagePtr->height ()) + if (fillLine.m_y + dy < 0 || fillLine.m_y + dy >= d->imagePtr->height ()) { return; + } for (int xnow = fillLine.m_x1; xnow <= fillLine.m_x2; xnow++) { // At current position, right colour? if (shouldGoTo (xnow, fillLine.m_y + dy)) { // Find minimum and maximum x values int minxnow = findMinX (fillLine.m_y + dy, xnow); int maxxnow = findMaxX (fillLine.m_y + dy, xnow); // Draw line addLine (fillLine.m_y + dy, minxnow, maxxnow); // Move x pointer xnow = maxxnow; } } } //--------------------------------------------------------------------- // public void kpFloodFill::prepare () { - if (d->prepared) + if (d->prepared) { return; + } qCDebug(kpLogImagelib) << "kpFloodFill::prepare()"; prepareColorToChange (); d->boundingRect = QRect (); qCDebug(kpLogImagelib) << "\tperforming NOP check"; // get the color we need to replace if (d->processedColorSimilarity == 0 && d->color == d->colorToChange) { // need to do absolutely nothing (this is a significant optimization // for people who randomly click a lot over already-filled areas) d->prepared = true; // sync with all "return true"'s return; } qCDebug(kpLogImagelib) << "\tcreating fillLinesCache"; // ready cache - for (int i = 0; i < d->imagePtr->height (); i++) + for (int i = 0; i < d->imagePtr->height (); i++) { d->fillLinesCache.append (QLinkedList ()); + } qCDebug(kpLogImagelib) << "\tcreating fill lines"; // draw initial line addLine (d->y, findMinX (d->y, d->x), findMaxX (d->y, d->x)); for (QLinkedList ::ConstIterator it = d->fillLines.begin (); it != d->fillLines.end (); ++it) { qCDebug(kpLogImagelib) << "Expanding from y=" << (*it).m_y << " x1=" << (*it).m_x1 << " x2=" << (*it).m_x2; // // Make more lines above and below current line. // // WARNING: Adds to end of "fillLines" (the linked list we are iterating // through). Therefore, "fillLines" must remain a linked list // - you cannot change it into a vector. Also, do not use // "foreach" for this loop as that makes a copy of the linked // list at the start and won't see new lines. // findAndAddLines (*it, -1); findAndAddLines (*it, +1); } qCDebug(kpLogImagelib) << "\tfinalising memory usage"; // finalize memory usage d->fillLinesCache.clear (); d->prepared = true; // sync with all "return true"'s } //--------------------------------------------------------------------- // public QRect kpFloodFill::boundingRect () { prepare (); return d->boundingRect; } //--------------------------------------------------------------------- // public void kpFloodFill::fill() { prepare(); QApplication::setOverrideCursor(Qt::WaitCursor); QPainter painter(d->imagePtr); // by definition, flood fill with a fully transparent color erases the pixels // and sets them to be fully transparent - if ( d->color.isTransparent() ) + if ( d->color.isTransparent() ) { painter.setCompositionMode(QPainter::CompositionMode_Clear); + } painter.setPen(d->color.toQColor()); - foreach (const kpFillLine &l, d->fillLines) + for (const auto &l : d->fillLines) { - if ( l.m_x1 == l.m_x2 ) + if ( l.m_x1 == l.m_x2 ) { painter.drawPoint(l.m_x1, l.m_y); - else + } + else { painter.drawLine(l.m_x1, l.m_y, l.m_x2, l.m_y); + } } QApplication::restoreOverrideCursor(); } //--------------------------------------------------------------------- diff --git a/imagelib/kpPainter.cpp b/imagelib/kpPainter.cpp index ec2a1bd9..5d9de308 100644 --- a/imagelib/kpPainter.cpp +++ b/imagelib/kpPainter.cpp @@ -1,457 +1,469 @@ /* Copyright (c) 2003-2007 Clarence Dang All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include "kpPainter.h" #include "kpImage.h" #include "pixmapfx/kpPixmapFX.h" #include "tools/kpTool.h" #include "tools/flow/kpToolFlowBase.h" #include #include #include #include #include #include "kpLogCategories.h" #include //--------------------------------------------------------------------- // public static bool kpPainter::pointsAreCardinallyAdjacent (const QPoint &p, const QPoint &q) { int dx = qAbs (p.x () - q.x ()); int dy = qAbs (p.y () - q.y ()); return (dx + dy == 1); } //--------------------------------------------------------------------- // Returns a random integer from 0 to 999 inclusive. static int RandomNumberFrom0to999 () { return (KRandom::random () % 1000); } //--------------------------------------------------------------------- // public static QList kpPainter::interpolatePoints (const QPoint &startPoint, const QPoint &endPoint, bool cardinalAdjacency, double probability) { qCDebug(kpLogImagelib) << "CALL(startPoint=" << startPoint << ",endPoint=" << endPoint << ")"; QList ret; Q_ASSERT (probability >= 0.0 && probability <= 1.0); const int probabilityTimes1000 = qRound (probability * 1000); #define SHOULD_DRAW() (probabilityTimes1000 == 1000/*avoid ::RandomNumberFrom0to999() call*/ || \ ::RandomNumberFrom0to999 () < probabilityTimes1000) // Derived from the zSprite2 Graphics Engine. // "MODIFIED" comment shows deviation from zSprite2 and Bresenham's line // algorithm. const int x1 = startPoint.x (), y1 = startPoint.y (), x2 = endPoint.x (), y2 = endPoint.y (); // Difference of x and y values const int dx = x2 - x1; const int dy = y2 - y1; // Absolute values of differences const int ix = qAbs (dx); const int iy = qAbs (dy); // Larger of the x and y differences const int inc = ix > iy ? ix : iy; // Plot location int plotx = x1; int ploty = y1; int x = 0; int y = 0; - if (SHOULD_DRAW ()) + if (SHOULD_DRAW ()) { ret.append (QPoint (plotx, ploty)); + } for (int i = 0; i <= inc; i++) { // oldplotx is equally as valid but would look different // (but nobody will notice which one it is) const int oldploty = ploty; int plot = 0; x += ix; y += iy; if (x > inc) { plot++; x -= inc; - if (dx < 0) + if (dx < 0) { plotx--; - else + } + else { plotx++; + } } if (y > inc) { plot++; y -= inc; - if (dy < 0) + if (dy < 0) { ploty--; - else + } + else { ploty++; + } } if (plot) { if (cardinalAdjacency && plot == 2) { // MODIFIED: Every point is // horizontally or vertically adjacent to another point (if there // is more than 1 point, of course). This is in contrast to the // ordinary line algorithm which can create diagonal adjacencies. - if (SHOULD_DRAW ()) + if (SHOULD_DRAW ()) { ret.append (QPoint (plotx, oldploty)); + } } - if (SHOULD_DRAW ()) + if (SHOULD_DRAW ()) { ret.append (QPoint (plotx, ploty)); + } } } #undef SHOULD_DRAW return ret; } //--------------------------------------------------------------------- // public static void kpPainter::fillRect (kpImage *image, int x, int y, int width, int height, const kpColor &color) { kpPixmapFX::fillRect (image, x, y, width, height, color); } //--------------------------------------------------------------------- // are operating on the original image // (the original image is not passed to this function). // // = subset of the original image containing all the pixels in // // = the rectangle, relative to the painters, whose pixels we // want to change static bool ReadableImageWashRect (QPainter *rgbPainter, const QImage &image, const kpColor &colorToReplace, const QRect &imageRect, const QRect &drawRect, int processedColorSimilarity) { bool didSomething = false; qCDebug(kpLogImagelib) << "kppixmapfx.cpp:WashRect(imageRect=" << imageRect << ",drawRect=" << drawRect << ")"; // If you're going to pass painter pointers, those painters had better be // active (i.e. QPainter::begin() has been called). Q_ASSERT (!rgbPainter || rgbPainter->isActive ()); // make use of scanline coherence #define FLUSH_LINE() \ { \ if (rgbPainter) { \ if (startDrawX == x - 1) \ rgbPainter->drawPoint (startDrawX + imageRect.x (), \ y + imageRect.y ()); \ else \ rgbPainter->drawLine (startDrawX + imageRect.x (), \ y + imageRect.y (), \ x - 1 + imageRect.x (), \ y + imageRect.y ()); \ } \ didSomething = true; \ startDrawX = -1; \ } const int maxY = drawRect.bottom () - imageRect.top (); const int minX = drawRect.left () - imageRect.left (); const int maxX = drawRect.right () - imageRect.left (); for (int y = drawRect.top () - imageRect.top (); y <= maxY; y++) { int startDrawX = -1; int x; // for FLUSH_LINE() for (x = minX; x <= maxX; x++) { fprintf (stderr, "y=%i x=%i colorAtPixel=%08X colorToReplace=%08X ... ", y, x, kpPixmapFX::getColorAtPixel (image, QPoint (x, y)).toQRgb (), colorToReplace.toQRgb ()); if (kpPixmapFX::getColorAtPixel (image, QPoint (x, y)).isSimilarTo (colorToReplace, processedColorSimilarity)) { fprintf (stderr, "similar\n"); - if (startDrawX < 0) + if (startDrawX < 0) { startDrawX = x; + } } else { fprintf (stderr, "different\n"); - if (startDrawX >= 0) + if (startDrawX >= 0) { FLUSH_LINE (); + } } } - if (startDrawX >= 0) + if (startDrawX >= 0) { FLUSH_LINE (); + } } #undef FLUSH_LINE return didSomething; } //--------------------------------------------------------------------- struct WashPack { QPoint startPoint, endPoint; kpColor color; - int penWidth, penHeight; + int penWidth{}, penHeight{}; kpColor colorToReplace; - int processedColorSimilarity; + int processedColorSimilarity{}; QRect readableImageRect; QImage readableImage; }; //--------------------------------------------------------------------- static QRect Wash (kpImage *image, const QPoint &startPoint, const QPoint &endPoint, const kpColor &color, int penWidth, int penHeight, const kpColor &colorToReplace, int processedColorSimilarity, QRect (*drawFunc) (QPainter * /*rgbPainter*/, void * /*data*/)) { WashPack pack; pack.startPoint = startPoint; pack.endPoint = endPoint; pack.color = color; pack.penWidth = penWidth; pack.penHeight = penHeight; pack.colorToReplace = colorToReplace; pack.processedColorSimilarity = processedColorSimilarity; // Get the rectangle that bounds the changes and the pixmap for that // rectangle. const QRect normalizedRect = kpPainter::normalizedRect(pack.startPoint, pack.endPoint); pack.readableImageRect = kpTool::neededRect (normalizedRect, qMax (pack.penWidth, pack.penHeight)); qCDebug(kpLogImagelib) << "kppainter.cpp:Wash() startPoint=" << startPoint << " endPoint=" << endPoint << " --> normalizedRect=" << normalizedRect << " readableImageRect=" << pack.readableImageRect; pack.readableImage = kpPixmapFX::getPixmapAt (*image, pack.readableImageRect); QPainter painter(image); return (*drawFunc)(&painter, &pack); } //--------------------------------------------------------------------- void WashHelperSetup (QPainter *rgbPainter, const WashPack *pack) { // Set the drawing colors for the painters. - if (rgbPainter) + if (rgbPainter) { rgbPainter->setPen (pack->color.toQColor()); + } } //--------------------------------------------------------------------- static QRect WashLineHelper (QPainter *rgbPainter, void *data) { - WashPack *pack = static_cast (data); + auto *pack = static_cast (data); // Setup painters. ::WashHelperSetup (rgbPainter, pack); bool didSomething = false; QList points = kpPainter::interpolatePoints (pack->startPoint, pack->endPoint); for (QList ::const_iterator pit = points.constBegin (); pit != points.constEnd (); ++pit) { // OPT: This may be reading and possibly writing pixels that were // visited on a previous iteration, since the pen is usually // bigger than 1 pixel. Maybe we could use QRegion to determine // all the non-intersecting regions and only wash each region once. // // Profiling needs to be done as QRegion is known to be a CPU hog. if (::ReadableImageWashRect (rgbPainter, pack->readableImage, pack->colorToReplace, pack->readableImageRect, kpToolFlowBase::hotRectForMousePointAndBrushWidthHeight ( *pit, pack->penWidth, pack->penHeight), pack->processedColorSimilarity)) { didSomething = true; } } // TODO: Rectangle may be too big. Use QRect::united() incrementally? // Efficiency? return didSomething ? pack->readableImageRect : QRect (); } //--------------------------------------------------------------------- // public static QRect kpPainter::washLine (kpImage *image, int x1, int y1, int x2, int y2, const kpColor &color, int penWidth, int penHeight, const kpColor &colorToReplace, int processedColorSimilarity) { return ::Wash (image, QPoint (x1, y1), QPoint (x2, y2), color, penWidth, penHeight, colorToReplace, processedColorSimilarity, &::WashLineHelper); } //--------------------------------------------------------------------- static QRect WashRectHelper (QPainter *rgbPainter, void *data) { - WashPack *pack = static_cast (data); + auto *pack = static_cast (data); // Setup painters. ::WashHelperSetup (rgbPainter, pack); const QRect drawRect (pack->startPoint, pack->endPoint); bool didSomething = false; if (::ReadableImageWashRect (rgbPainter, pack->readableImage, pack->colorToReplace, pack->readableImageRect, drawRect, pack->processedColorSimilarity)) { didSomething = true; } return didSomething ? drawRect : QRect (); } //--------------------------------------------------------------------- // public static QRect kpPainter::washRect (kpImage *image, int x, int y, int width, int height, const kpColor &color, const kpColor &colorToReplace, int processedColorSimilarity) { return ::Wash (image, QPoint (x, y), QPoint (x + width - 1, y + height - 1), color, 1/*pen width*/, 1/*pen height*/, colorToReplace, processedColorSimilarity, &::WashRectHelper); } //--------------------------------------------------------------------- // public static void kpPainter::sprayPoints (kpImage *image, const QList &points, const kpColor &color, int spraycanSize) { qCDebug(kpLogImagelib) << "kpPainter::sprayPoints()"; Q_ASSERT (spraycanSize > 0); QPainter painter(image); const int radius = spraycanSize / 2; // Set the drawing colors for the painters. painter.setPen(color.toQColor()); - foreach (const QPoint &p, points) + for (const auto &p : points) { for (int i = 0; i < 10; i++) { const int dx = (KRandom::random () % spraycanSize) - radius; const int dy = (KRandom::random () % spraycanSize) - radius; // Make it look circular. // TODO: Can be done better by doing a random vector angle & length // but would sin and cos be too slow? - if ((dx * dx) + (dy * dy) > (radius * radius)) + if ((dx * dx) + (dy * dy) > (radius * radius)) { continue; + } const QPoint p2 (p.x () + dx, p.y () + dy); painter.drawPoint(p2); } } } //--------------------------------------------------------------------- diff --git a/imagelib/transforms/kpTransformAutoCrop.cpp b/imagelib/transforms/kpTransformAutoCrop.cpp index d1b34ff3..7b075da0 100644 --- a/imagelib/transforms/kpTransformAutoCrop.cpp +++ b/imagelib/transforms/kpTransformAutoCrop.cpp @@ -1,742 +1,736 @@ /* Copyright (c) 2003-2007 Clarence Dang All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ // TODO: Color Similarity is obviously useful in Autocrop but it isn't // obvious as to how to implement it. The current heuristic, // for each side, chooses an arbitrary reference color for which // all other candidate pixels in that side are tested against // for similarity. But if the reference color happens to be at // one extreme of the range of colors in that side, then pixels // at the other extreme would not be deemed similar enough. The // key is to find the median color as the reference but how do // you do this if you don't know which pixels to sample in the first // place (that's what you're trying to find)? Chicken and egg situation. // // The other heuristic that is in doubt is the use of the average // color in determining the similarity of sides (it is possible // to get vastly differently colors in both sides yet they will be // considered similar). #include "kpTransformAutoCrop.h" #include "layers/selections/image/kpAbstractImageSelection.h" #include "widgets/toolbars/kpColorToolBar.h" #include "environments/commands/kpCommandEnvironment.h" #include "commands/kpCommandHistory.h" #include "document/kpDocument.h" #include "mainWindow/kpMainWindow.h" #include "imagelib/kpPainter.h" #include "pixmapfx/kpPixmapFX.h" #include "layers/selections/image/kpRectangularImageSelection.h" #include "generic/kpSetOverrideCursorSaver.h" #include "tools/kpTool.h" #include "views/manager/kpViewManager.h" #include "kpLogCategories.h" #include #include #include //--------------------------------------------------------------------- class kpTransformAutoCropBorder { public: // WARNING: Only call the with imagePtr = 0 if you are going to use // operator= to fill it in with a valid imagePtr immediately // afterwards. kpTransformAutoCropBorder (const kpImage *imagePtr = nullptr, int processedColorSimilarity = 0); kpCommandSize::SizeType size () const; const kpImage *image () const; int processedColorSimilarity () const; QRect rect () const; int left () const; int right () const; int top () const; int bottom () const; kpColor referenceColor () const; kpColor averageColor () const; bool isSingleColor () const; // (returns true on success (even if no rect) or false on error) bool calculate (int isX, int dir); bool fillsEntireImage () const; bool exists () const; void invalidate (); private: const kpImage *m_imagePtr; int m_processedColorSimilarity; QRect m_rect; kpColor m_referenceColor; int m_redSum, m_greenSum, m_blueSum; bool m_isSingleColor; }; kpTransformAutoCropBorder::kpTransformAutoCropBorder (const kpImage *imagePtr, int processedColorSimilarity) : m_imagePtr (imagePtr), m_processedColorSimilarity (processedColorSimilarity) { invalidate (); } // public kpCommandSize::SizeType kpTransformAutoCropBorder::size () const { return sizeof (kpTransformAutoCropBorder); } // public const kpImage *kpTransformAutoCropBorder::image () const { return m_imagePtr; } // public int kpTransformAutoCropBorder::processedColorSimilarity () const { return m_processedColorSimilarity; } // public QRect kpTransformAutoCropBorder::rect () const { return m_rect; } // public int kpTransformAutoCropBorder::left () const { return m_rect.left (); } // public int kpTransformAutoCropBorder::right () const { return m_rect.right (); } // public int kpTransformAutoCropBorder::top () const { return m_rect.top (); } // public int kpTransformAutoCropBorder::bottom () const { return m_rect.bottom (); } // public kpColor kpTransformAutoCropBorder::referenceColor () const { return m_referenceColor; } // public kpColor kpTransformAutoCropBorder::averageColor () const { if (!m_rect.isValid ()) return kpColor::Invalid; if (m_referenceColor.isTransparent ()) return kpColor::Transparent; - else if (m_processedColorSimilarity == 0) + + if (m_processedColorSimilarity == 0) return m_referenceColor; - else - { - int numPixels = (m_rect.width () * m_rect.height ()); - Q_ASSERT (numPixels > 0); - return kpColor (m_redSum / numPixels, - m_greenSum / numPixels, - m_blueSum / numPixels); - } + int numPixels = (m_rect.width () * m_rect.height ()); + Q_ASSERT (numPixels > 0); + + return kpColor (m_redSum / numPixels, m_greenSum / numPixels, m_blueSum / numPixels); + } //--------------------------------------------------------------------- bool kpTransformAutoCropBorder::isSingleColor () const { return m_isSingleColor; } //--------------------------------------------------------------------- // public bool kpTransformAutoCropBorder::calculate (int isX, int dir) { qCDebug(kpLogImagelib) << "kpTransformAutoCropBorder::calculate() CALLED!"; int maxX = m_imagePtr->width () - 1; int maxY = m_imagePtr->height () - 1; QImage qimage = *m_imagePtr; Q_ASSERT (!qimage.isNull ()); // (sync both branches) if (isX) { int numCols = 0; int startX = (dir > 0) ? 0 : maxX; kpColor col = kpPixmapFX::getColorAtPixel (qimage, startX, 0); for (int x = startX; x >= 0 && x <= maxX; x += dir) { int y; for (y = 0; y <= maxY; y++) { if (!kpPixmapFX::getColorAtPixel (qimage, x, y).isSimilarTo (col, m_processedColorSimilarity)) break; } if (y <= maxY) break; else numCols++; } if (numCols) { m_rect = kpPainter::normalizedRect(QPoint(startX, 0), QPoint(startX + (numCols - 1) * dir, maxY)); m_referenceColor = col; } } else { int numRows = 0; int startY = (dir > 0) ? 0 : maxY; kpColor col = kpPixmapFX::getColorAtPixel (qimage, 0, startY); for (int y = startY; y >= 0 && y <= maxY; y += dir) { int x; for (x = 0; x <= maxX; x++) { if (!kpPixmapFX::getColorAtPixel (qimage, x, y).isSimilarTo (col, m_processedColorSimilarity)) break; } if (x <= maxX) break; else numRows++; } if (numRows) { m_rect = kpPainter::normalizedRect(QPoint(0, startY), QPoint(maxX, startY + (numRows - 1) * dir)); m_referenceColor = col; } } if (m_rect.isValid ()) { m_isSingleColor = true; if (m_processedColorSimilarity != 0) { for (int y = m_rect.top (); y <= m_rect.bottom (); y++) { for (int x = m_rect.left (); x <= m_rect.right (); x++) { kpColor colAtPixel = kpPixmapFX::getColorAtPixel (qimage, x, y); if (m_isSingleColor && colAtPixel != m_referenceColor) m_isSingleColor = false; m_redSum += colAtPixel.red (); m_greenSum += colAtPixel.green (); m_blueSum += colAtPixel.blue (); } } } } return true; } // public bool kpTransformAutoCropBorder::fillsEntireImage () const { return (m_rect == m_imagePtr->rect ()); } // public bool kpTransformAutoCropBorder::exists () const { // (will use in an addition so make sure returns 1 or 0) return (m_rect.isValid () ? 1 : 0); } // public void kpTransformAutoCropBorder::invalidate () { m_rect = QRect (); m_referenceColor = kpColor::Invalid; m_redSum = m_greenSum = m_blueSum = 0; m_isSingleColor = false; } struct kpTransformAutoCropCommandPrivate { - bool actOnSelection; + bool actOnSelection{}; kpTransformAutoCropBorder leftBorder, rightBorder, topBorder, botBorder; - kpImage *leftImage, *rightImage, *topImage, *botImage; + kpImage *leftImage{}, *rightImage{}, *topImage{}, *botImage{}; QRect contentsRect; - int oldWidth, oldHeight; - kpAbstractImageSelection *oldSelectionPtr; + int oldWidth{}, oldHeight{}; + kpAbstractImageSelection *oldSelectionPtr{}; }; // REFACTOR: Move to /commands/ kpTransformAutoCropCommand::kpTransformAutoCropCommand (bool actOnSelection, const kpTransformAutoCropBorder &leftBorder, const kpTransformAutoCropBorder &rightBorder, const kpTransformAutoCropBorder &topBorder, const kpTransformAutoCropBorder &botBorder, kpCommandEnvironment *environ) : kpNamedCommand(text(actOnSelection, DontShowAccel), environ), d (new kpTransformAutoCropCommandPrivate ()) { d->actOnSelection = actOnSelection; d->leftBorder = leftBorder; d->rightBorder = rightBorder; d->topBorder = topBorder; d->botBorder = botBorder; d->leftImage = nullptr; d->rightImage = nullptr; d->topImage = nullptr; d->botImage = nullptr; kpDocument *doc = document (); Q_ASSERT (doc); d->oldWidth = doc->width (d->actOnSelection); d->oldHeight = doc->height (d->actOnSelection); d->oldSelectionPtr = nullptr; } //--------------------------------------------------------------------- kpTransformAutoCropCommand::~kpTransformAutoCropCommand () { deleteUndoImages (); delete d->oldSelectionPtr; delete d; } //--------------------------------------------------------------------- // public static QString kpTransformAutoCropCommand::text(bool actOnSelection, int options) { if (actOnSelection) { - if (options & kpTransformAutoCropCommand::ShowAccel) + if (options & kpTransformAutoCropCommand::ShowAccel) { return i18n ("Remove Internal B&order"); - else - return i18n ("Remove Internal Border"); - } - else - { - if (options & kpTransformAutoCropCommand::ShowAccel) - return i18n ("Autocr&op"); - else - return i18n ("Autocrop"); + } + + return i18n ("Remove Internal Border"); } + + if (options & kpTransformAutoCropCommand::ShowAccel) + return i18n ("Autocr&op"); + + return i18n ("Autocrop"); } //--------------------------------------------------------------------- // public virtual [base kpCommand] kpCommandSize::SizeType kpTransformAutoCropCommand::size () const { return d->leftBorder.size () + d->rightBorder.size () + d->topBorder.size () + d->botBorder.size () + ImageSize (d->leftImage) + ImageSize (d->rightImage) + ImageSize (d->topImage) + ImageSize (d->botImage) + SelectionSize (d->oldSelectionPtr); } //--------------------------------------------------------------------- // private void kpTransformAutoCropCommand::getUndoImage (const kpTransformAutoCropBorder &border, kpImage **image) { kpDocument *doc = document (); Q_ASSERT (doc); qCDebug(kpLogImagelib) << "kpTransformAutoCropCommand::getUndoImage()"; qCDebug(kpLogImagelib) << "\timage=" << image << " border: rect=" << border.rect () - << " isSingleColor=" << border.isSingleColor () - << endl; + << " isSingleColor=" << border.isSingleColor (); if (image && border.exists () && !border.isSingleColor ()) { if (*image) { qCDebug(kpLogImagelib) << "\talready have *image - delete it"; delete *image; } *image = new kpImage ( kpPixmapFX::getPixmapAt (doc->image (d->actOnSelection), border.rect ())); } } // private void kpTransformAutoCropCommand::getUndoImages () { getUndoImage (d->leftBorder, &d->leftImage); getUndoImage (d->rightBorder, &d->rightImage); getUndoImage (d->topBorder, &d->topImage); getUndoImage (d->botBorder, &d->botImage); } // private void kpTransformAutoCropCommand::deleteUndoImages () { qCDebug(kpLogImagelib) << "kpTransformAutoCropCommand::deleteUndoImages()"; delete d->leftImage; d->leftImage = nullptr; delete d->rightImage; d->rightImage = nullptr; delete d->topImage; d->topImage = nullptr; delete d->botImage; d->botImage = nullptr; } // public virtual [base kpCommand] void kpTransformAutoCropCommand::execute () { - if (!d->contentsRect.isValid ()) + if (!d->contentsRect.isValid ()) { d->contentsRect = contentsRect (); + } getUndoImages (); kpDocument *doc = document (); Q_ASSERT (doc); kpImage imageWithoutBorder = kpTool::neededPixmap (doc->image (d->actOnSelection), d->contentsRect); - if (!d->actOnSelection) + if (!d->actOnSelection) { doc->setImage (imageWithoutBorder); - else - { + } + else { d->oldSelectionPtr = doc->imageSelection ()->clone (); d->oldSelectionPtr->setBaseImage (kpImage ()); // d->contentsRect is relative to the top of the sel // while sel is relative to the top of the doc QRect rect = d->contentsRect; rect.translate (d->oldSelectionPtr->x (), d->oldSelectionPtr->y ()); kpRectangularImageSelection sel ( rect, imageWithoutBorder, d->oldSelectionPtr->transparency ()); doc->setSelection (sel); environ ()->somethingBelowTheCursorChanged (); } } // public virtual [base kpCommand] void kpTransformAutoCropCommand::unexecute () { qCDebug(kpLogImagelib) << "kpTransformAutoCropCommand::unexecute()"; kpDocument *doc = document (); Q_ASSERT (doc); kpImage image (d->oldWidth, d->oldHeight, QImage::Format_ARGB32_Premultiplied); // restore the position of the center image kpPixmapFX::setPixmapAt (&image, d->contentsRect, doc->image (d->actOnSelection)); // draw the borders const kpTransformAutoCropBorder *borders [] = { &d->leftBorder, &d->rightBorder, &d->topBorder, &d->botBorder, nullptr }; const kpImage *images [] = { d->leftImage, d->rightImage, d->topImage, d->botImage, nullptr }; const kpImage **p = images; for (const kpTransformAutoCropBorder **b = borders; *b; b++, p++) { - if (!(*b)->exists ()) + if (!(*b)->exists ()) { continue; + } if ((*b)->isSingleColor ()) { kpColor col = (*b)->referenceColor (); #if DEBUG_KP_TOOL_AUTO_CROP && 1 qCDebug(kpLogImagelib) << "\tdrawing border " << (*b)->rect () - << " rgb=" << (int *) col.toQRgb () /* %X hack */ << endl; + << " rgb=" << (int *) col.toQRgb () /* %X hack */; #endif const QRect r = (*b)->rect (); kpPainter::fillRect (&image, r.x (), r.y (), r.width (), r.height (), col); } else { #if DEBUG_KP_TOOL_AUTO_CROP && 1 qCDebug(kpLogImagelib) << "\trestoring border image " << (*b)->rect (); #endif if (*p) { // REFACTOR: Add equivalent method to kpPainter and use. kpPixmapFX::setPixmapAt (&image, (*b)->rect (), **p); } } } - if (!d->actOnSelection) + if (!d->actOnSelection) { doc->setImage (image); + } else { d->oldSelectionPtr->setBaseImage (image); doc->setSelection (*d->oldSelectionPtr); delete d->oldSelectionPtr; d->oldSelectionPtr = nullptr; environ ()->somethingBelowTheCursorChanged (); } deleteUndoImages (); } // private QRect kpTransformAutoCropCommand::contentsRect () const { const kpImage image = document ()->image (d->actOnSelection); QPoint topLeft (d->leftBorder.exists () ? d->leftBorder.rect ().right () + 1 : 0, d->topBorder.exists () ? d->topBorder.rect ().bottom () + 1 : 0); QPoint botRight (d->rightBorder.exists () ? d->rightBorder.rect ().left () - 1 : image.width () - 1, d->botBorder.exists () ? d->botBorder.rect ().top () - 1 : image.height () - 1); - return QRect (topLeft, botRight); + return {topLeft, botRight}; } static void ShowNothingToAutocropMessage (kpMainWindow *mainWindow, bool actOnSelection) { kpSetOverrideCursorSaver cursorSaver (Qt::ArrowCursor); if (actOnSelection) { KMessageBox::information (mainWindow, i18n ("KolourPaint cannot remove the selection's internal border as it" " could not be located."), i18nc ("@title:window", "Cannot Remove Internal Border"), "NothingToAutoCrop"); } else { KMessageBox::information (mainWindow, i18n ("KolourPaint cannot automatically crop the image as its" " border could not be located."), i18nc ("@title:window", "Cannot Autocrop"), "NothingToAutoCrop"); } } bool kpTransformAutoCrop (kpMainWindow *mainWindow) { qCDebug(kpLogImagelib) << "kpTransformAutoCrop() CALLED!"; Q_ASSERT (mainWindow); kpDocument *doc = mainWindow->document (); Q_ASSERT (doc); // OPT: if already pulled selection image, no need to do it again here kpImage image = doc->selection () ? doc->getSelectedBaseImage () : doc->image (); Q_ASSERT (!image.isNull ()); kpViewManager *vm = mainWindow->viewManager (); Q_ASSERT (vm); int processedColorSimilarity = mainWindow->colorToolBar ()->processedColorSimilarity (); kpTransformAutoCropBorder leftBorder (&image, processedColorSimilarity), rightBorder (&image, processedColorSimilarity), topBorder (&image, processedColorSimilarity), botBorder (&image, processedColorSimilarity); kpSetOverrideCursorSaver cursorSaver (Qt::WaitCursor); mainWindow->colorToolBar ()->flashColorSimilarityToolBarItem (); // TODO: With Colour Similarity, a lot of weird (and wonderful) things can // happen resulting in a huge number of code paths. Needs refactoring // and regression testing. // // TODO: e.g. When the top fills entire rect but bot doesn't we could // invalidate top and continue autocrop. int numRegions = 0; if (!leftBorder.calculate (true/*x*/, +1/*going right*/) || leftBorder.fillsEntireImage () || !rightBorder.calculate (true/*x*/, -1/*going left*/) || rightBorder.fillsEntireImage () || !topBorder.calculate (false/*y*/, +1/*going down*/) || topBorder.fillsEntireImage () || !botBorder.calculate (false/*y*/, -1/*going up*/) || botBorder.fillsEntireImage () || ((numRegions = leftBorder.exists () + rightBorder.exists () + topBorder.exists () + botBorder.exists ()) == 0)) { #if DEBUG_KP_TOOL_AUTO_CROP qCDebug(kpLogImagelib) << "\tcan't find border; leftBorder.rect=" << leftBorder.rect () << " rightBorder.rect=" << rightBorder.rect () << " topBorder.rect=" << topBorder.rect () - << " botBorder.rect=" << botBorder.rect () - << endl; + << " botBorder.rect=" << botBorder.rect (); #endif ::ShowNothingToAutocropMessage (mainWindow, static_cast (doc->selection ())); return false; } qCDebug(kpLogImagelib) << "\tnumRegions=" << numRegions; qCDebug(kpLogImagelib) << "\t\tleft=" << leftBorder.rect () - << " refCol=" << (leftBorder.exists () ? (int *) leftBorder.referenceColor ().toQRgb () : 0) - << " avgCol=" << (leftBorder.exists () ? (int *) leftBorder.averageColor ().toQRgb () : 0) - << endl; + << " refCol=" << (leftBorder.exists () ? (int *) leftBorder.referenceColor ().toQRgb () : nullptr) + << " avgCol=" << (leftBorder.exists () ? (int *) leftBorder.averageColor ().toQRgb () : nullptr); qCDebug(kpLogImagelib) << "\t\tright=" << rightBorder.rect () - << " refCol=" << (rightBorder.exists () ? (int *) rightBorder.referenceColor ().toQRgb () : 0) - << " avgCol=" << (rightBorder.exists () ? (int *) rightBorder.averageColor ().toQRgb () : 0) - << endl; + << " refCol=" << (rightBorder.exists () ? (int *) rightBorder.referenceColor ().toQRgb () : nullptr) + << " avgCol=" << (rightBorder.exists () ? (int *) rightBorder.averageColor ().toQRgb () : nullptr); qCDebug(kpLogImagelib) << "\t\ttop=" << topBorder.rect () - << " refCol=" << (topBorder.exists () ? (int *) topBorder.referenceColor ().toQRgb () : 0) - << " avgCol=" << (topBorder.exists () ? (int *) topBorder.averageColor ().toQRgb () : 0) - << endl; + << " refCol=" << (topBorder.exists () ? (int *) topBorder.referenceColor ().toQRgb () : nullptr) + << " avgCol=" << (topBorder.exists () ? (int *) topBorder.averageColor ().toQRgb () : nullptr); qCDebug(kpLogImagelib) << "\t\tbot=" << botBorder.rect () - << " refCol=" << (botBorder.exists () ? (int *) botBorder.referenceColor ().toQRgb () : 0) - << " avgCol=" << (botBorder.exists () ? (int *) botBorder.averageColor ().toQRgb () : 0) - << endl; + << " refCol=" << (botBorder.exists () ? (int *) botBorder.referenceColor ().toQRgb () : nullptr) + << " avgCol=" << (botBorder.exists () ? (int *) botBorder.averageColor ().toQRgb () : nullptr); // In case e.g. the user pastes a solid, coloured-in rectangle, // we favor killing the bottom and right regions // (these regions probably contain the unwanted whitespace due // to the doc being bigger than the pasted selection to start with). // // We also kill if they kiss or even overlap. if (leftBorder.exists () && rightBorder.exists ()) { const kpColor leftCol = leftBorder.averageColor (); const kpColor rightCol = rightBorder.averageColor (); if ((numRegions == 2 && !leftCol.isSimilarTo (rightCol, processedColorSimilarity)) || leftBorder.right () >= rightBorder.left () - 1) // kissing or overlapping { qCDebug(kpLogImagelib) << "\tignoring left border"; leftBorder.invalidate (); } } if (topBorder.exists () && botBorder.exists ()) { const kpColor topCol = topBorder.averageColor (); const kpColor botCol = botBorder.averageColor (); if ((numRegions == 2 && !topCol.isSimilarTo (botCol, processedColorSimilarity)) || topBorder.bottom () >= botBorder.top () - 1) // kissing or overlapping { qCDebug(kpLogImagelib) << "\tignoring top border"; topBorder.invalidate (); } } mainWindow->addImageOrSelectionCommand ( new kpTransformAutoCropCommand (static_cast (doc->selection ()), leftBorder, rightBorder, topBorder, botBorder, mainWindow->commandEnvironment ())); return true; } diff --git a/imagelib/transforms/kpTransformCrop.cpp b/imagelib/transforms/kpTransformCrop.cpp index b837e07c..34d1011e 100644 --- a/imagelib/transforms/kpTransformCrop.cpp +++ b/imagelib/transforms/kpTransformCrop.cpp @@ -1,76 +1,77 @@ /* Copyright (c) 2003-2007 Clarence Dang All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #define DEBUG_KP_TOOL_CROP 0 #include "kpTransformCrop.h" #include "kpTransformCropPrivate.h" #include "layers/selections/image/kpAbstractImageSelection.h" #include "layers/selections/kpAbstractSelection.h" #include "document/kpDocument.h" #include "mainWindow/kpMainWindow.h" #include "layers/selections/text/kpTextSelection.h" #include "commands/imagelib/transforms/kpTransformResizeScaleCommand.h" #include void kpTransformCrop (kpMainWindow *mainWindow) { kpDocument *doc = mainWindow->document (); Q_ASSERT (doc); kpAbstractSelection *sel = doc->selection (); Q_ASSERT (sel); kpCommand *resizeDocCommand = new kpTransformResizeScaleCommand ( false/*act on doc, not sel*/, sel->width (), sel->height (), kpTransformResizeScaleCommand::Resize, mainWindow->commandEnvironment ()); - kpTextSelection *textSel = - dynamic_cast (sel); - kpAbstractImageSelection *imageSel = - dynamic_cast (sel); + auto *textSel = dynamic_cast (sel); + auto *imageSel = dynamic_cast (sel); // It's either a text selection or an image selection, but cannot be // neither or both. Q_ASSERT (!!textSel != !!imageSel); - if (textSel) + if (textSel) { ::kpTransformCrop_TextSelection (mainWindow, i18n ("Set as Image"), resizeDocCommand); - else if (imageSel) + } + else if (imageSel) { ::kpTransformCrop_ImageSelection (mainWindow, i18n ("Set as Image"), resizeDocCommand); - else + } + else { Q_ASSERT (!"unreachable"); + } } diff --git a/imagelib/transforms/kpTransformCrop_ImageSelection.cpp b/imagelib/transforms/kpTransformCrop_ImageSelection.cpp index 31229d26..e6cb0dda 100644 --- a/imagelib/transforms/kpTransformCrop_ImageSelection.cpp +++ b/imagelib/transforms/kpTransformCrop_ImageSelection.cpp @@ -1,241 +1,238 @@ /* Copyright (c) 2003-2007 Clarence Dang All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include "kpTransformCrop.h" #include "kpTransformCropPrivate.h" #include "layers/selections/image/kpAbstractImageSelection.h" #include "environments/commands/kpCommandEnvironment.h" #include "commands/kpCommandHistory.h" #include "document/kpDocument.h" #include "imagelib/kpImage.h" #include "commands/kpMacroCommand.h" #include "mainWindow/kpMainWindow.h" #include "pixmapfx/kpPixmapFX.h" #include "commands/tools/selection/kpToolSelectionCreateCommand.h" #include "views/manager/kpViewManager.h" #include "kpLogCategories.h" // See the "image selection" part of the kpTransformCrop() API Doc. // // REFACTOR: Move into commands/ class SetDocumentToSelectionImageCommand : public kpCommand { public: SetDocumentToSelectionImageCommand (kpCommandEnvironment *environ); ~SetDocumentToSelectionImageCommand () override; /* (uninteresting child of macro cmd) */ QString name () const override { return QString(); } kpCommandSize::SizeType size () const override { return ImageSize (m_oldImage) + SelectionSize (m_fromSelectionPtr) + ImageSize (m_imageIfFromSelectionDoesntHaveOne); } // ASSUMPTION: Document has been resized to be the same size as the // selection. void execute () override; void unexecute () override; protected: kpColor m_backgroundColor; kpImage m_oldImage; kpAbstractImageSelection *m_fromSelectionPtr; kpImage m_imageIfFromSelectionDoesntHaveOne; }; SetDocumentToSelectionImageCommand::SetDocumentToSelectionImageCommand (kpCommandEnvironment *environ) : kpCommand (environ), m_backgroundColor (environ->backgroundColor ()), m_fromSelectionPtr ( dynamic_cast ( environ->document ()->selection ()->clone ())) { Q_ASSERT (m_fromSelectionPtr); if ( m_fromSelectionPtr ) // make coverity happy { m_imageIfFromSelectionDoesntHaveOne = m_fromSelectionPtr->hasContent () ? kpImage () : document ()->getSelectedBaseImage (); } } //--------------------------------------------------------------------- SetDocumentToSelectionImageCommand::~SetDocumentToSelectionImageCommand () { delete m_fromSelectionPtr; } //--------------------------------------------------------------------- // public virtual [base kpCommand] void SetDocumentToSelectionImageCommand::execute () { qCDebug(kpLogImagelib) << "SetDocumentToSelectionImageCommand::execute()"; viewManager ()->setQueueUpdates (); { // kpTransformCrop_ImageSelection's has // executed, resizing the document to be the size of the selection // bounding rectangle. Q_ASSERT (document ()->width () == m_fromSelectionPtr->width ()); Q_ASSERT (document ()->height () == m_fromSelectionPtr->height ()); m_oldImage = document ()->image (); // // e.g. original elliptical selection: // // t/---\ T = original transparent selection pixel // | TT | t = outside the selection region // t\__/t [every other character] = original opaque selection pixel // // Afterwards, the _document_ image becomes: // // b/---\ T = [unchanged] // | TT | b = background color // b\__/b [every other character] = [unchanged] // // The selection is deleted. // // TODO: Do not introduce a mask if the result will not contain // any transparent pixels. // QImage newDocImage(document()->width(), document()->height(), QImage::Format_ARGB32_Premultiplied); newDocImage.fill(m_backgroundColor.toQRgb()); qCDebug(kpLogImagelib) << "\tsel: rect=" << m_fromSelectionPtr->boundingRect () - << " pm=" << m_fromSelectionPtr->hasContent () - << endl; + << " pm=" << m_fromSelectionPtr->hasContent (); QImage setTransparentImage; if (m_fromSelectionPtr->hasContent ()) { setTransparentImage = m_fromSelectionPtr->transparentImage (); qCDebug(kpLogImagelib) << "\thave pixmap; rect=" - << setTransparentImage.rect () - << endl; + << setTransparentImage.rect (); } else { setTransparentImage = m_imageIfFromSelectionDoesntHaveOne; qCDebug(kpLogImagelib) << "\tno pixmap in sel - get it; rect=" - << setTransparentImage.rect () - << endl; + << setTransparentImage.rect (); } kpPixmapFX::paintPixmapAt (&newDocImage, QPoint (0, 0), setTransparentImage); document ()->setImageAt (newDocImage, QPoint (0, 0)); document ()->selectionDelete (); environ ()->somethingBelowTheCursorChanged (); } viewManager ()->restoreQueueUpdates (); } //--------------------------------------------------------------------- // public virtual [base kpCommand] void SetDocumentToSelectionImageCommand::unexecute () { qCDebug(kpLogImagelib) << "SetDocumentToSelectionImageCommand::unexecute()"; viewManager ()->setQueueUpdates (); { document ()->setImageAt (m_oldImage, QPoint (0, 0)); m_oldImage = kpImage (); qCDebug(kpLogImagelib) << "\tsel: rect=" << m_fromSelectionPtr->boundingRect () - << " pm=" << m_fromSelectionPtr->hasContent () - << endl; + << " pm=" << m_fromSelectionPtr->hasContent (); document ()->setSelection (*m_fromSelectionPtr); environ ()->somethingBelowTheCursorChanged (); } viewManager ()->restoreQueueUpdates (); } //--------------------------------------------------------------------- void kpTransformCrop_ImageSelection (kpMainWindow *mainWindow, const QString &commandName, kpCommand *resizeDocCommand) { // Save starting selection, minus the border. - kpAbstractImageSelection *borderImageSel = - dynamic_cast ( + auto *borderImageSel = dynamic_cast ( mainWindow->document ()->selection ()->clone ()); + Q_ASSERT (borderImageSel); - if ( !borderImageSel ) // make coverity happy - return; + if ( !borderImageSel ) { // make coverity happy + return; + } // (only interested in border) borderImageSel->deleteContent (); borderImageSel->moveTo (QPoint (0, 0)); - kpCommandEnvironment *environ = mainWindow->commandEnvironment (); - kpMacroCommand *macroCmd = new kpMacroCommand (commandName, environ); + auto *environ = mainWindow->commandEnvironment (); + auto *macroCmd = new kpMacroCommand (commandName, environ); // (must resize doc _before_ SetDocumentToSelectionImageCommand in case // doc needs to gets bigger - else selection image may not fit) macroCmd->addCommand (resizeDocCommand); qCDebug(kpLogImagelib) << "\tis pixmap sel"; qCDebug(kpLogImagelib) << "\tcreating SetImage cmd"; macroCmd->addCommand (new SetDocumentToSelectionImageCommand (environ)); mainWindow->addImageOrSelectionCommand ( macroCmd, true/*add create cmd*/, false/*don't add pull cmd*/); // Add selection border back for convenience. mainWindow->commandHistory ()->addCommand ( new kpToolSelectionCreateCommand ( i18n ("Selection: Create"), *borderImageSel, mainWindow->commandEnvironment ())); delete borderImageSel; } diff --git a/imagelib/transforms/kpTransformCrop_TextSelection.cpp b/imagelib/transforms/kpTransformCrop_TextSelection.cpp index b0bc8558..f3f88931 100644 --- a/imagelib/transforms/kpTransformCrop_TextSelection.cpp +++ b/imagelib/transforms/kpTransformCrop_TextSelection.cpp @@ -1,73 +1,73 @@ /* Copyright (c) 2003-2007 Clarence Dang All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #define DEBUG_KP_TOOL_CROP 0 #include "kpTransformCrop.h" #include "kpTransformCropPrivate.h" #include "commands/imagelib/effects/kpEffectClearCommand.h" #include "commands/kpMacroCommand.h" #include "mainWindow/kpMainWindow.h" #include "commands/tools/selection/kpToolSelectionMoveCommand.h" #include "kpLogCategories.h" void kpTransformCrop_TextSelection (kpMainWindow *mainWindow, const QString &commandName, kpCommand *resizeDocCommand) { kpCommandEnvironment *environ = mainWindow->commandEnvironment (); - kpMacroCommand *macroCmd = new kpMacroCommand (commandName, environ); + auto *macroCmd = new kpMacroCommand (commandName, environ); macroCmd->addCommand (resizeDocCommand); qCDebug(kpLogImagelib) << "\tisText"; qCDebug(kpLogImagelib) << "\tclearing doc with trans cmd"; macroCmd->addCommand ( new kpEffectClearCommand ( false/*act on doc*/, kpColor::Transparent, environ)); qCDebug(kpLogImagelib) << "\tmoving sel to (0,0) cmd"; kpToolSelectionMoveCommand *moveCmd = new kpToolSelectionMoveCommand ( QString()/*uninteresting child of macro cmd*/, environ); moveCmd->moveTo (QPoint (0, 0), true/*move on exec, not now*/); moveCmd->finalize (); macroCmd->addCommand (moveCmd); mainWindow->addImageOrSelectionCommand ( macroCmd, true/*add create cmd*/, true/*add create content cmd*/); } diff --git a/kpThumbnail.cpp b/kpThumbnail.cpp index a5468129..206d0eef 100644 --- a/kpThumbnail.cpp +++ b/kpThumbnail.cpp @@ -1,180 +1,183 @@ /* Copyright (c) 2003-2007 Clarence Dang All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #define DEBUG_KP_THUMBNAIL 0 #include "kpThumbnail.h" #include "kpDefs.h" #include "document/kpDocument.h" #include "mainWindow/kpMainWindow.h" #include "views/kpThumbnailView.h" #include "tools/kpTool.h" #include "kpLogCategories.h" #include #include #include struct kpThumbnailPrivate { kpMainWindow *mainWindow; kpThumbnailView *view; QHBoxLayout *lay; }; kpThumbnail::kpThumbnail (kpMainWindow *parent) : kpSubWindow (parent), d (new kpThumbnailPrivate ()) { Q_ASSERT (parent); d->mainWindow = parent; d->view = nullptr; d->lay = new QHBoxLayout (this); setMinimumSize (64, 64); updateCaption (); } kpThumbnail::~kpThumbnail () { delete d; } // public kpThumbnailView *kpThumbnail::view () const { return d->view; } // public void kpThumbnail::setView (kpThumbnailView *view) { #if DEBUG_KP_THUMBNAIL qCDebug(kpLogMisc) << "kpThumbnail::setView(" << view << ")"; #endif - if (d->view == view) + if (d->view == view) { return; + } if (d->view) { disconnect (d->view, &kpThumbnailView::destroyed, this, &kpThumbnail::slotViewDestroyed); disconnect (d->view, &kpThumbnailView::zoomLevelChanged, this, &kpThumbnail::updateCaption); d->lay->removeWidget (d->view); } d->view = view; if (d->view) { connect (d->view, &kpThumbnailView::destroyed, this, &kpThumbnail::slotViewDestroyed); connect (d->view, &kpThumbnailView::zoomLevelChanged, this, &kpThumbnail::updateCaption); Q_ASSERT (d->view->parent () == this); d->lay->addWidget (d->view, Qt::AlignCenter); d->view->show (); } updateCaption (); } // public slot void kpThumbnail::updateCaption () { setWindowTitle (view () ? view ()->caption () : i18nc ("@title:window", "Thumbnail")); } // protected slot void kpThumbnail::slotViewDestroyed () { #if DEBUG_KP_THUMBNAIL qCDebug(kpLogMisc) << "kpThumbnail::slotViewDestroyed()"; #endif d->view = nullptr; updateCaption (); } // protected virtual [base QWidget] void kpThumbnail::resizeEvent (QResizeEvent *e) { #if DEBUG_KP_THUMBNAIL qCDebug(kpLogMisc) << "kpThumbnail::resizeEvent(" << width () - << "," << height () << ")" << endl; + << "," << height () << ")"; #endif QWidget::resizeEvent (e); // updateVariableZoom (); TODO: is below a good idea since this commented out? if (d->mainWindow) { d->mainWindow->notifyThumbnailGeometryChanged (); - if (d->mainWindow->tool ()) + if (d->mainWindow->tool ()) { d->mainWindow->tool ()->somethingBelowTheCursorChanged (); + } } } // protected virtual [base QWidget] void kpThumbnail::moveEvent (QMoveEvent * /*e*/) { - if (d->mainWindow) + if (d->mainWindow) { d->mainWindow->notifyThumbnailGeometryChanged (); + } } // protected virtual [base QWidget] void kpThumbnail::closeEvent (QCloseEvent *e) { QWidget::closeEvent (e); emit windowClosed (); } diff --git a/kpViewScrollableContainer.cpp b/kpViewScrollableContainer.cpp index 49f57bf4..6ec7698f 100644 --- a/kpViewScrollableContainer.cpp +++ b/kpViewScrollableContainer.cpp @@ -1,1179 +1,1208 @@ /* Copyright (c) 2003-2007 Clarence Dang Copyright (c) 2011 Martin Koller All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #define DEBUG_KP_VIEW_SCROLLABLE_CONTAINER 0 #include "kpViewScrollableContainer.h" #include #include #include #include #include #include #include #include #include "kpLogCategories.h" #include #include "kpDefs.h" #include "pixmapfx/kpPixmapFX.h" #include "views/kpView.h" #include "generic/kpWidgetMapper.h" //--------------------------------------------------------------------- // (Pulled from out of Thurston's hat) static const int DragScrollLeftTopMargin = 0; static const int DragScrollRightBottomMargin = 16; // scrollbarish static const int DragScrollInterval = 150; static const int DragScrollInitialInterval = DragScrollInterval * 2; static const int DragScrollNumPixels = 10; static const int DragDistanceFromRectMaxFor1stMultiplier = 50; static const int DragDistanceFromRectMaxFor2ndMultiplier = 100; //--------------------------------------------------------------------- //--------------------------------------------------------------------- // a transparent widget above all others in the viewport used only while resizing the document // to be able to show the resize lines above everything else class kpOverlay : public QWidget { public: kpOverlay(QWidget *parent, kpViewScrollableContainer *container) : QWidget(parent), m_container(container) { } void paintEvent(QPaintEvent *) override { m_container->drawResizeLines(); } private: kpViewScrollableContainer *m_container; }; //--------------------------------------------------------------------- const int kpGrip::Size = 5; //--------------------------------------------------------------------- kpGrip::kpGrip (GripType type, QWidget *parent) : QWidget(parent), m_type (type), m_startPoint (KP_INVALID_POINT), m_currentPoint (KP_INVALID_POINT), m_shouldReleaseMouseButtons (false) { setCursor(cursorForType(m_type)); setMouseTracking(true); // mouseMoveEvent's even when no mousebtn down setAutoFillBackground(true); setBackgroundRole(QPalette::Highlight); setFixedSize(kpGrip::Size, kpGrip::Size); } //--------------------------------------------------------------------- // public kpGrip::GripType kpGrip::type () const { return m_type; } //--------------------------------------------------------------------- // public static QCursor kpGrip::cursorForType (GripType type) { switch (type) { case kpGrip::Bottom: return Qt::SizeVerCursor; case kpGrip::Right: return Qt::SizeHorCursor; case kpGrip::BottomRight: return Qt::SizeFDiagCursor; } return Qt::ArrowCursor; } //--------------------------------------------------------------------- // public bool kpGrip::containsCursor() { return isVisible() && QRect(mapToGlobal(rect().topLeft()), mapToGlobal(rect().bottomRight())).contains(QCursor::pos()); } //--------------------------------------------------------------------- // public bool kpGrip::isDrawing () const { return (m_startPoint != KP_INVALID_POINT); } //--------------------------------------------------------------------- // public QString kpGrip::haventBegunDrawUserMessage () const { return i18n ("Left drag the handle to resize the image."); } //--------------------------------------------------------------------- // public QString kpGrip::userMessage () const { return m_userMessage; } //--------------------------------------------------------------------- // public void kpGrip::setUserMessage (const QString &message) { // Don't do NOP checking here since another grip might have changed // the message so an apparent NOP for this grip is not a NOP in the // global sense (kpViewScrollableContainer::slotGripStatusMessageChanged()). m_userMessage = message; emit statusMessageChanged (message); } //--------------------------------------------------------------------- // protected void kpGrip::cancel () { #if DEBUG_KP_VIEW_SCROLLABLE_CONTAINER qCDebug(kpLogMisc) << "kpGrip::cancel()"; #endif - if (m_currentPoint == KP_INVALID_POINT) + if (m_currentPoint == KP_INVALID_POINT) { return; + } m_startPoint = KP_INVALID_POINT; m_currentPoint = KP_INVALID_POINT; setUserMessage (i18n ("Resize Image: Let go of all the mouse buttons.")); setCursor (Qt::ArrowCursor); m_shouldReleaseMouseButtons = true; releaseKeyboard (); emit cancelledDraw (); } //--------------------------------------------------------------------- // protected virtual [base QWidget] void kpGrip::keyReleaseEvent (QKeyEvent *e) { if (m_startPoint != KP_INVALID_POINT && e->key () == Qt::Key_Escape) { cancel (); } } //--------------------------------------------------------------------- // protected virtual [base QWidget] void kpGrip::mousePressEvent (QMouseEvent *e) { if (m_startPoint == KP_INVALID_POINT && (e->buttons () & Qt::MouseButtonMask) == Qt::LeftButton) { m_startPoint = e->pos (); m_currentPoint = e->pos (); emit beganDraw (); grabKeyboard (); setUserMessage (i18n ("Resize Image: Right click to cancel.")); setCursor (cursorForType (m_type)); } else { - if (m_startPoint != KP_INVALID_POINT) + if (m_startPoint != KP_INVALID_POINT) { cancel (); + } } } //--------------------------------------------------------------------- // public QPoint kpGrip::viewDeltaPoint () const { - if (m_startPoint == KP_INVALID_POINT) + if (m_startPoint == KP_INVALID_POINT) { return KP_INVALID_POINT; + } const QPoint point = mapFromGlobal (QCursor::pos ()); // TODO: this is getting out of sync with m_currentPoint - return QPoint (((m_type & kpGrip::Right) ? point.x () - m_startPoint.x () : 0), - ((m_type & kpGrip::Bottom) ? point.y () - m_startPoint.y () : 0)); + return {(m_type & kpGrip::Right) ? point.x () - m_startPoint.x () : 0, + (m_type & kpGrip::Bottom) ? point.y () - m_startPoint.y () : 0}; } //--------------------------------------------------------------------- // public void kpGrip::mouseMovedTo (const QPoint &point, bool dueToDragScroll) { - if (m_startPoint == KP_INVALID_POINT) + if (m_startPoint == KP_INVALID_POINT) { return; + } m_currentPoint = point; emit continuedDraw (((m_type & kpGrip::Right) ? point.x () - m_startPoint.x () : 0), ((m_type & kpGrip::Bottom) ? point.y () - m_startPoint.y () : 0), dueToDragScroll); } //--------------------------------------------------------------------- // protected virtual [base QWidget] void kpGrip::mouseMoveEvent (QMouseEvent *e) { #if DEBUG_KP_VIEW_SCROLLABLE_CONTAINER qCDebug(kpLogMisc) << "kpGrip::mouseMoveEvent() m_startPoint=" << m_startPoint - << " stateAfter: buttons=" << (int *) (int) e->buttons () - << endl; + << " stateAfter: buttons=" << (int *) (int) e->buttons (); #endif if (m_startPoint == KP_INVALID_POINT) { - if ((e->buttons () & Qt::MouseButtonMask) == 0) + if ((e->buttons () & Qt::MouseButtonMask) == 0) { setUserMessage (haventBegunDrawUserMessage ()); + } return; } mouseMovedTo (e->pos (), false/*not due to drag scroll*/); } //--------------------------------------------------------------------- // protected virtual [base QWidget] void kpGrip::mouseReleaseEvent (QMouseEvent *e) { #if DEBUG_KP_VIEW_SCROLLABLE_CONTAINER qCDebug(kpLogMisc) << "kpGrip::mouseReleaseEvent() m_startPoint=" << m_startPoint - << " stateAfter: buttons=" << (int *) (int) e->buttons () - << endl; + << " stateAfter: buttons=" << (int *) (int) e->buttons (); #endif if (m_startPoint != KP_INVALID_POINT) { const int dx = m_currentPoint.x () - m_startPoint.x (), dy = m_currentPoint.y () - m_startPoint.y (); m_currentPoint = KP_INVALID_POINT; m_startPoint = KP_INVALID_POINT; releaseKeyboard (); emit endedDraw ((m_type & kpGrip::Right) ? dx : 0, (m_type & kpGrip::Bottom) ? dy : 0); } if ((e->buttons () & Qt::MouseButtonMask) == 0) { m_shouldReleaseMouseButtons = false; setUserMessage(QString()); setCursor (cursorForType (m_type)); releaseKeyboard (); emit releasedAllButtons (); } } //--------------------------------------------------------------------- // protected virtual [base QWidget] void kpGrip::enterEvent (QEvent * /*e*/) { #if DEBUG_KP_VIEW_SCROLLABLE_CONTAINER qCDebug(kpLogMisc) << "kpGrip::enterEvent()" << " m_startPoint=" << m_startPoint << " shouldReleaseMouseButtons=" - << m_shouldReleaseMouseButtons << endl; + << m_shouldReleaseMouseButtons; #endif if (m_startPoint == KP_INVALID_POINT && !m_shouldReleaseMouseButtons) { #if DEBUG_KP_VIEW_SCROLLABLE_CONTAINER qCDebug(kpLogMisc) << "\tsending message"; #endif setUserMessage (haventBegunDrawUserMessage ()); } } //--------------------------------------------------------------------- // protected virtual [base QWidget] void kpGrip::leaveEvent (QEvent * /*e*/) { #if DEBUG_KP_VIEW_SCROLLABLE_CONTAINER qCDebug(kpLogMisc) << "kpGrip::leaveEvent()" << " m_startPoint=" << m_startPoint << " shouldReleaseMouseButtons=" - << m_shouldReleaseMouseButtons << endl; + << m_shouldReleaseMouseButtons; #endif if (m_startPoint == KP_INVALID_POINT && !m_shouldReleaseMouseButtons) { setUserMessage(QString()); } } //--------------------------------------------------------------------- //--------------------------------------------------------------------- //--------------------------------------------------------------------- // TODO: Are we checking for m_view == 0 often enough? Also an issue in KDE 3. kpViewScrollableContainer::kpViewScrollableContainer(QWidget *parent) : QScrollArea(parent), m_view(nullptr), m_overlay(new kpOverlay(viewport(), this)), m_docResizingGrip (nullptr), m_dragScrollTimer (new QTimer (this)), m_zoomLevel (100), m_scrollTimerRunOnce (false), m_resizeRoundedLastViewX (-1), m_resizeRoundedLastViewY (-1), m_resizeRoundedLastViewDX (0), m_resizeRoundedLastViewDY (0), m_haveMovedFromOriginalDocSize (false) { // the base widget holding the documents view plus the resize grips setWidget(new QWidget(viewport())); m_bottomGrip = new kpGrip(kpGrip::Bottom, widget()); m_rightGrip = new kpGrip(kpGrip::Right, widget()); m_bottomRightGrip = new kpGrip(kpGrip::BottomRight, widget()); m_bottomGrip->setObjectName(QLatin1String("Bottom Grip")); m_rightGrip->setObjectName(QLatin1String("Right Grip")); m_bottomRightGrip->setObjectName(QLatin1String("BottomRight Grip")); m_bottomGrip->hide (); connectGripSignals (m_bottomGrip); m_rightGrip->hide (); connectGripSignals (m_rightGrip); m_bottomRightGrip->hide (); connectGripSignals (m_bottomRightGrip); connect (horizontalScrollBar(), &QScrollBar::valueChanged, this, &kpViewScrollableContainer::slotContentsMoved); connect (verticalScrollBar(), &QScrollBar::valueChanged, this, &kpViewScrollableContainer::slotContentsMoved); connect (m_dragScrollTimer, &QTimer::timeout, this, [this]{slotDragScroll();}); m_overlay->hide(); } //--------------------------------------------------------------------- // protected void kpViewScrollableContainer::connectGripSignals (kpGrip *grip) { connect (grip, &kpGrip::beganDraw, this, &kpViewScrollableContainer::slotGripBeganDraw); connect (grip, &kpGrip::continuedDraw, this, &kpViewScrollableContainer::slotGripContinuedDraw); connect (grip, &kpGrip::cancelledDraw, this, &kpViewScrollableContainer::slotGripCancelledDraw); connect (grip, &kpGrip::endedDraw, this, &kpViewScrollableContainer::slotGripEndedDraw); connect (grip, &kpGrip::statusMessageChanged, this, &kpViewScrollableContainer::slotGripStatusMessageChanged); connect (grip, &kpGrip::releasedAllButtons, this, &kpViewScrollableContainer::recalculateStatusMessage); } //--------------------------------------------------------------------- // public QSize kpViewScrollableContainer::newDocSize () const { return newDocSize (m_resizeRoundedLastViewDX, m_resizeRoundedLastViewDY); } //--------------------------------------------------------------------- // public bool kpViewScrollableContainer::haveMovedFromOriginalDocSize () const { return m_haveMovedFromOriginalDocSize; } //--------------------------------------------------------------------- // public QString kpViewScrollableContainer::statusMessage () const { return m_gripStatusMessage; } //--------------------------------------------------------------------- // public void kpViewScrollableContainer::clearStatusMessage () { #if DEBUG_KP_VIEW_SCROLLABLE_CONTAINER && 1 qCDebug(kpLogMisc) << "kpViewScrollableContainer::clearStatusMessage()"; #endif m_bottomRightGrip->setUserMessage(QString()); m_bottomGrip->setUserMessage(QString()); m_rightGrip->setUserMessage(QString()); } //--------------------------------------------------------------------- // protected QSize kpViewScrollableContainer::newDocSize (int viewDX, int viewDY) const { - if (!m_view) - return QSize (); + if (!m_view) { + return {}; + } - if (!docResizingGrip ()) - return QSize (); + if (!docResizingGrip ()) { + return {}; + } const int docX = static_cast (m_view->transformViewToDocX (m_view->width () + viewDX)); const int docY = static_cast (m_view->transformViewToDocY (m_view->height () + viewDY)); - return QSize (qMax (1, docX), qMax (1, docY)); + return {qMax (1, docX), qMax (1, docY)}; } //--------------------------------------------------------------------- // protected void kpViewScrollableContainer::calculateDocResizingGrip () { - if (m_bottomRightGrip->isDrawing ()) + if (m_bottomRightGrip->isDrawing ()) { m_docResizingGrip = m_bottomRightGrip; - else if (m_bottomGrip->isDrawing ()) + } + else if (m_bottomGrip->isDrawing ()) { m_docResizingGrip = m_bottomGrip; - else if (m_rightGrip->isDrawing ()) + } + else if (m_rightGrip->isDrawing ()) { m_docResizingGrip = m_rightGrip; - else + } + else { m_docResizingGrip = nullptr; + } } //--------------------------------------------------------------------- // protected kpGrip *kpViewScrollableContainer::docResizingGrip () const { return m_docResizingGrip; } //--------------------------------------------------------------------- // protected int kpViewScrollableContainer::bottomResizeLineWidth () const { - if (!docResizingGrip ()) + if (!docResizingGrip ()) { return -1; + } - if (!m_view) + if (!m_view) { return -1; + } - if (docResizingGrip ()->type () & kpGrip::Bottom) + if (docResizingGrip ()->type () & kpGrip::Bottom) { return qMax (m_view->zoomLevelY () / 100, 1); - else - return 1; + } + + return 1; } //--------------------------------------------------------------------- // protected int kpViewScrollableContainer::rightResizeLineWidth () const { - if (!docResizingGrip ()) + if (!docResizingGrip ()) { return -1; + } - if (!m_view) + if (!m_view) { return -1; + } - if (docResizingGrip ()->type () & kpGrip::Right) + if (docResizingGrip ()->type () & kpGrip::Right) { return qMax (m_view->zoomLevelX () / 100, 1); - else - return 1; + } + + return 1; } //--------------------------------------------------------------------- // protected QRect kpViewScrollableContainer::bottomResizeLineRect () const { - if (m_resizeRoundedLastViewX < 0 || m_resizeRoundedLastViewY < 0) - return QRect (); + if (m_resizeRoundedLastViewX < 0 || m_resizeRoundedLastViewY < 0) { + return {}; + } QRect visibleArea = QRect(QPoint(horizontalScrollBar()->value(),verticalScrollBar()->value()), viewport()->size()); return QRect (QPoint (0, m_resizeRoundedLastViewY), QPoint (m_resizeRoundedLastViewX - 1, m_resizeRoundedLastViewY + bottomResizeLineWidth () - 1)).intersected(visibleArea); } //--------------------------------------------------------------------- // protected QRect kpViewScrollableContainer::rightResizeLineRect () const { - if (m_resizeRoundedLastViewX < 0 || m_resizeRoundedLastViewY < 0) - return QRect (); + if (m_resizeRoundedLastViewX < 0 || m_resizeRoundedLastViewY < 0) { + return {}; + } QRect visibleArea = QRect(QPoint(horizontalScrollBar()->value(),verticalScrollBar()->value()), viewport()->size()); return QRect (QPoint (m_resizeRoundedLastViewX, 0), QPoint (m_resizeRoundedLastViewX + rightResizeLineWidth () - 1, m_resizeRoundedLastViewY - 1)).intersected(visibleArea); } //--------------------------------------------------------------------- // protected QRect kpViewScrollableContainer::bottomRightResizeLineRect () const { - if (m_resizeRoundedLastViewX < 0 || m_resizeRoundedLastViewY < 0) - return QRect (); + if (m_resizeRoundedLastViewX < 0 || m_resizeRoundedLastViewY < 0) { + return {}; + } QRect visibleArea = QRect(QPoint(horizontalScrollBar()->value(),verticalScrollBar()->value()), viewport()->size()); return QRect (QPoint (m_resizeRoundedLastViewX, m_resizeRoundedLastViewY), QPoint (m_resizeRoundedLastViewX + rightResizeLineWidth () - 1, m_resizeRoundedLastViewY + bottomResizeLineWidth () - 1)).intersected(visibleArea); } //--------------------------------------------------------------------- // private QRect kpViewScrollableContainer::mapViewToViewport (const QRect &viewRect) { - if (!viewRect.isValid ()) - return QRect (); + if (!viewRect.isValid ()) { + return {}; + } QRect ret = viewRect; ret.translate (-horizontalScrollBar()->value() - viewport()->x(), -verticalScrollBar()->value() - viewport()->y()); return ret; } //--------------------------------------------------------------------- void kpViewScrollableContainer::drawResizeLines () { static const char *stipple[] = { "8 8 2 1", ". c #000000", "# c #ffffff", "....####", "....####", "....####", "....####", "####....", "####....", "####....", "####...." }; QPainter p(m_overlay); p.setBackground(QPixmap(stipple)); const QRect rightRect = rightResizeLineRect(); if ( rightRect.isValid() ) { QRect rect = mapViewToViewport(rightRect); p.setBrushOrigin(rect.x(), rect.y()); p.eraseRect(rect); } const QRect bottomRect = bottomResizeLineRect(); if ( bottomRect.isValid() ) { QRect rect = mapViewToViewport(bottomRect); p.setBrushOrigin(rect.x(), rect.y()); p.eraseRect(rect); } const QRect bottomRightRect = bottomRightResizeLineRect (); if ( bottomRightRect.isValid() ) { QRect rect = mapViewToViewport(bottomRightRect); p.setBrushOrigin(rect.x(), rect.y()); p.eraseRect(rect); } } //--------------------------------------------------------------------- // protected void kpViewScrollableContainer::updateResizeLines (int viewX, int viewY, int viewDX, int viewDY) { #if DEBUG_KP_VIEW_SCROLLABLE_CONTAINER && 0 qCDebug(kpLogMisc) << "kpViewScrollableContainer::updateResizeLines(" << viewX << "," << viewY << ")" << " oldViewX=" << m_resizeRoundedLastViewX << " oldViewY=" << m_resizeRoundedLastViewY << " viewDX=" << viewDX - << " viewDY=" << viewDY - << endl; + << " viewDY=" << viewDY; #endif if (viewX >= 0 && viewY >= 0) { m_resizeRoundedLastViewX = static_cast (m_view->transformDocToViewX (m_view->transformViewToDocX (viewX))); m_resizeRoundedLastViewY = static_cast (m_view->transformDocToViewY (m_view->transformViewToDocY (viewY))); m_resizeRoundedLastViewDX = viewDX; m_resizeRoundedLastViewDY = viewDY; } else { m_resizeRoundedLastViewX = -1; m_resizeRoundedLastViewY = -1; m_resizeRoundedLastViewDX = 0; m_resizeRoundedLastViewDY = 0; } m_overlay->update(); } //--------------------------------------------------------------------- // protected slot void kpViewScrollableContainer::slotGripBeganDraw () { - if (!m_view) + if (!m_view) { return; + } m_overlay->resize(viewport()->size()); // make it cover whole viewport m_overlay->move(viewport()->pos()); m_overlay->show(); m_overlay->raise(); // make it top-most calculateDocResizingGrip (); m_haveMovedFromOriginalDocSize = false; updateResizeLines (m_view->width (), m_view->height (), 0/*viewDX*/, 0/*viewDY*/); emit beganDocResize (); } //--------------------------------------------------------------------- // protected slot void kpViewScrollableContainer::slotGripContinuedDraw (int inViewDX, int inViewDY, bool dueToDragScroll) { int viewDX = inViewDX, viewDY = inViewDY; #if DEBUG_KP_VIEW_SCROLLABLE_CONTAINER qCDebug(kpLogMisc) << "kpViewScrollableContainer::slotGripContinuedDraw(" << viewDX << "," << viewDY << ") size=" << newDocSize (viewDX, viewDY) - << " dueToDragScroll=" << dueToDragScroll - << endl; + << " dueToDragScroll=" << dueToDragScroll; #endif - if (!m_view) + if (!m_view) { return; + } if (!dueToDragScroll && beginDragScroll(m_view->zoomLevelX ())) { const QPoint newViewDeltaPoint = docResizingGrip ()->viewDeltaPoint (); viewDX = newViewDeltaPoint.x (); viewDY = newViewDeltaPoint.y (); #if DEBUG_KP_VIEW_SCROLLABLE_CONTAINER qCDebug(kpLogMisc) << "\tdrag scrolled - new view delta point=" - << newViewDeltaPoint - << endl; + << newViewDeltaPoint; #endif } m_haveMovedFromOriginalDocSize = true; updateResizeLines (qMax (1, qMax (m_view->width () + viewDX, static_cast (m_view->transformDocToViewX (1)))), qMax (1, qMax (m_view->height () + viewDY, static_cast (m_view->transformDocToViewY (1)))), viewDX, viewDY); emit continuedDocResize (newDocSize ()); } //--------------------------------------------------------------------- // protected slot void kpViewScrollableContainer::slotGripCancelledDraw () { m_haveMovedFromOriginalDocSize = false; updateResizeLines (-1, -1, 0, 0); calculateDocResizingGrip (); emit cancelledDocResize (); endDragScroll (); m_overlay->hide(); } //--------------------------------------------------------------------- // protected slot void kpViewScrollableContainer::slotGripEndedDraw (int viewDX, int viewDY) { #if DEBUG_KP_VIEW_SCROLLABLE_CONTAINER qCDebug(kpLogMisc) << "kpViewScrollableContainer::slotGripEndedDraw(" << viewDX << "," << viewDY << ") size=" - << newDocSize (viewDX, viewDY) - << endl; + << newDocSize (viewDX, viewDY); #endif - if (!m_view) + if (!m_view) { return; + } const QSize newSize = newDocSize (viewDX, viewDY); m_haveMovedFromOriginalDocSize = false; // must erase lines before view size changes updateResizeLines (-1, -1, 0, 0); calculateDocResizingGrip (); emit endedDocResize (newSize); endDragScroll (); m_overlay->hide(); } //--------------------------------------------------------------------- // protected slot void kpViewScrollableContainer::slotGripStatusMessageChanged (const QString &string) { - if (string == m_gripStatusMessage) + if (string == m_gripStatusMessage) { return; + } m_gripStatusMessage = string; emit statusMessageChanged (string); } //--------------------------------------------------------------------- // public slot void kpViewScrollableContainer::recalculateStatusMessage () { #if DEBUG_KP_VIEW_SCROLLABLE_CONTAINER qCDebug(kpLogMisc) << "kpViewScrollabelContainer::recalculateStatusMessage()"; qCDebug(kpLogMisc) << "\tQCursor::pos=" << QCursor::pos () << " global visibleRect=" << kpWidgetMapper::toGlobal (this, - QRect(0, 0, viewport->width(), viewport->height())) - << endl; + QRect(0, 0, viewport->width(), viewport->height())); #endif // HACK: After dragging to a new size, handles move so that they are now // under the mouse pointer but no mouseMoveEvent() is generated for // any grip. This also handles the case of canceling over any // grip. // if (kpWidgetMapper::toGlobal (this, QRect(0, 0, viewport()->width(), viewport()->height())) .contains (QCursor::pos ())) { if ( m_bottomRightGrip->containsCursor() ) { m_bottomRightGrip->setUserMessage (i18n ("Left drag the handle to resize the image.")); } else if ( m_bottomGrip->containsCursor() ) { m_bottomGrip->setUserMessage (i18n ("Left drag the handle to resize the image.")); } else if ( m_rightGrip->containsCursor() ) { m_rightGrip->setUserMessage (i18n ("Left drag the handle to resize the image.")); } else { clearStatusMessage (); } } else { clearStatusMessage (); } } //--------------------------------------------------------------------- // protected slot void kpViewScrollableContainer::slotContentsMoved () { kpGrip *grip = docResizingGrip (); if (grip) { grip->mouseMovedTo (grip->mapFromGlobal (QCursor::pos ()), true/*moved due to drag scroll*/); } m_overlay->move(viewport()->pos()); m_overlay->update(); emit contentsMoved(); } //--------------------------------------------------------------------- // protected void kpViewScrollableContainer::disconnectViewSignals () { disconnect (m_view, static_cast(&kpView::sizeChanged), this, &kpViewScrollableContainer::updateGrips); disconnect (m_view, &kpView::destroyed, this, &kpViewScrollableContainer::slotViewDestroyed); } //--------------------------------------------------------------------- // protected void kpViewScrollableContainer::connectViewSignals () { connect (m_view, static_cast(&kpView::sizeChanged), this, &kpViewScrollableContainer::updateGrips); connect (m_view, &kpView::destroyed, this, &kpViewScrollableContainer::slotViewDestroyed); } //--------------------------------------------------------------------- // public kpView *kpViewScrollableContainer::view () const { return m_view; } //--------------------------------------------------------------------- // public void kpViewScrollableContainer::setView (kpView *view) { - if (m_view == view) + if (m_view == view) { return; + } if (m_view) { disconnectViewSignals (); } m_view = view; if ( m_view ) { m_view->setParent(widget()); m_view->show(); } updateGrips (); if (m_view) { connectViewSignals (); } } //--------------------------------------------------------------------- // public slot void kpViewScrollableContainer::updateGrips () { if (m_view) { widget()->resize(m_view->size() + m_bottomRightGrip->size()); // to make the grip more easily "touchable" make it as high as the view m_rightGrip->setFixedHeight(m_view->height()); m_rightGrip->move(m_view->width(), 0); // to make the grip more easily "touchable" make it as wide as the view m_bottomGrip->setFixedWidth(m_view->width()); m_bottomGrip->move(0, m_view->height ()); m_bottomRightGrip->move(m_view->width(), m_view->height()); } m_bottomGrip->setHidden (m_view == nullptr); m_rightGrip->setHidden (m_view == nullptr); m_bottomRightGrip->setHidden (m_view == nullptr); recalculateStatusMessage (); } //--------------------------------------------------------------------- // protected slot void kpViewScrollableContainer::slotViewDestroyed () { m_view = nullptr; updateGrips (); } //--------------------------------------------------------------------- // public slot bool kpViewScrollableContainer::beginDragScroll(int zoomLevel, bool *didSomething) { - if (didSomething) + if (didSomething) { *didSomething = false; + } m_zoomLevel = zoomLevel; const QPoint p = mapFromGlobal (QCursor::pos ()); bool stopDragScroll = true; bool scrolled = false; if (!noDragScrollRect ().contains (p)) { if (m_dragScrollTimer->isActive ()) { if (m_scrollTimerRunOnce) { scrolled = slotDragScroll (); } } else { m_scrollTimerRunOnce = false; m_dragScrollTimer->start (DragScrollInitialInterval); } stopDragScroll = false; } - if (stopDragScroll) + if (stopDragScroll) { m_dragScrollTimer->stop (); + } - if (didSomething) + if (didSomething) { *didSomething = scrolled; + } return scrolled; } //--------------------------------------------------------------------- // public slot bool kpViewScrollableContainer::beginDragScroll(int zoomLevel) { return beginDragScroll(zoomLevel, nullptr/*don't want scrolled notification*/); } //--------------------------------------------------------------------- // public slot bool kpViewScrollableContainer::endDragScroll () { if (m_dragScrollTimer->isActive ()) { m_dragScrollTimer->stop (); return true; } - else - { - return false; - } + + return false; } //--------------------------------------------------------------------- static int distanceFromRectToMultiplier (int dist) { - if (dist < 0) + if (dist < 0) { return 0; - else if (dist < DragDistanceFromRectMaxFor1stMultiplier) + } + + if (dist < DragDistanceFromRectMaxFor1stMultiplier) { return 1; - else if (dist < DragDistanceFromRectMaxFor2ndMultiplier) + } + + if (dist < DragDistanceFromRectMaxFor2ndMultiplier) { return 2; - else - return 4; + } + + return 4; } //--------------------------------------------------------------------- // protected slot bool kpViewScrollableContainer::slotDragScroll (bool *didSomething) { bool scrolled = false; - if (didSomething) + if (didSomething) { *didSomething = false; + } const QRect rect = noDragScrollRect (); const QPoint pos = mapFromGlobal (QCursor::pos ()); int dx = 0, dy = 0; int dxMultiplier = 0, dyMultiplier = 0; if (pos.x () < rect.left ()) { dx = -DragScrollNumPixels; dxMultiplier = distanceFromRectToMultiplier (rect.left () - pos.x ()); } else if (pos.x () > rect.right ()) { dx = +DragScrollNumPixels; dxMultiplier = distanceFromRectToMultiplier (pos.x () - rect.right ()); } if (pos.y () < rect.top ()) { dy = -DragScrollNumPixels; dyMultiplier = distanceFromRectToMultiplier (rect.top () - pos.y ()); } else if (pos.y () > rect.bottom ()) { dy = +DragScrollNumPixels; dyMultiplier = distanceFromRectToMultiplier (pos.y () - rect.bottom ()); } dx *= dxMultiplier;// * qMax (1, m_zoomLevel / 100); dy *= dyMultiplier;// * qMax (1, m_zoomLevel / 100); if (dx || dy) { const int oldContentsX = horizontalScrollBar()->value (), oldContentsY = verticalScrollBar()->value (); horizontalScrollBar()->setValue(oldContentsX + dx); verticalScrollBar()->setValue(oldContentsY + dy); scrolled = (oldContentsX != horizontalScrollBar()->value () || oldContentsY != verticalScrollBar()->value ()); if (scrolled) { QRegion region = QRect (horizontalScrollBar()->value (), verticalScrollBar()->value (), viewport()->width(), viewport()->height()); region -= QRect (oldContentsX, oldContentsY, viewport()->width(), viewport()->height()); // Repaint newly exposed region immediately to reduce tearing // of scrollView. m_view->repaint (region); } } m_dragScrollTimer->start (DragScrollInterval); m_scrollTimerRunOnce = true; - if (didSomething) + if (didSomething) { *didSomething = scrolled; + } return scrolled; } //--------------------------------------------------------------------- // protected virtual void kpViewScrollableContainer::wheelEvent (QWheelEvent *e) { e->ignore (); - if (m_view) + if (m_view) { m_view->wheelEvent (e); + } - if ( !e->isAccepted() ) + if ( !e->isAccepted() ) { QScrollArea::wheelEvent(e); + } } //--------------------------------------------------------------------------------- QRect kpViewScrollableContainer::noDragScrollRect () const { - return QRect (DragScrollLeftTopMargin, DragScrollLeftTopMargin, - width () - DragScrollLeftTopMargin - DragScrollRightBottomMargin, - height () - DragScrollLeftTopMargin - DragScrollRightBottomMargin); + return {DragScrollLeftTopMargin, DragScrollLeftTopMargin, + width () - DragScrollLeftTopMargin - DragScrollRightBottomMargin, + height () - DragScrollLeftTopMargin - DragScrollRightBottomMargin}; } //--------------------------------------------------------------------- // protected virtual [base QScrollView] void kpViewScrollableContainer::resizeEvent (QResizeEvent *e) { QScrollArea::resizeEvent (e); emit resized (); } //--------------------------------------------------------------------- diff --git a/layers/selections/image/kpAbstractImageSelection.cpp b/layers/selections/image/kpAbstractImageSelection.cpp index 6e528a61..842875ac 100644 --- a/layers/selections/image/kpAbstractImageSelection.cpp +++ b/layers/selections/image/kpAbstractImageSelection.cpp @@ -1,550 +1,557 @@ /* Copyright (c) 2003-2007 Clarence Dang All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #define DEBUG_KP_SELECTION 0 #include "layers/selections/image/kpAbstractImageSelection.h" #include #include #include "kpLogCategories.h" //--------------------------------------------------------------------- // Returns whether can be set to have . // In other words, this is the precondition for .setBaseImage(width () && baseImage.height () == sel->height ()); } //--------------------------------------------------------------------- struct kpAbstractImageSelectionPrivate { kpImage baseImage; kpImageSelectionTransparency transparency; // The mask for the image, after selection transparency (a.k.a. background // subtraction) is applied. QBitmap transparencyMaskCache; // OPT: calculate lazily i.e. on-demand only }; //--------------------------------------------------------------------- // protected kpAbstractImageSelection::kpAbstractImageSelection ( const kpImageSelectionTransparency &transparency) : kpAbstractSelection (), d (new kpAbstractImageSelectionPrivate ()) { setTransparency (transparency); } //--------------------------------------------------------------------- // protected kpAbstractImageSelection::kpAbstractImageSelection (const QRect &rect, const kpImage &baseImage, const kpImageSelectionTransparency &transparency) : kpAbstractSelection (rect), d (new kpAbstractImageSelectionPrivate ()) { // This also checks that and have compatible // relative dimensions. setBaseImage (baseImage); setTransparency (transparency); } //--------------------------------------------------------------------- // protected kpAbstractImageSelection::kpAbstractImageSelection (const QRect &rect, const kpImageSelectionTransparency &transparency) : kpAbstractSelection (rect), d (new kpAbstractImageSelectionPrivate ()) { setTransparency (transparency); } //--------------------------------------------------------------------- // protected kpAbstractImageSelection &kpAbstractImageSelection::operator= ( const kpAbstractImageSelection &rhs) { kpAbstractSelection::operator= (rhs); d->baseImage = rhs.d->baseImage; d->transparency = rhs.d->transparency; d->transparencyMaskCache = rhs.d->transparencyMaskCache; return *this; } //--------------------------------------------------------------------- // protected kpAbstractImageSelection::~kpAbstractImageSelection () { delete d; } //--------------------------------------------------------------------- // public virtual [base kpAbstractSelection] bool kpAbstractImageSelection::readFromStream (QDataStream &stream) { - if (!kpAbstractSelection::readFromStream (stream )) + if (!kpAbstractSelection::readFromStream (stream )) { return false; + } QImage qimage; stream >> qimage; qCDebug(kpLogLayers) << "\timage: w=" << qimage.width () << " h=" << qimage.height () - << " depth=" << qimage.depth () << endl; + << " depth=" << qimage.depth (); if (!qimage.isNull ()) { // Image size does not match the selection's dimensions? // This call only accesses our superclass' fields, which have already // been read in. if (!::CanSetBaseImageTo (this, qimage)) { return false; } d->baseImage = qimage; } // (was just a selection border in the clipboard, even though KolourPaint's // GUI doesn't allow you to copy such a thing into the clipboard) - else + else { d->baseImage = kpImage (); + } // TODO: Reset transparency mask? // TODO: Concrete subclass need to emit changed()? // [we can't since changed() must be called after all reading // is complete and subclasses always call this method // _before_ their reading logic] return true; } //--------------------------------------------------------------------- // public virtual [base kpAbstractSelection] void kpAbstractImageSelection::writeToStream (QDataStream &stream) const { kpAbstractSelection::writeToStream (stream); if (!d->baseImage.isNull ()) { const QImage image = d->baseImage; qCDebug(kpLogLayers) << "\twrote image rect=" << image.rect (); stream << image; } else { qCDebug(kpLogLayers) << "\twrote no image because no pixmap"; stream << QImage (); } } //--------------------------------------------------------------------- // public virtual [kpAbstractSelection] QString kpAbstractImageSelection::name () const { return i18n ("Selection"); } //--------------------------------------------------------------------- // public virtual [base kpAbstractSelection] kpCommandSize::SizeType kpAbstractImageSelection::size () const { return kpAbstractSelection::size () + kpCommandSize::ImageSize (d->baseImage) + (d->transparencyMaskCache.width() * d->transparencyMaskCache.height()) / 8; } //--------------------------------------------------------------------- // public kpCommandSize::SizeType kpAbstractImageSelection::sizeWithoutImage () const { return (size () - kpCommandSize::ImageSize (d->baseImage)); } //--------------------------------------------------------------------- // public virtual [kpAbstractSelection] int kpAbstractImageSelection::minimumWidth () const { return 1; } //--------------------------------------------------------------------- // public virtual [kpAbstractSelection] int kpAbstractImageSelection::minimumHeight () const { return 1; } //--------------------------------------------------------------------- // public virtual QBitmap kpAbstractImageSelection::shapeBitmap (bool nullForRectangular) const { (void) nullForRectangular; Q_ASSERT (boundingRect ().isValid ()); QBitmap maskBitmap (width (), height ()); maskBitmap.fill (Qt::color0/*transparent*/); { QPainter painter(&maskBitmap); painter.setPen (Qt::color1/*opaque*/); painter.setBrush (Qt::color1/*opaque*/); QPolygon points = calculatePoints (); points.translate (-x (), -y ()); // Unlike QPainter::drawRect(), this draws the points literally // without being 1 pixel wider and higher. This requires a QPen // or it will draw 1 pixel narrower and shorter. painter.drawPolygon (points, Qt::OddEvenFill); } return maskBitmap; } //--------------------------------------------------------------------- // public kpImage kpAbstractImageSelection::givenImageMaskedByShape (const kpImage &image) const { qCDebug(kpLogLayers) << "kpAbstractImageSelection::givenImageMaskedByShape() boundingRect=" << boundingRect (); Q_ASSERT (image.width () == width () && image.height () == height ()); - if (isRectangular ()) + if (isRectangular ()) { return image; + } const QRegion mRegion = shapeRegion ().translated (-topLeft ()); qCDebug(kpLogLayers) << "\tshapeRegion=" << shapeRegion () << " [rect=" << shapeRegion ().boundingRect () << "]" << " calculatePoints=" << calculatePoints () << " [rect=" << calculatePoints ().boundingRect () << "]"; kpImage retImage(width (), height (), QImage::Format_ARGB32_Premultiplied); retImage.fill(0); // transparent QPainter painter(&retImage); painter.setClipRegion(mRegion); painter.drawImage(0, 0, image); painter.end(); return retImage; } //--------------------------------------------------------------------- // public virtual [kpAbstractSelection] bool kpAbstractImageSelection::hasContent () const { return !d->baseImage.isNull (); } //--------------------------------------------------------------------- // public virtual [kpAbstractSelection] void kpAbstractImageSelection::deleteContent () { - if (!hasContent ()) + if (!hasContent ()) { return; + } setBaseImage (kpImage ()); } //--------------------------------------------------------------------- // public kpImage kpAbstractImageSelection::baseImage () const { return d->baseImage; } //--------------------------------------------------------------------- // public void kpAbstractImageSelection::setBaseImage (const kpImage &baseImage) { Q_ASSERT (::CanSetBaseImageTo (this, baseImage)); // qt doc: the image format must be set to Format_ARGB32Premultiplied or Format_ARGB32 // for the composition modes to have any effect d->baseImage = baseImage.convertToFormat(QImage::Format_ARGB32_Premultiplied); recalculateTransparencyMaskCache (); emit changed (boundingRect ()); } //--------------------------------------------------------------------- // public kpImageSelectionTransparency kpAbstractImageSelection::transparency () const { return d->transparency; } //--------------------------------------------------------------------- // public bool kpAbstractImageSelection::setTransparency ( const kpImageSelectionTransparency &transparency, bool checkTransparentPixmapChanged) { - if (d->transparency == transparency) + if (d->transparency == transparency) { return false; + } d->transparency = transparency; bool haveChanged = true; QBitmap oldTransparencyMaskCache = d->transparencyMaskCache; recalculateTransparencyMaskCache (); if ( oldTransparencyMaskCache.size() == d->transparencyMaskCache.size() ) { if (d->transparencyMaskCache.isNull ()) { qCDebug(kpLogLayers) << "\tboth old and new pixmaps are null - nothing changed"; haveChanged = false; } else if (checkTransparentPixmapChanged) { QImage oldTransparencyMaskImage = oldTransparencyMaskCache.toImage(); QImage newTransparencyMaskImage = d->transparencyMaskCache.toImage(); bool changed = false; for (int y = 0; y < oldTransparencyMaskImage.height () && !changed; y++) { for (int x = 0; x < oldTransparencyMaskImage.width () && !changed; x++) { if (kpPixmapFX::getColorAtPixel (oldTransparencyMaskImage, x, y) != kpPixmapFX::getColorAtPixel (newTransparencyMaskImage, x, y)) { qCDebug(kpLogLayers) << "\tdiffer at " << QPoint (x, y) << " old=" << kpPixmapFX::getColorAtPixel (oldTransparencyMaskImage, x, y).toQRgb () << " new=" << kpPixmapFX::getColorAtPixel (newTransparencyMaskImage, x, y).toQRgb (); changed = true; break; } } } - if (!changed) + if (!changed) { haveChanged = false; + } } } - if (haveChanged) + if (haveChanged) { emit changed (boundingRect ()); + } return haveChanged; } //--------------------------------------------------------------------- // private void kpAbstractImageSelection::recalculateTransparencyMaskCache () { qCDebug(kpLogLayers) << "kpAbstractImageSelection::recalculateTransparencyMaskCache()"; if (d->baseImage.isNull ()) { qCDebug(kpLogLayers) << "\tno image - no need for transparency mask"; d->transparencyMaskCache = QBitmap (); return; } if (d->transparency.isOpaque ()) { qCDebug(kpLogLayers) << "\topaque - no need for transparency mask"; d->transparencyMaskCache = QBitmap (); return; } d->transparencyMaskCache = QBitmap(d->baseImage.size()); QPainter transparencyMaskPainter (&d->transparencyMaskCache); bool hasTransparent = false; for (int y = 0; y < d->baseImage.height (); y++) { for (int x = 0; x < d->baseImage.width (); x++) { const kpColor pixelCol = kpPixmapFX::getColorAtPixel (d->baseImage, x, y); if (pixelCol == kpColor::Transparent || pixelCol.isSimilarTo (d->transparency.transparentColor (), d->transparency.processedColorSimilarity ())) { transparencyMaskPainter.setPen (Qt::color1/*transparent*/); hasTransparent = true; } else { transparencyMaskPainter.setPen (Qt::color0/*opaque*/); } transparencyMaskPainter.drawPoint (x, y); } } transparencyMaskPainter.end (); if (!hasTransparent) { qCDebug(kpLogLayers) << "\tcolour useless - completely opaque"; d->transparencyMaskCache = QBitmap (); return; } } //--------------------------------------------------------------------- // public kpImage kpAbstractImageSelection::transparentImage () const { kpImage image = baseImage (); if (!d->transparencyMaskCache.isNull ()) { QPainter painter(&image); painter.setCompositionMode(QPainter::CompositionMode_Clear); painter.drawPixmap(0, 0, d->transparencyMaskCache); } return image; } //--------------------------------------------------------------------- // public void kpAbstractImageSelection::fill (const kpColor &color) { QImage newImage(width(), height(), QImage::Format_ARGB32_Premultiplied); newImage.fill(color.toQRgb()); // LOTODO: Maybe disable Image/Clear menu item if transparent color if ( !color.isTransparent() ) { QPainter painter(&newImage); painter.setCompositionMode(QPainter::CompositionMode_Clear); painter.drawPixmap(0, 0, shapeBitmap()); } setBaseImage (newImage); } //--------------------------------------------------------------------- // public virtual void kpAbstractImageSelection::flip (bool horiz, bool vert) { qCDebug(kpLogLayers) << "kpAbstractImageSelection::flip(horiz=" << horiz - << ",vert=" << vert << ")" << endl; + << ",vert=" << vert << ")"; if (!d->baseImage.isNull ()) { qCDebug(kpLogLayers) << "\thave pixmap - flipping that"; d->baseImage = d->baseImage.mirrored(horiz, vert); } if (!d->transparencyMaskCache.isNull ()) { qCDebug(kpLogLayers) << "\thave transparency mask - flipping that"; QImage image = d->transparencyMaskCache.toImage().mirrored(horiz, vert); d->transparencyMaskCache = QBitmap::fromImage(image); } emit changed (boundingRect ()); } //--------------------------------------------------------------------- static void Paint (const kpAbstractImageSelection *sel, const kpImage &srcImage, QImage *destImage, const QRect &docRect) { if (!srcImage.isNull ()) { kpPixmapFX::paintPixmapAt (destImage, sel->topLeft () - docRect.topLeft (), srcImage); } } //--------------------------------------------------------------------- // public virtual [kpAbstractSelection] void kpAbstractImageSelection::paint (QImage *destImage, const QRect &docRect) const { ::Paint (this, transparentImage (), destImage, docRect); } //--------------------------------------------------------------------- // public void kpAbstractImageSelection::paintWithBaseImage (QImage *destImage, const QRect &docRect) const { ::Paint (this, baseImage (), destImage, docRect); } //--------------------------------------------------------------------- diff --git a/layers/selections/image/kpEllipticalImageSelection.cpp b/layers/selections/image/kpEllipticalImageSelection.cpp index 6a8d35fd..7d3fc5f0 100644 --- a/layers/selections/image/kpEllipticalImageSelection.cpp +++ b/layers/selections/image/kpEllipticalImageSelection.cpp @@ -1,182 +1,184 @@ /* Copyright (c) 2003-2007 Clarence Dang All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #define DEBUG_KP_SELECTION 0 #include "layers/selections/image/kpEllipticalImageSelection.h" #include #include struct kpEllipticalImageSelectionPrivate { }; kpEllipticalImageSelection::kpEllipticalImageSelection ( const kpImageSelectionTransparency &transparency) : kpAbstractImageSelection (transparency), d (new kpEllipticalImageSelectionPrivate ()) { } kpEllipticalImageSelection::kpEllipticalImageSelection (const QRect &rect, const kpImage &baseImage, const kpImageSelectionTransparency &transparency) : kpAbstractImageSelection (rect, baseImage, transparency), d (new kpEllipticalImageSelectionPrivate ()) { } kpEllipticalImageSelection::kpEllipticalImageSelection (const QRect &rect, const kpImageSelectionTransparency &transparency) : kpAbstractImageSelection (rect, transparency), d (new kpEllipticalImageSelectionPrivate ()) { } kpEllipticalImageSelection::kpEllipticalImageSelection (const kpEllipticalImageSelection &rhs) : kpAbstractImageSelection (), d (new kpEllipticalImageSelectionPrivate ()) { *this = rhs; } kpEllipticalImageSelection &kpEllipticalImageSelection::operator= ( const kpEllipticalImageSelection &rhs) { kpAbstractImageSelection::operator= (rhs); return *this; } kpEllipticalImageSelection *kpEllipticalImageSelection::clone () const { kpEllipticalImageSelection *sel = new kpEllipticalImageSelection (); *sel = *this; return sel; } kpEllipticalImageSelection::~kpEllipticalImageSelection () { delete d; } //--------------------------------------------------------------------- // public virtual [kpAbstractSelection] int kpEllipticalImageSelection::serialID () const { return SerialID; } //--------------------------------------------------------------------- // public virtual [kpAbstractSelection] bool kpEllipticalImageSelection::isRectangular () const { return false; } //--------------------------------------------------------------------- // public virtual [kpAbstractSelection] QPolygon kpEllipticalImageSelection::calculatePoints () const { Q_ASSERT (boundingRect ().isValid ()); if (width () == 1 && height () == 1) { QPolygon ret; ret.append (topLeft ()); return ret; } QPainterPath path; if (width () == 1 || height () == 1) { path.moveTo (x (), y ()); // This does not work when the width _and_ height are 1 since lineTo() // would not move at all. This is why we have a separate case for that // at the top of the method. path.lineTo (x () + width () - 1, y () + height () - 1); } else { // The adjusting is to fight QPainterPath::addEllipse() making // the ellipse 1 pixel higher and wider than specified. path.addEllipse (boundingRect ().adjusted (0, 0, -1, -1)); } const QList polygons = path.toSubpathPolygons (); Q_ASSERT (polygons.size () == 1); - const QPolygonF firstPolygonF = polygons.first (); + const QPolygonF& firstPolygonF = polygons.first (); return firstPolygonF.toPolygon (); } //--------------------------------------------------------------------- // protected virtual [kpAbstractImageSelection] QRegion kpEllipticalImageSelection::shapeRegion () const { QRegion reg(calculatePoints()); return reg; } //--------------------------------------------------------------------- // public virtual [kpAbstractSelection] bool kpEllipticalImageSelection::contains (const QPoint &point) const { - if (!boundingRect ().contains (point)) + if (!boundingRect ().contains (point)) { return false; + } return shapeRegion ().contains (point); } //--------------------------------------------------------------------- // public virtual [kpAbstractSelection] void kpEllipticalImageSelection::paintBorder (QImage *destPixmap, const QRect &docRect, bool selectionFinished) const { - if ( !boundingRect().isValid() ) + if ( !boundingRect().isValid() ) { return; + } paintPolygonalBorder (calculatePoints (), destPixmap, docRect, selectionFinished); } diff --git a/layers/selections/image/kpFreeFormImageSelection.cpp b/layers/selections/image/kpFreeFormImageSelection.cpp index ab16a01c..c000f95e 100644 --- a/layers/selections/image/kpFreeFormImageSelection.cpp +++ b/layers/selections/image/kpFreeFormImageSelection.cpp @@ -1,382 +1,388 @@ /* Copyright (c) 2003-2007 Clarence Dang All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #define DEBUG_KP_SELECTION 0 #include "layers/selections/image/kpFreeFormImageSelection.h" #include "kpLogCategories.h" #include "imagelib/kpPainter.h" struct kpFreeFormImageSelectionPrivate { QPolygon orgPoints; // Various Qt methods that take a QPolygon interpolate points differently // (e.g. QPainter::drawPolygon() vs QRegion(QPolygon)) when given consecutive // points that are not cardinally adjacent e.g. these 2 points: // // # // # // // are diagonally, but not cardinally, adjacent. They are rendered // inconsistently. Also, points which are not adjacent at all definitely // require interpolation and are inconsistently rendered: // // # // # // // So, we only pass cardinally interpolated points to those methods to // avoid this issue: // // ## // # // // These interpolated points are stored in . Regarding // , see the APIDoc for cardinallyAdjacentPointsLoop(). QPolygon cardPointsCache, cardPointsLoopCache; }; kpFreeFormImageSelection::kpFreeFormImageSelection ( const kpImageSelectionTransparency &transparency) : kpAbstractImageSelection (transparency), d (new kpFreeFormImageSelectionPrivate ()) { } kpFreeFormImageSelection::kpFreeFormImageSelection (const QPolygon &points, const kpImage &baseImage, const kpImageSelectionTransparency &transparency) : kpAbstractImageSelection (points.boundingRect (), baseImage, transparency), d (new kpFreeFormImageSelectionPrivate ()) { d->orgPoints = points; recalculateCardinallyAdjacentPoints (); } kpFreeFormImageSelection::kpFreeFormImageSelection (const QPolygon &points, const kpImageSelectionTransparency &transparency) : kpAbstractImageSelection (points.boundingRect (), transparency), d (new kpFreeFormImageSelectionPrivate ()) { d->orgPoints = points; recalculateCardinallyAdjacentPoints (); } kpFreeFormImageSelection::kpFreeFormImageSelection (const kpFreeFormImageSelection &rhs) : kpAbstractImageSelection (), d (new kpFreeFormImageSelectionPrivate ()) { *this = rhs; } kpFreeFormImageSelection &kpFreeFormImageSelection::operator= (const kpFreeFormImageSelection &rhs) { kpAbstractImageSelection::operator= (rhs); d->orgPoints = rhs.d->orgPoints; d->cardPointsCache = rhs.d->cardPointsCache; d->cardPointsLoopCache = rhs.d->cardPointsLoopCache; return *this; } // public virtual [kpAbstractSelection] kpFreeFormImageSelection *kpFreeFormImageSelection::clone () const { kpFreeFormImageSelection *sel = new kpFreeFormImageSelection (); *sel = *this; return sel; } kpFreeFormImageSelection::~kpFreeFormImageSelection () { delete d; } // public virtual [kpAbstractSelection] int kpFreeFormImageSelection::serialID () const { return SerialID; } // public virtual [base kpAbstractImageSelection] bool kpFreeFormImageSelection::readFromStream (QDataStream &stream) { - if (!kpAbstractImageSelection::readFromStream (stream)) + if (!kpAbstractImageSelection::readFromStream (stream)) { return false; + } stream >> d->orgPoints; recalculateCardinallyAdjacentPoints (); return true; } // public virtual [base kpAbstractImageSelection] void kpFreeFormImageSelection::writeToStream (QDataStream &stream) const { kpAbstractImageSelection::writeToStream (stream); stream << d->orgPoints; } // public virtual [base kpAbstractImageSelection] kpCommandSize::SizeType kpFreeFormImageSelection::size () const { return kpAbstractImageSelection::size () + (kpCommandSize::PolygonSize (d->orgPoints) + kpCommandSize::PolygonSize (d->cardPointsCache) + kpCommandSize::PolygonSize (d->cardPointsLoopCache)); } // public virtual [kpAbstractSelection] bool kpFreeFormImageSelection::isRectangular () const { return false; } // public QPolygon kpFreeFormImageSelection::originalPoints () const { return d->orgPoints; } static QPolygon RecalculateCardinallyAdjacentPoints (const QPolygon &points) { - qCDebug(kpLogLayers) << "kpFreeFormImageSelection.cpp:RecalculateCardinallyAdjacentPoints()" - << endl; + qCDebug(kpLogLayers) << "kpFreeFormImageSelection.cpp:RecalculateCardinallyAdjacentPoints()"; qCDebug(kpLogLayers) << "\tpoints=" << points; // Filter out duplicates. QPolygon noDups; - foreach (const QPoint &p, points) + for (const auto &p : points) { - if (!noDups.isEmpty () && p == noDups.last ()) + if (!noDups.isEmpty () && p == noDups.last ()) { continue; + } noDups.append (p); } qCDebug(kpLogLayers) << "\twithout dups=" << noDups; // Interpolate to ensure cardinal adjacency. QPolygon cardPoints; - foreach (const QPoint &p, noDups) + for (const auto &p : noDups) { if (!cardPoints.isEmpty () && !kpPainter::pointsAreCardinallyAdjacent (p, cardPoints.last ())) { const QPoint lastPoint = cardPoints.last (); QList interpPoints = kpPainter::interpolatePoints ( lastPoint, p, true/*cardinal adjacency*/); Q_ASSERT (interpPoints.size () >= 2); Q_ASSERT (interpPoints [0] == lastPoint); Q_ASSERT (interpPoints.last () == p); for (int i = 1/*skip already existing point*/; i < interpPoints.size (); i++) { cardPoints.append (interpPoints [i]); } } - else + else { cardPoints.append (p); + } } qCDebug(kpLogLayers) << "\tcardinally adjacent=" << cardPoints; return cardPoints; } // protected void kpFreeFormImageSelection::recalculateCardinallyAdjacentPoints () { d->cardPointsCache = ::RecalculateCardinallyAdjacentPoints (d->orgPoints); QPolygon pointsLoop = d->cardPointsCache; - if (!pointsLoop.isEmpty ()) + if (!pointsLoop.isEmpty ()) { pointsLoop.append (pointsLoop.first ()); + } // OPT: We know this method only needs to act on the last 2 points of // "pointLoop", since the previous points are definitely cardinally // adjacent. d->cardPointsLoopCache = ::RecalculateCardinallyAdjacentPoints (pointsLoop); } // public QPolygon kpFreeFormImageSelection::cardinallyAdjacentPoints () const { return d->cardPointsCache; } // public QPolygon kpFreeFormImageSelection::cardinallyAdjacentPointsLoop () const { return d->cardPointsLoopCache; } // public virtual [kpAbstractSelection] QPolygon kpFreeFormImageSelection::calculatePoints () const { return d->cardPointsLoopCache; } // protected virtual [kpAbstractSelection] QRegion kpFreeFormImageSelection::shapeRegion () const { const QRegion region = QRegion (d->cardPointsLoopCache, Qt::OddEvenFill); // In Qt4, while QPainter::drawRect() gives you rectangles 1 pixel // wider and higher, QRegion(QPolygon) gives you regions 1 pixel // narrower and shorter! Compensate for this by merging shifted // versions of the region. This seems to be consistent with shapeBitmap() // but I am a bit worried. // // Regarding alternative solutions: // 1. Instead of doing this region shifting and merging, if we were to // construct a QRegion simply from a point array with 4 points for // every point in "d->cardPointsLoopCache" (4 points = original point + 3 // translations below), it probably wouldn't work because the order of // the points in any point array matter for the odd-even fill // algorithm. This would probably manifest as problems with // self-intersecting borders. // 2. Constructing a QRegion from QBitmap (from shapeBitmap()) is probably // very slow since it would have to read each pixel of the QBitmap. // Having said that, this is probably the safest option as region shifting // is dodgy. Also, this would guarantee that shapeBitmap() and shapeRegion() // are consistent and we wouldn't need cardinally adjacent points either // (d->cardPointsCache and d->cardPointsLoopCache). const QRegion regionX = region.translated (1, 0); const QRegion regionY = region.translated (0, 1); const QRegion regionXY = region.translated (1, 1); return region.united (regionX).united (regionY).united (regionXY); } // public virtual [kpAbstractSelection] bool kpFreeFormImageSelection::contains (const QPoint &point) const { - if (!boundingRect ().contains (point)) + if (!boundingRect ().contains (point)) { return false; + } // We can't use the baseImage() (when non-null) and get the transparency of // the pixel at , instead of this region test, as the pixel may be // transparent but still within the border. return shapeRegion ().contains (point); } // public virtual [base kpAbstractSelection] void kpFreeFormImageSelection::moveBy (int dx, int dy) { d->orgPoints.translate (dx, dy); d->cardPointsCache.translate (dx, dy); d->cardPointsLoopCache.translate (dx, dy); // Call base last since it fires the changed() signal and we only // want that to fire at the very end of this method, after all // the selection state has been changed. kpAbstractImageSelection::moveBy (dx, dy); } //--------------------------------------------------------------------- static void FlipPoints (QPolygon *points, bool horiz, bool vert, const QRect &oldRect) { points->translate (-oldRect.x (), -oldRect.y ()); const QTransform matrix (horiz ? -1 : +1, // m11 0, // m12 0, // m21 vert ? -1 : +1, // m22 horiz ? (oldRect.width() - 1) : 0, // dx vert ? (oldRect.height() - 1) : 0); // dy #if !defined (QT_NO_DEBUG) && !defined (NDEBUG) QPolygon oldPoints = *points; #endif *points = matrix.map (*points); #if !defined (QT_NO_DEBUG) && !defined (NDEBUG) // Sanity check: flipping the points twice gives us the original points. Q_ASSERT (oldPoints == matrix.map (*points)); #endif points->translate (oldRect.x (), oldRect.y ()); } //--------------------------------------------------------------------- // public virtual [base kpAbstractImageSelection] void kpFreeFormImageSelection::flip (bool horiz, bool vert) { ::FlipPoints (&d->orgPoints, horiz, vert, boundingRect ()); ::FlipPoints (&d->cardPointsCache, horiz, vert, boundingRect ()); ::FlipPoints (&d->cardPointsLoopCache, horiz, vert, boundingRect ()); // Call base last since it fires the changed() signal and we only // want that to fire at the very end of this method, after all // the selection state has been changed. kpAbstractImageSelection::flip (horiz, vert); } //--------------------------------------------------------------------- // public virtual [kpAbstractSelection] void kpFreeFormImageSelection::paintBorder (QImage *destPixmap, const QRect &docRect, bool selectionFinished) const { - if (selectionFinished) + if (selectionFinished) { paintPolygonalBorder (cardinallyAdjacentPointsLoop (), destPixmap, docRect, selectionFinished); - else + } + else { paintPolygonalBorder (cardinallyAdjacentPoints (), destPixmap, docRect, selectionFinished); + } } diff --git a/layers/selections/image/kpImageSelectionTransparency.cpp b/layers/selections/image/kpImageSelectionTransparency.cpp index 86f53dcf..e138b26c 100644 --- a/layers/selections/image/kpImageSelectionTransparency.cpp +++ b/layers/selections/image/kpImageSelectionTransparency.cpp @@ -1,197 +1,195 @@ /* Copyright (c) 2003-2007 Clarence Dang All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #define DEBUG_KP_SELECTION_TRANSPARENCY 0 #include "layers/selections/image/kpImageSelectionTransparency.h" #include "kpLogCategories.h" #include "imagelib/kpColor.h" #include "widgets/colorSimilarity/kpColorSimilarityHolder.h" //--------------------------------------------------------------------- kpImageSelectionTransparency::kpImageSelectionTransparency () : m_isOpaque (true) { setColorSimilarity (0); } //--------------------------------------------------------------------- kpImageSelectionTransparency::kpImageSelectionTransparency (const kpColor &transparentColor, double colorSimilarity) : m_isOpaque (false), m_transparentColor (transparentColor) { setColorSimilarity (colorSimilarity); } //--------------------------------------------------------------------- kpImageSelectionTransparency::kpImageSelectionTransparency (bool isOpaque, const kpColor &transparentColor, double colorSimilarity) : m_isOpaque (isOpaque), m_transparentColor (transparentColor) { setColorSimilarity (colorSimilarity); } //--------------------------------------------------------------------- bool kpImageSelectionTransparency::operator== (const kpImageSelectionTransparency &rhs) const { qCDebug(kpLogLayers) << "kpImageSelectionTransparency::operator==()"; if (m_isOpaque != rhs.m_isOpaque) { qCDebug(kpLogLayers) << "\tdifferent opacity: lhs=" << m_isOpaque << " rhs=" << rhs.m_isOpaque; return false; } if (m_isOpaque) { qCDebug(kpLogLayers) << "\tboth opaque - eq"; return true; } qCDebug(kpLogLayers) << "\tcolours: lhs=" << (int *) m_transparentColor.toQRgb () << " rhs=" << (int *) rhs.m_transparentColor.toQRgb (); qCDebug(kpLogLayers) << "\tcolour similarity: lhs=" << m_colorSimilarity << " rhs=" << rhs.m_colorSimilarity; return (m_transparentColor == rhs.m_transparentColor && m_colorSimilarity == rhs.m_colorSimilarity); } //--------------------------------------------------------------------- bool kpImageSelectionTransparency::operator!= (const kpImageSelectionTransparency &rhs) const { return !(*this == rhs); } //--------------------------------------------------------------------- -kpImageSelectionTransparency::~kpImageSelectionTransparency () -{ -} +kpImageSelectionTransparency::~kpImageSelectionTransparency () = default; //--------------------------------------------------------------------- // public bool kpImageSelectionTransparency::isOpaque () const { return m_isOpaque; } //--------------------------------------------------------------------- // public bool kpImageSelectionTransparency::isTransparent () const { return !isOpaque (); } //--------------------------------------------------------------------- // public void kpImageSelectionTransparency::setOpaque (bool yes) { m_isOpaque = yes; } //--------------------------------------------------------------------- // public void kpImageSelectionTransparency::setTransparent (bool yes) { setOpaque (!yes); } //--------------------------------------------------------------------- // public kpColor kpImageSelectionTransparency::transparentColor () const { if (m_isOpaque) { // There are legitimate uses for this so no qCCritical(kpLogLayers) qCDebug(kpLogLayers) << "kpImageSelectionTransparency::transparentColor() " - "getting transparent color even though opaque" << endl; + "getting transparent color even though opaque"; } return m_transparentColor; } //--------------------------------------------------------------------- // public void kpImageSelectionTransparency::setTransparentColor (const kpColor &transparentColor) { m_transparentColor = transparentColor; } //--------------------------------------------------------------------- // public double kpImageSelectionTransparency::colorSimilarity () const { if (m_colorSimilarity < 0 || m_colorSimilarity > kpColorSimilarityHolder::MaxColorSimilarity) { - qCCritical(kpLogLayers) << "kpImageSelectionTransparency::colorSimilarity() invalid colorSimilarity" << endl; + qCCritical(kpLogLayers) << "kpImageSelectionTransparency::colorSimilarity() invalid colorSimilarity"; return 0; } return m_colorSimilarity; } //--------------------------------------------------------------------- // pubulic void kpImageSelectionTransparency::setColorSimilarity (double colorSimilarity) { m_colorSimilarity = colorSimilarity; m_processedColorSimilarity = kpColor::processSimilarity (colorSimilarity); } //--------------------------------------------------------------------- // public int kpImageSelectionTransparency::processedColorSimilarity () const { return m_processedColorSimilarity; } //--------------------------------------------------------------------- diff --git a/layers/selections/image/kpRectangularImageSelection.cpp b/layers/selections/image/kpRectangularImageSelection.cpp index 4760e1bb..e219c8e1 100644 --- a/layers/selections/image/kpRectangularImageSelection.cpp +++ b/layers/selections/image/kpRectangularImageSelection.cpp @@ -1,148 +1,149 @@ /* Copyright (c) 2003-2007 Clarence Dang All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #define DEBUG_KP_SELECTION 0 #include "layers/selections/image/kpRectangularImageSelection.h" #include #include struct kpRectangularImageSelectionPrivate { }; kpRectangularImageSelection::kpRectangularImageSelection ( const kpImageSelectionTransparency &transparency) : kpAbstractImageSelection (transparency), d (new kpRectangularImageSelectionPrivate ()) { } kpRectangularImageSelection::kpRectangularImageSelection (const QRect &rect, const kpImage &baseImage, const kpImageSelectionTransparency &transparency) : kpAbstractImageSelection (rect, baseImage, transparency), d (new kpRectangularImageSelectionPrivate ()) { } kpRectangularImageSelection::kpRectangularImageSelection (const QRect &rect, const kpImageSelectionTransparency &transparency) : kpAbstractImageSelection (rect, transparency), d (new kpRectangularImageSelectionPrivate ()) { } kpRectangularImageSelection::kpRectangularImageSelection (const kpRectangularImageSelection &rhs) : kpAbstractImageSelection (), d (new kpRectangularImageSelectionPrivate ()) { *this = rhs; } kpRectangularImageSelection &kpRectangularImageSelection::operator= ( const kpRectangularImageSelection &rhs) { kpAbstractImageSelection::operator= (rhs); return *this; } kpRectangularImageSelection *kpRectangularImageSelection::clone () const { kpRectangularImageSelection *sel = new kpRectangularImageSelection (); *sel = *this; return sel; } kpRectangularImageSelection::~kpRectangularImageSelection () { delete d; } // public virtual [kpAbstractSelection] int kpRectangularImageSelection::serialID () const { return SerialID; } // public virtual [kpAbstractSelection] bool kpRectangularImageSelection::isRectangular () const { return true; } // public virtual [kpAbstractSelection] QPolygon kpRectangularImageSelection::calculatePoints () const { return kpAbstractImageSelection::CalculatePointsForRectangle (boundingRect ()); } // public virtual [base kpAbstractImageSelection] QBitmap kpRectangularImageSelection::shapeBitmap (bool nullForRectangular) const { Q_ASSERT (boundingRect ().isValid ()); - if (nullForRectangular) - return QBitmap (); + if (nullForRectangular) { + return {}; + } QBitmap maskBitmap (width (), height ()); maskBitmap.fill (Qt::color1/*opaque*/); return maskBitmap; } // public virtual [kpAbstractImageSelection] QRegion kpRectangularImageSelection::shapeRegion () const { return QRegion (boundingRect (), QRegion::Rectangle); } // public virtual [kpAbstractSelection] bool kpRectangularImageSelection::contains (const QPoint &point) const { return boundingRect ().contains (point); } // public virtual [kpAbstractSelection] void kpRectangularImageSelection::paintBorder (QImage *destPixmap, const QRect &docRect, bool selectionFinished) const { paintRectangularBorder (destPixmap, docRect, selectionFinished); } diff --git a/layers/selections/kpAbstractSelection.cpp b/layers/selections/kpAbstractSelection.cpp index 8d3e96c2..f8f09b0e 100644 --- a/layers/selections/kpAbstractSelection.cpp +++ b/layers/selections/kpAbstractSelection.cpp @@ -1,309 +1,315 @@ /* Copyright (c) 2003-2007 Clarence Dang All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #define DEBUG_KP_SELECTION 0 #include "layers/selections/kpAbstractSelection.h" #include #include #include "kpLogCategories.h" struct kpAbstractSelectionPrivate { QRect rect; }; // protected kpAbstractSelection::kpAbstractSelection () : QObject (), d (new kpAbstractSelectionPrivate ()) { d->rect = QRect (); } // protected kpAbstractSelection::kpAbstractSelection (const QRect &rect) : QObject (), d (new kpAbstractSelectionPrivate ()) { d->rect = rect; } // protected kpAbstractSelection &kpAbstractSelection::operator= (const kpAbstractSelection &rhs) { - if (this == &rhs) + if (this == &rhs) { return *this; + } d->rect = rhs.d->rect; return *this; } // protected kpAbstractSelection::~kpAbstractSelection () { delete d; } // public virtual bool kpAbstractSelection::readFromStream (QDataStream &stream) { stream >> d->rect; return true; } // public virtual void kpAbstractSelection::writeToStream (QDataStream &stream) const { stream << d->rect; } // friend QDataStream &operator<< (QDataStream &stream, const kpAbstractSelection &selection) { #if DEBUG_KP_SELECTION && 1 qCDebug(kpLogLayers) << "kpAbstractSelection::operator<<(sel: rect=" << - selection.boundingRect () << endl; + selection.boundingRect (); #endif stream << selection.serialID (); selection.writeToStream (stream); return stream; } // public virtual kpCommandSize::SizeType kpAbstractSelection::size () const { return 0/*constant size*/; } // public QSize kpAbstractSelection::minimumSize () const { - return QSize (minimumWidth (), minimumHeight ()); + return {minimumWidth (), minimumHeight ()}; } // public int kpAbstractSelection::x () const { return d->rect.x (); } // public int kpAbstractSelection::y () const { return d->rect.y (); } // public QPoint kpAbstractSelection::topLeft () const { return d->rect.topLeft (); } // public int kpAbstractSelection::width () const { return boundingRect ().width (); } // public int kpAbstractSelection::height () const { return boundingRect ().height (); } // public QRect kpAbstractSelection::boundingRect () const { return d->rect; } // public static QPolygon kpAbstractSelection::CalculatePointsForRectangle (const QRect &rect) { QPolygon points; // OPT: not space optimal - current code adds duplicate corner points. // top - for (int x = 0; x < rect.width (); x++) + for (int x = 0; x < rect.width (); x++) { points.append (QPoint (rect.x () + x, rect.top ())); + } // right - for (int y = 0; y < rect.height (); y++) + for (int y = 0; y < rect.height (); y++) { points.append (QPoint (rect.right (), rect.y () + y)); + } // bottom - for (int x = rect.width () - 1; x >= 0; x--) + for (int x = rect.width () - 1; x >= 0; x--) { points.append (QPoint (rect.x () + x, rect.bottom ())); + } // left - for (int y = rect.height () - 1; y >= 0; y--) + for (int y = rect.height () - 1; y >= 0; y--) { points.append (QPoint (rect.left (), rect.y () + y)); + } return points; } // public bool kpAbstractSelection::contains (int x, int y) const { return contains (QPoint (x, y)); } // public virtual void kpAbstractSelection::moveBy (int dx, int dy) { #if DEBUG_KP_SELECTION && 1 qCDebug(kpLogLayers) << "kpAbstractSelection::moveBy(" << dx << "," << dy << ")"; #endif - if (dx == 0 && dy == 0) + if (dx == 0 && dy == 0) { return; + } QRect oldRect = boundingRect (); #if DEBUG_KP_SELECTION && 1 qCDebug(kpLogLayers) << "\toldRect=" << oldRect; #endif d->rect.translate (dx, dy); #if DEBUG_KP_SELECTION && 1 qCDebug(kpLogLayers) << "\tnewRect=" << d->rect; #endif emit changed (oldRect); emit changed (boundingRect ()); } // public void kpAbstractSelection::moveTo (int dx, int dy) { moveTo (QPoint (dx, dy)); } // public void kpAbstractSelection::moveTo (const QPoint &topLeftPoint) { #if DEBUG_KP_SELECTION && 1 qCDebug(kpLogLayers) << "kpAbstractSelection::moveTo(" << topLeftPoint << ")"; #endif QRect oldBoundingRect = boundingRect (); #if DEBUG_KP_SELECTION && 1 qCDebug(kpLogLayers) << "\toldBoundingRect=" << oldBoundingRect; #endif - if (topLeftPoint == oldBoundingRect.topLeft ()) + if (topLeftPoint == oldBoundingRect.topLeft ()) { return; + } QPoint delta (topLeftPoint - oldBoundingRect.topLeft ()); moveBy (delta.x (), delta.y ()); } //--------------------------------------------------------------------- // protected void kpAbstractSelection::paintRectangularBorder (QImage *destPixmap, const QRect &docRect, bool selectionFinished) const { (void) selectionFinished; #if DEBUG_KP_SELECTION && 1 qCDebug(kpLogLayers) << "kpAbstractSelection::paintRectangularBorder() boundingRect=" - << boundingRect () << endl; + << boundingRect (); #endif #if DEBUG_KP_SELECTION && 1 qCDebug(kpLogLayers) << "\tselection border = rectangle"; qCDebug(kpLogLayers) << "\t\tx=" << boundingRect ().x () - docRect.x () << " y=" << boundingRect ().y () - docRect.y () << " w=" << boundingRect ().width () - << " h=" << boundingRect ().height () - << endl; + << " h=" << boundingRect ().height (); #endif kpPixmapFX::drawStippleRect(destPixmap, boundingRect ().x () - docRect.x (), boundingRect ().y () - docRect.y (), boundingRect ().width (), boundingRect ().height (), kpColor::Blue, kpColor::Yellow); } //--------------------------------------------------------------------- // protected void kpAbstractSelection::paintPolygonalBorder (const QPolygon &points, QImage *destPixmap, const QRect &docRect, bool selectionFinished) const { #if DEBUG_KP_SELECTION && 1 qCDebug(kpLogLayers) << "kpAbstractSelection::paintPolygonalBorder() boundingRect=" - << boundingRect () << endl; + << boundingRect (); #endif QPolygon pointsTranslated = points; pointsTranslated.translate (-docRect.x (), -docRect.y ()); if ( !selectionFinished ) { kpPixmapFX::drawPolyline(destPixmap, pointsTranslated, kpColor::Blue, 1/*pen width*/, kpColor::Yellow); } else { kpPixmapFX::drawPolygon(destPixmap, pointsTranslated, kpColor::Blue, 1/*pen width*/, kpColor::Invalid/*no background*/, true/*is final*/, kpColor::Yellow); kpPixmapFX::drawStippleRect(destPixmap, boundingRect ().x () - docRect.x (), boundingRect ().y () - docRect.y (), boundingRect ().width (), boundingRect ().height (), kpColor::LightGray, kpColor::DarkGray); } } diff --git a/layers/selections/kpSelectionDrag.cpp b/layers/selections/kpSelectionDrag.cpp index d31f0d8f..7d446a23 100644 --- a/layers/selections/kpSelectionDrag.cpp +++ b/layers/selections/kpSelectionDrag.cpp @@ -1,166 +1,165 @@ /* Copyright (c) 2003-2007 Clarence Dang Copyright (c) 2011 Martin Koller All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #define DEBUG_KP_SELECTION_DRAG 0 #include "kpSelectionDrag.h" #include #include #include #include "kpLogCategories.h" #include "kpSelectionFactory.h" #include "layers/selections/image/kpAbstractImageSelection.h" #include "layers/selections/image/kpRectangularImageSelection.h" //--------------------------------------------------------------------- // public static const char * const kpSelectionDrag::SelectionMimeType = "application/x-kolourpaint-selection-400"; //--------------------------------------------------------------------- kpSelectionDrag::kpSelectionDrag (const kpAbstractImageSelection &sel) { #if DEBUG_KP_SELECTION_DRAG && 1 qCDebug(kpLogLayers) << "kpSelectionDrag() w=" << sel.width () - << " h=" << sel.height () - << endl; + << " h=" << sel.height (); #endif Q_ASSERT (sel.hasContent ()); // Store as selection. QByteArray ba; { QDataStream stream (&ba, QIODevice::WriteOnly); stream << sel; } setData (kpSelectionDrag::SelectionMimeType, ba); // Store as image (so that QMimeData::hasImage()) works). // OPT: an awful waste of memory storing image in both selection and QImage const QImage image = sel.baseImage (); #if DEBUG_KP_SELECTION_DRAG && 1 qCDebug(kpLogLayers) << "\timage: w=" << image.width () - << " h=" << image.height () - << endl; + << " h=" << image.height (); #endif if (image.isNull ()) { // TODO: proper error handling. - qCCritical(kpLogLayers) << "kpSelectionDrag::setSelection() could not convert to image" - << endl; + qCCritical(kpLogLayers) << "kpSelectionDrag::setSelection() could not convert to image"; } - else + else { setImageData (image); + } } //--------------------------------------------------------------------- // public static bool kpSelectionDrag::canDecode(const QMimeData *mimeData) { Q_ASSERT(mimeData); #if DEBUG_KP_SELECTION_DRAG qCDebug(kpLogLayers) << "kpSelectionDrag::canDecode()" << "hasSel=" << mimeData->hasFormat(kpSelectionDrag::SelectionMimeType) << "hasImage=" << mimeData->hasImage(); #endif // mimeData->hasImage() would not check if the data is a valid image return mimeData->hasFormat(kpSelectionDrag::SelectionMimeType) || !qvariant_cast(mimeData->imageData()).isNull(); } //--------------------------------------------------------------------- // public static kpAbstractImageSelection *kpSelectionDrag::decode(const QMimeData *mimeData) { #if DEBUG_KP_SELECTION_DRAG qCDebug(kpLogLayers) << "kpSelectionDrag::decode(kpAbstractSelection)"; #endif Q_ASSERT (mimeData); if (mimeData->hasFormat (kpSelectionDrag::SelectionMimeType)) { #if DEBUG_KP_SELECTION_DRAG qCDebug(kpLogLayers) << "\tmimeSource hasFormat selection - just return it in QByteArray"; #endif QByteArray data = mimeData->data (kpSelectionDrag::SelectionMimeType); QDataStream stream (&data, QIODevice::ReadOnly); return kpSelectionFactory::FromStream (stream); } - else + + +#if DEBUG_KP_SELECTION_DRAG + qCDebug(kpLogLayers) << "\tmimeSource doesn't provide selection - try image"; +#endif + + QImage image = qvariant_cast (mimeData->imageData ()); + if (!image.isNull ()) { - #if DEBUG_KP_SELECTION_DRAG - qCDebug(kpLogLayers) << "\tmimeSource doesn't provide selection - try image"; - #endif +#if DEBUG_KP_SELECTION_DRAG + qCDebug(kpLogLayers) << "\tok w=" << image.width () << " h=" << image.height (); +#endif - QImage image = qvariant_cast (mimeData->imageData ()); - if (!image.isNull ()) - { - #if DEBUG_KP_SELECTION_DRAG - qCDebug(kpLogLayers) << "\tok w=" << image.width () << " h=" << image.height (); - #endif + return new kpRectangularImageSelection ( + QRect (0, 0, image.width (), image.height ()), image); + } - return new kpRectangularImageSelection ( - QRect (0, 0, image.width (), image.height ()), image); - } - else if ( mimeData->hasUrls() ) // no image, check for path to local image file - { - QList urls = mimeData->urls(); + if ( mimeData->hasUrls() ) // no image, check for path to local image file + { + QList urls = mimeData->urls(); - if ( urls.count() && urls[0].isLocalFile() ) - { + if ( urls.count() && urls[0].isLocalFile() ) + { image.load(urls[0].toLocalFile()); if ( !image.isNull() ) { - return new kpRectangularImageSelection( - QRect(0, 0, image.width(), image.height()), image); + return new kpRectangularImageSelection( + QRect(0, 0, image.width(), image.height()), image); } - } } + } #if DEBUG_KP_SELECTION_DRAG qCDebug(kpLogLayers) << "kpSelectionDrag::decode(kpAbstractSelection) mimeSource had no sel " - "and could not decode to image" << endl; + "and could not decode to image"; #endif return nullptr; - } + } //--------------------------------------------------------------------- diff --git a/layers/selections/text/kpPreeditText.cpp b/layers/selections/text/kpPreeditText.cpp index a904561f..87671d90 100644 --- a/layers/selections/text/kpPreeditText.cpp +++ b/layers/selections/text/kpPreeditText.cpp @@ -1,142 +1,142 @@ /* Copyright (c) 2010 Tasuku Suzuki All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include "layers/selections/text/kpPreeditText.h" //--------------------------------------------------------------------- bool attributeLessThan (const QInputMethodEvent::Attribute &a1, const QInputMethodEvent::Attribute &a2) { return a1.start < a2.start; } //--------------------------------------------------------------------- kpPreeditText::kpPreeditText () : m_cursorPosition (0), m_cursorColor (Qt::transparent), m_selectionStart (0), m_selectionLength (0), m_position (-1, -1) { } //--------------------------------------------------------------------- kpPreeditText::kpPreeditText (const QInputMethodEvent *event) : m_cursorPosition (0), m_cursorColor (Qt::transparent), m_selectionStart (0), m_selectionLength (0), m_position (-1, -1) { m_preeditString = event->preeditString (); - foreach (const QInputMethodEvent::Attribute &attr, event->attributes ()) + for (const auto &attr : event->attributes ()) { switch (attr.type) { case QInputMethodEvent::TextFormat: m_textFormatList.append (attr); break; case QInputMethodEvent::Cursor: m_cursorPosition = attr.start; if (attr.length > 0) { m_cursorColor = attr.value.value (); } break; case QInputMethodEvent::Selection: m_selectionStart = attr.start; m_selectionLength = attr.length; break; default: break; } } qSort (m_textFormatList.begin (), m_textFormatList.end (), attributeLessThan); } //--------------------------------------------------------------------- bool kpPreeditText::isEmpty () const { return m_preeditString.isEmpty (); } //--------------------------------------------------------------------- const QString &kpPreeditText::preeditString () const { return m_preeditString; } //--------------------------------------------------------------------- int kpPreeditText::cursorPosition () const { return m_cursorPosition; } //--------------------------------------------------------------------- const QColor &kpPreeditText::cursorColor () const { return m_cursorColor; } //--------------------------------------------------------------------- int kpPreeditText::selectionStart () const { return m_selectionStart; } //--------------------------------------------------------------------- int kpPreeditText::selectionLength () const { return m_selectionLength; } //--------------------------------------------------------------------- const QList &kpPreeditText::textFormatList () const { return m_textFormatList; } //--------------------------------------------------------------------- const QPoint &kpPreeditText::position () const { return m_position; } //--------------------------------------------------------------------- void kpPreeditText::setPosition (const QPoint &position) { m_position = position; } //--------------------------------------------------------------------- diff --git a/layers/selections/text/kpTextSelection.cpp b/layers/selections/text/kpTextSelection.cpp index c92b6d7b..167967ee 100644 --- a/layers/selections/text/kpTextSelection.cpp +++ b/layers/selections/text/kpTextSelection.cpp @@ -1,345 +1,347 @@ /* Copyright (c) 2003-2007 Clarence Dang Copyright (c) 2010 Tasuku Suzuki All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #define DEBUG_KP_SELECTION 0 #include "kpTextSelection.h" #include "kpTextSelectionPrivate.h" #include "kpDefs.h" #include "kpTextStyle.h" #include "kpLogCategories.h" #include #include // public kpTextSelection::kpTextSelection (const QRect &rect, const kpTextStyle &textStyle) : kpAbstractSelection (rect), d (new kpTextSelectionPrivate ()) { d->textStyle = textStyle; } // public kpTextSelection::kpTextSelection (const QRect &rect, const QList &textLines, const kpTextStyle &textStyle) : kpAbstractSelection (rect), d (new kpTextSelectionPrivate ()) { d->textLines = textLines; d->textStyle = textStyle; } // public kpTextSelection::kpTextSelection (const kpTextSelection &rhs) : kpAbstractSelection (), d (new kpTextSelectionPrivate ()) { *this = rhs; } // public kpTextSelection &kpTextSelection::operator= (const kpTextSelection &rhs) { kpAbstractSelection::operator= (rhs); d->textLines = rhs.d->textLines; d->textStyle = rhs.d->textStyle; d->preeditText = rhs.d->preeditText; return *this; } // public virtual [base kpAbstractSelection] kpTextSelection *kpTextSelection::clone () const { kpTextSelection *sel = new kpTextSelection (); *sel = *this; return sel; } // public kpTextSelection *kpTextSelection::resized (int newWidth, int newHeight) const { return new kpTextSelection (QRect (x (), y (), newWidth, newHeight), d->textLines, d->textStyle); } // public kpTextSelection::~kpTextSelection () { delete d; } // public virtual [kpAbstractSelection] int kpTextSelection::serialID () const { Q_ASSERT (!"Marshalling not supported"); return -1; } // public virtual [base kpAbstractSelection] bool kpTextSelection::readFromStream (QDataStream &stream) { (void) stream; Q_ASSERT (!"Marshalling not supported"); return false; } // public virtual [base kpAbstractSelection] void kpTextSelection::writeToStream (QDataStream &stream) const { (void) stream; Q_ASSERT (!"Marshalling not supported"); } // public virtual [kpAbstractSelection] QString kpTextSelection::name () const { return i18n ("Text"); } // public virtual [base kpAbstractSelection] kpCommandSize::SizeType kpTextSelection::size () const { return kpAbstractSelection::size () + kpCommandSize::StringSize (text ()); } // public virtual [kpAbstractSelection] bool kpTextSelection::isRectangular () const { return true; } // public static int kpTextSelection::MinimumWidthForTextStyle (const kpTextStyle &) { return (kpTextSelection::TextBorderSize () * 2 + 5); } // public static int kpTextSelection::MinimumHeightForTextStyle (const kpTextStyle &) { return (kpTextSelection::TextBorderSize () * 2 + 5); } // public static QSize kpTextSelection::MinimumSizeForTextStyle (const kpTextStyle &textStyle) { - return QSize (kpTextSelection::MinimumWidthForTextStyle (textStyle), - kpTextSelection::MinimumHeightForTextStyle (textStyle)); + return {kpTextSelection::MinimumWidthForTextStyle (textStyle), + kpTextSelection::MinimumHeightForTextStyle (textStyle)}; } // public virtual [kpAbstractSelection] int kpTextSelection::minimumWidth () const { return kpTextSelection::MinimumWidthForTextStyle (textStyle ()); } // public virtual [kpAbstractSelection] int kpTextSelection::minimumHeight () const { return kpTextSelection::MinimumHeightForTextStyle (textStyle ()); } // public static int kpTextSelection::PreferredMinimumWidthForTextStyle (const kpTextStyle &textStyle) { const int about15CharsWidth = textStyle.fontMetrics ().width ( QLatin1String ("1234567890abcde")); const int preferredMinWidth = qMax (150, kpTextSelection::TextBorderSize () * 2 + about15CharsWidth); return qMax (kpTextSelection::MinimumWidthForTextStyle (textStyle), qMin (250, preferredMinWidth)); } // public static int kpTextSelection::PreferredMinimumHeightForTextStyle (const kpTextStyle &textStyle) { const int preferredMinHeight = kpTextSelection::TextBorderSize () * 2 + textStyle.fontMetrics ().height (); return qMax (kpTextSelection::MinimumHeightForTextStyle (textStyle), qMin (150, preferredMinHeight)); } // public static QSize kpTextSelection::PreferredMinimumSizeForTextStyle (const kpTextStyle &textStyle) { - return QSize (kpTextSelection::PreferredMinimumWidthForTextStyle (textStyle), - kpTextSelection::PreferredMinimumHeightForTextStyle (textStyle)); + return {kpTextSelection::PreferredMinimumWidthForTextStyle (textStyle), + kpTextSelection::PreferredMinimumHeightForTextStyle (textStyle)}; } // public static int kpTextSelection::TextBorderSize () { return 1; } // public QRect kpTextSelection::textAreaRect () const { - return QRect (x () + kpTextSelection::TextBorderSize (), - y () + kpTextSelection::TextBorderSize (), - width () - kpTextSelection::TextBorderSize () * 2, - height () - kpTextSelection::TextBorderSize () * 2); + return {x () + kpTextSelection::TextBorderSize (), + y () + kpTextSelection::TextBorderSize (), + width () - kpTextSelection::TextBorderSize () * 2, + height () - kpTextSelection::TextBorderSize () * 2}; } // public virtual [kpAbstractSelection] QPolygon kpTextSelection::calculatePoints () const { return kpAbstractSelection::CalculatePointsForRectangle (boundingRect ()); } // public virtual [kpAbstractSelection] bool kpTextSelection::contains (const QPoint &point) const { return boundingRect ().contains (point); } // public bool kpTextSelection::pointIsInTextBorderArea (const QPoint &point) const { return (boundingRect ().contains (point) && !pointIsInTextArea (point)); } // public bool kpTextSelection::pointIsInTextArea (const QPoint &point) const { return textAreaRect ().contains (point); } // public virtual [kpAbstractSelection] bool kpTextSelection::hasContent () const { return !d->textLines.isEmpty (); } // public virtual [kpAbstractSelection] void kpTextSelection::deleteContent () { - if (!hasContent ()) + if (!hasContent ()) { return; + } setTextLines (QList ()); } // public QList kpTextSelection::textLines () const { return d->textLines; } // public void kpTextSelection::setTextLines (const QList &textLines_) { d->textLines = textLines_; emit changed (boundingRect ()); } // public static QString kpTextSelection::TextForTextLines (const QList &textLines) { - if (textLines.isEmpty ()) - return QString (); + if (textLines.isEmpty ()) { + return {}; + } QString bigString = textLines [0]; for (QList ::const_iterator it = textLines.begin () + 1; it != textLines.end (); ++it) { bigString += QLatin1String ("\n"); bigString += (*it); } return bigString; } // public QString kpTextSelection::text () const { return kpTextSelection::TextForTextLines (d->textLines); } // public kpTextStyle kpTextSelection::textStyle () const { return d->textStyle; } // public void kpTextSelection::setTextStyle (const kpTextStyle &textStyle) { d->textStyle = textStyle; emit changed (boundingRect ()); } kpPreeditText kpTextSelection::preeditText () const { return d->preeditText; } void kpTextSelection::setPreeditText (const kpPreeditText &preeditText) { d->preeditText = preeditText; emit changed (boundingRect ()); } diff --git a/layers/selections/text/kpTextSelection_Cursor.cpp b/layers/selections/text/kpTextSelection_Cursor.cpp index 8d847158..9503032f 100644 --- a/layers/selections/text/kpTextSelection_Cursor.cpp +++ b/layers/selections/text/kpTextSelection_Cursor.cpp @@ -1,126 +1,129 @@ /* Copyright (c) 2003-2007 Clarence Dang Copyright (c) 2010 Tasuku Suzuki All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #define DEBUG_KP_SELECTION 0 #include "kpTextSelection.h" #include "kpTextSelectionPrivate.h" #include "kpDefs.h" #include "kpTextStyle.h" #include "kpPreeditText.h" #include "kpLogCategories.h" #include #include // public int kpTextSelection::closestTextRowForPoint (const QPoint &point) const { - if (!pointIsInTextArea (point)) + if (!pointIsInTextArea (point)) { return -1; + } const QFontMetrics fontMetrics (d->textStyle.fontMetrics ()); int row = (point.y () - textAreaRect ().y ()) / fontMetrics.lineSpacing (); - if (row >= static_cast (d->textLines.size ())) + if (row >= static_cast (d->textLines.size ())) { row = d->textLines.size () - 1; + } return row; } // public int kpTextSelection::closestTextColForPoint (const QPoint &point) const { int row = closestTextRowForPoint (point); - if (row < 0 || row >= static_cast (d->textLines.size ())) + if (row < 0 || row >= static_cast (d->textLines.size ())) { return -1; + } const int localX = point.x () - textAreaRect ().x (); const QFontMetrics fontMetrics (d->textStyle.fontMetrics ()); // (should be 0 but call just in case) int charLocalLeft = fontMetrics.width (d->textLines [row], 0); // OPT: binary search or guess location then move for (int col = 0; col < static_cast (d->textLines [row].length ()); col++) { // OPT: fontMetrics::charWidth() might be faster const int nextCharLocalLeft = fontMetrics.width (d->textLines [row], col + 1); - if (localX <= (charLocalLeft + nextCharLocalLeft) / 2) + if (localX <= (charLocalLeft + nextCharLocalLeft) / 2) { return col; + } charLocalLeft = nextCharLocalLeft; } return d->textLines [row].length ()/*past end of line*/; } //--------------------------------------------------------------------- // public QPoint kpTextSelection::pointForTextRowCol (int row, int col) const { kpPreeditText preeditText = d->preeditText; if ((row < 0 || col < 0) || (preeditText.isEmpty () && (row >= static_cast (d->textLines.size ()) || col > static_cast (d->textLines [row].length ())))) { #if DEBUG_KP_SELECTION && 1 qCDebug(kpLogLayers) << "kpTextSelection::pointForTextRowCol(" << row << "," << col << ") out of range" << " textLines='" << text () - << "'" - << endl; + << "'"; #endif return KP_INVALID_POINT; } const QFontMetrics fontMetrics (d->textStyle.fontMetrics ()); QString line = (d->textLines.count () > row) ? d->textLines[row] : QString (); if (row == preeditText.position ().y ()) { line.insert (preeditText.position ().x (), preeditText.preeditString ()); } const int x = fontMetrics.width (line.left (col)); const int y = row * fontMetrics.height () + (row >= 1 ? row * fontMetrics.leading () : 0); return textAreaRect ().topLeft () + QPoint (x, y); } //--------------------------------------------------------------------- diff --git a/layers/selections/text/kpTextSelection_Paint.cpp b/layers/selections/text/kpTextSelection_Paint.cpp index b0d1a6c2..4811d5cf 100644 --- a/layers/selections/text/kpTextSelection_Paint.cpp +++ b/layers/selections/text/kpTextSelection_Paint.cpp @@ -1,269 +1,274 @@ // REFACTOR: Move into kpPainter /* Copyright (c) 2003-2007 Clarence Dang Copyright (c) 2010 Tasuku Suzuki All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #define DEBUG_KP_SELECTION 0 #include "kpTextSelection.h" #include "kpTextSelectionPrivate.h" #include "kpTextStyle.h" #include "kpPreeditText.h" #include "pixmapfx/kpPixmapFX.h" #include "kpLogCategories.h" #include #include #include #include #include //--------------------------------------------------------------------- void kpTextSelection::drawPreeditString(QPainter &painter, int &x, int y, const kpPreeditText &preeditText) const { int i = 0; - QString preeditString = preeditText.preeditString (); + const QString& preeditString = preeditText.preeditString (); QString str; - foreach (const QInputMethodEvent::Attribute &attr, preeditText.textFormatList ()) + for (const auto &attr : preeditText.textFormatList ()) { int start = attr.start; int length = attr.length; QTextCharFormat format = qvariant_cast (attr.value).toCharFormat (); if (i > start) { length = length - i + start; start = i; } - if (length <= 0) continue; + if (length <= 0) { + continue; + } if (i < start) { str = preeditString.mid (i, start - i); painter.drawText (x, y, str); x += painter.fontMetrics ().width (str); } painter.save(); str = preeditString.mid (start, length); int width = painter.fontMetrics().width (str); if (format.background ().color () != Qt::black) { painter.save (); painter.setPen (format.background ().color ()); painter.setBrush (format.background()); painter.drawRect (x, y - painter.fontMetrics ().ascent (), width, painter.fontMetrics ().height ()); painter.restore (); } if (format.foreground ().color () != Qt::black) { painter.setBrush (format.foreground ()); painter.setPen (format.foreground ().color ()); } if (format.underlineStyle ()) { painter.drawLine (x, y + painter.fontMetrics ().descent (), x + width, y + painter.fontMetrics ().descent ()); } painter.drawText (x, y, str); x += width; painter.restore (); i = start + length; } if (i < preeditString.length ()) { str = preeditString.mid (i); painter.drawText (x, y, str); x += painter.fontMetrics ().width (str); } } //--------------------------------------------------------------------- // public virtual [kpAbstractSelection] void kpTextSelection::paint(QImage *destPixmap, const QRect &docRect) const { #if DEBUG_KP_SELECTION qCDebug(kpLogLayers) << "kpTextSelection::paint() textStyle: fcol=" << (int *) d->textStyle.foregroundColor ().toQRgb () << " bcol=" - << (int *) d->textStyle.backgroundColor ().toQRgb () - << endl; + << (int *) d->textStyle.backgroundColor ().toQRgb (); #endif // Drawing text is slow so if the text box will be rendered completely // outside of , don't bother rendering it at all. const QRect modifyingRect = docRect.intersected (boundingRect ()); - if (modifyingRect.isEmpty ()) + if (modifyingRect.isEmpty ()) { return; + } // Is the text box completely invisible? if (textStyle ().foregroundColor ().isTransparent () && textStyle ().backgroundColor ().isTransparent ()) { return; } kpImage floatImage(modifyingRect.size(), QImage::Format_ARGB32_Premultiplied); floatImage.fill(0); QRect theWholeAreaRect, theTextAreaRect; theWholeAreaRect = boundingRect ().translated (-modifyingRect.topLeft ()); theTextAreaRect = textAreaRect ().translated (-modifyingRect.topLeft ()); QList theTextLines = textLines(); kpTextStyle theTextStyle = textStyle(); const QFontMetrics fontMetrics (theTextStyle.font ()); #if DEBUG_KP_SELECTION qCDebug(kpLogLayers) << "kpTextSelection_Paint.cpp:DrawTextHelper"; qCDebug(kpLogLayers) << "\theight=" << fontMetrics.height () << " leading=" << fontMetrics.leading () << " ascent=" << fontMetrics.ascent () << " descent=" << fontMetrics.descent () - << " lineSpacing=" << fontMetrics.lineSpacing () - << endl; + << " lineSpacing=" << fontMetrics.lineSpacing (); #endif QPainter painter(&floatImage); // Fill in the background using the transparent/opaque tool setting - if ( theTextStyle.isBackgroundTransparent() ) + if ( theTextStyle.isBackgroundTransparent() ) { painter.fillRect(theWholeAreaRect, Qt::transparent); - else + } + else { painter.fillRect(theWholeAreaRect, theTextStyle.backgroundColor().toQColor()); + } painter.setClipRect(theWholeAreaRect); painter.setPen(theTextStyle.foregroundColor().toQColor()); painter.setFont(theTextStyle.font()); if ( theTextStyle.foregroundColor().toQColor().alpha() < 255 ) { // if the foreground color has an alpha channel, we want to // see through the background, so we first need to punch holes // into the background where the text is painter.setCompositionMode(QPainter::CompositionMode_Clear); int baseLine = theTextAreaRect.y () + fontMetrics.ascent (); - foreach (const QString &str, theTextLines) + for (const auto &str : theTextLines) { painter.drawText (theTextAreaRect.x (), baseLine, str); baseLine += fontMetrics.lineSpacing (); // if the next textline would already be below the visible text area, stop drawing - if ( (baseLine - fontMetrics.ascent()) > (theTextAreaRect.y() + theTextAreaRect.height()) ) + if ( (baseLine - fontMetrics.ascent()) > (theTextAreaRect.y() + theTextAreaRect.height()) ) { break; + } } // the next text drawing will now blend the text foreground color with // what is really below the text background painter.setCompositionMode(QPainter::CompositionMode_SourceOver); } // Draw a line at a time instead of using QPainter::drawText(QRect,...). // Else, the line heights become >QFontMetrics::height() if you type Chinese // characters (!) and then the cursor gets out of sync. int baseLine = theTextAreaRect.y () + fontMetrics.ascent (); kpPreeditText thePreeditText = preeditText(); if ( theTextLines.isEmpty() ) { if ( ! thePreeditText.isEmpty() ) { int x = theTextAreaRect.x(); drawPreeditString(painter, x, baseLine, thePreeditText); } } else { int i = 0; int row = thePreeditText.position().y(); int col = thePreeditText.position().x(); - foreach (const QString &str, theTextLines) + for (const auto &str : theTextLines) { if (row == i && !thePreeditText.isEmpty()) { QString left = str.left(col); QString right = str.mid(col); int x = theTextAreaRect.x(); painter.drawText(x, baseLine, left); x += fontMetrics.width(left); drawPreeditString(painter, x, baseLine, thePreeditText); painter.drawText(x, baseLine, right); } else { painter.drawText(theTextAreaRect.x (), baseLine, str); } baseLine += fontMetrics.lineSpacing(); i++; // if the next textline would already be below the visible text area, stop drawing - if ( (baseLine - fontMetrics.ascent()) > (theTextAreaRect.y() + theTextAreaRect.height()) ) + if ( (baseLine - fontMetrics.ascent()) > (theTextAreaRect.y() + theTextAreaRect.height()) ) { break; + } } } // ... convert that into "painting" transparent pixels on top of // the document. kpPixmapFX::paintPixmapAt (destPixmap, modifyingRect.topLeft () - docRect.topLeft (), floatImage); } //--------------------------------------------------------------------- // public virtual [kpAbstractSelection] void kpTextSelection::paintBorder (QImage *destPixmap, const QRect &docRect, bool selectionFinished) const { paintRectangularBorder (destPixmap, docRect, selectionFinished); } //--------------------------------------------------------------------- // public kpImage kpTextSelection::approximateImage () const { kpImage retImage (width (), height (), QImage::Format_ARGB32_Premultiplied); retImage.fill(0); paint (&retImage, boundingRect ()); return retImage; } //--------------------------------------------------------------------- diff --git a/layers/selections/text/kpTextStyle.cpp b/layers/selections/text/kpTextStyle.cpp index eaa1970a..5b05cafb 100644 --- a/layers/selections/text/kpTextStyle.cpp +++ b/layers/selections/text/kpTextStyle.cpp @@ -1,269 +1,267 @@ /* Copyright (c) 2003-2007 Clarence Dang All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include "layers/selections/text/kpTextStyle.h" #include #include #include kpTextStyle::kpTextStyle () : m_fontSize (0), m_isBold (false), m_isItalic (false), m_isUnderline (false), m_isStrikeThru (false), m_isBackgroundOpaque (true) { } kpTextStyle::kpTextStyle (const QString &fontFamily, int fontSize, bool isBold, bool isItalic, bool isUnderline, bool isStrikeThru, const kpColor &fcolor, const kpColor &bcolor, bool isBackgroundOpaque) : m_fontFamily (fontFamily), m_fontSize (fontSize), m_isBold (isBold), m_isItalic (isItalic), m_isUnderline (isUnderline), m_isStrikeThru (isStrikeThru), m_foregroundColor (fcolor), m_backgroundColor (bcolor), m_isBackgroundOpaque (isBackgroundOpaque) { } -kpTextStyle::~kpTextStyle () -{ -} +kpTextStyle::~kpTextStyle () = default; // friend QDataStream &operator<< (QDataStream &stream, const kpTextStyle &textStyle) { stream << textStyle.m_fontFamily; stream << textStyle.m_fontSize; stream << int (textStyle.m_isBold) << int (textStyle.m_isItalic) << int (textStyle.m_isUnderline) << int (textStyle.m_isStrikeThru); stream << textStyle.m_foregroundColor << textStyle.m_backgroundColor; stream << int (textStyle.m_isBackgroundOpaque); return stream; } // friend QDataStream &operator>> (QDataStream &stream, kpTextStyle &textStyle) { stream >> textStyle.m_fontFamily; stream >> textStyle.m_fontSize; int a, b, c, d; stream >> a >> b >> c >> d; textStyle.m_isBold = a; textStyle.m_isItalic = b; textStyle.m_isUnderline = c; textStyle.m_isStrikeThru = d; stream >> textStyle.m_foregroundColor >> textStyle.m_backgroundColor; int e; stream >> e; textStyle.m_isBackgroundOpaque = e; return stream; } // public bool kpTextStyle::operator== (const kpTextStyle &rhs) const { return (m_fontFamily == rhs.m_fontFamily && m_fontSize == rhs.m_fontSize && m_isBold == rhs.m_isBold && m_isItalic == rhs.m_isItalic && m_isUnderline == rhs.m_isUnderline && m_isStrikeThru == rhs.m_isStrikeThru && m_foregroundColor == rhs.m_foregroundColor && m_backgroundColor == rhs.m_backgroundColor && m_isBackgroundOpaque == rhs.m_isBackgroundOpaque); } // public bool kpTextStyle::operator!= (const kpTextStyle &rhs) const { return !(*this == rhs); } // public QString kpTextStyle::fontFamily () const { return m_fontFamily; } // public void kpTextStyle::setFontFamily (const QString &f) { m_fontFamily = f; } // public int kpTextStyle::fontSize () const { return m_fontSize; } // public void kpTextStyle::setFontSize (int s) { m_fontSize = s; } // public bool kpTextStyle::isBold () const { return m_isBold; } // public void kpTextStyle::setBold (bool yes) { m_isBold = yes; } // public bool kpTextStyle::isItalic () const { return m_isItalic; } // public void kpTextStyle::setItalic (bool yes) { m_isItalic = yes; } // public bool kpTextStyle::isUnderline () const { return m_isUnderline; } // public void kpTextStyle::setUnderline (bool yes) { m_isUnderline = yes; } // public bool kpTextStyle::isStrikeThru () const { return m_isStrikeThru; } // public void kpTextStyle::setStrikeThru (bool yes) { m_isStrikeThru = yes; } // public kpColor kpTextStyle::foregroundColor () const { return m_foregroundColor; } // public void kpTextStyle::setForegroundColor (const kpColor &fcolor) { m_foregroundColor = fcolor; } // public kpColor kpTextStyle::backgroundColor () const { return m_backgroundColor; } // public void kpTextStyle::setBackgroundColor (const kpColor &bcolor) { m_backgroundColor = bcolor; } // public bool kpTextStyle::isBackgroundOpaque () const { return m_isBackgroundOpaque; } // public void kpTextStyle::setBackgroundOpaque (bool yes) { m_isBackgroundOpaque = yes; } // public bool kpTextStyle::isBackgroundTransparent () const { return !m_isBackgroundOpaque; } // public void kpTextStyle::setBackgroundTransparent (bool yes) { m_isBackgroundOpaque = !yes; } // public QFont kpTextStyle::font () const { QFont fnt (m_fontFamily, m_fontSize); fnt.setBold (m_isBold); fnt.setItalic (m_isItalic); fnt.setUnderline (m_isUnderline); fnt.setStrikeOut (m_isStrikeThru); return fnt; } // public QFontMetrics kpTextStyle::fontMetrics () const { return QFontMetrics (font ()); } diff --git a/layers/tempImage/kpTempImage.cpp b/layers/tempImage/kpTempImage.cpp index 7a16dc54..32d9b358 100644 --- a/layers/tempImage/kpTempImage.cpp +++ b/layers/tempImage/kpTempImage.cpp @@ -1,218 +1,218 @@ /* Copyright (c) 2003-2007 Clarence Dang All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include "layers/tempImage/kpTempImage.h" #include "pixmapfx/kpPixmapFX.h" #include "views/manager/kpViewManager.h" #include //--------------------------------------------------------------------- kpTempImage::kpTempImage (bool isBrush, RenderMode renderMode, const QPoint &topLeft, const kpImage &image) : m_isBrush (isBrush), m_renderMode (renderMode), m_topLeft (topLeft), m_image (image), m_width (image.width ()), m_height (image.height ()), m_userFunction (nullptr), m_userData (nullptr) { // Use below constructor for that. Q_ASSERT (renderMode != UserFunction); } //--------------------------------------------------------------------- kpTempImage::kpTempImage (bool isBrush, const QPoint &topLeft, UserFunctionType userFunction, void *userData, int width, int height) : m_isBrush (isBrush), m_renderMode (UserFunction), m_topLeft (topLeft), m_width (width), m_height (height), m_userFunction (userFunction), m_userData (userData) { Q_ASSERT (m_userFunction); } //--------------------------------------------------------------------- kpTempImage::kpTempImage (const kpTempImage &rhs) : m_isBrush (rhs.m_isBrush), m_renderMode (rhs.m_renderMode), m_topLeft (rhs.m_topLeft), m_image (rhs.m_image), m_width (rhs.m_width), m_height (rhs.m_height), m_userFunction (rhs.m_userFunction), m_userData (rhs.m_userData) { } //--------------------------------------------------------------------- kpTempImage &kpTempImage::operator= (const kpTempImage &rhs) { - if (this == &rhs) + if (this == &rhs) { return *this; + } m_isBrush = rhs.m_isBrush; m_renderMode = rhs.m_renderMode; m_topLeft = rhs.m_topLeft; m_image = rhs.m_image; m_width = rhs.m_width; m_height = rhs.m_height; m_userFunction = rhs.m_userFunction; m_userData = rhs.m_userData; return *this; } //--------------------------------------------------------------------- // public bool kpTempImage::isBrush () const { return m_isBrush; } //--------------------------------------------------------------------- // public kpTempImage::RenderMode kpTempImage::renderMode () const { return m_renderMode; } //--------------------------------------------------------------------- // public QPoint kpTempImage::topLeft () const { return m_topLeft; } //--------------------------------------------------------------------- // public kpImage kpTempImage::image () const { return m_image; } //--------------------------------------------------------------------- // public kpTempImage::UserFunctionType kpTempImage::userFunction () const { return m_userFunction; } //--------------------------------------------------------------------- // public void *kpTempImage::userData () const { return m_userData; } //--------------------------------------------------------------------- // public bool kpTempImage::isVisible (const kpViewManager *vm) const { return m_isBrush ? static_cast (vm->viewUnderCursor ()) : true; } //--------------------------------------------------------------------- // public QRect kpTempImage::rect () const { - return QRect (m_topLeft.x (), m_topLeft.y (), - m_width, m_height); + return {m_topLeft.x (), m_topLeft.y (), m_width, m_height}; } //--------------------------------------------------------------------- // public int kpTempImage::width () const { return m_width; } //--------------------------------------------------------------------- // public int kpTempImage::height () const { return m_height; } //--------------------------------------------------------------------- // public bool kpTempImage::paintMayAddMask () const { return (m_renderMode == SetImage || m_renderMode == UserFunction); } //--------------------------------------------------------------------- // public void kpTempImage::paint (kpImage *destImage, const QRect &docRect) const { const QPoint REL_TOP_LEFT = m_topLeft - docRect.topLeft (); switch (m_renderMode) { case SetImage: { kpPixmapFX::setPixmapAt(destImage, REL_TOP_LEFT, m_image); break; } case PaintImage: { kpPixmapFX::paintPixmapAt(destImage, REL_TOP_LEFT, m_image); break; } case UserFunction: { m_userFunction(destImage, REL_TOP_LEFT, m_userData); break; } } } //--------------------------------------------------------------------- diff --git a/lgpl/generic/kpColorCollection.cpp b/lgpl/generic/kpColorCollection.cpp index 26725d6f..ab751105 100644 --- a/lgpl/generic/kpColorCollection.cpp +++ b/lgpl/generic/kpColorCollection.cpp @@ -1,509 +1,509 @@ // REFACT0R: Remote open/save file logic is duplicated in kpDocument. // HITODO: Test when remote file support in KDE 4 stabilizes /* This file is part of the KDE libraries Copyright (C) 1999 Waldo Bastian (bastian@kde.org) Copyright (C) 2007 Clarence Dang (dang@kde.org) This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as published by the Free Software Foundation; either version 2 of the License. This library 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 Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with this library; see the file COPYING.LIB. If not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ //----------------------------------------------------------------------------- // KDE color collection #define DEBUG_KP_COLOR_COLLECTION 0 #include "kpColorCollection.h" #include "kpUrlFormatter.h" #include // kdelibs4support #include #include #include "kpLogCategories.h" #include #include #include #include #include #include #include #include struct ColorNode { ColorNode(const QColor &c, const QString &n) : color(c), name(n) {} QColor color; QString name; }; //--------------------------------------------------------------------- //BEGIN kpColorCollectionPrivate class kpColorCollectionPrivate { public: kpColorCollectionPrivate(); kpColorCollectionPrivate(const kpColorCollectionPrivate&); QList colorList; QString name; QString desc; kpColorCollection::Editable editable; }; kpColorCollectionPrivate::kpColorCollectionPrivate() : editable(kpColorCollection::Yes) { } kpColorCollectionPrivate::kpColorCollectionPrivate(const kpColorCollectionPrivate& p) : colorList(p.colorList), name(p.name), desc(p.desc), editable(p.editable) { } //END kpColorCollectionPrivate //--------------------------------------------------------------------- QStringList kpColorCollection::installedCollections() { QStringList paletteList; QStringList paths = QStandardPaths::locateAll(QStandardPaths::GenericConfigLocation, "colors", QStandardPaths::LocateDirectory); - foreach (const QString &path, paths) { + for (const auto &path : paths) { paletteList.append(QDir(path).entryList(QStringList(), QDir::Files)); } return paletteList; } kpColorCollection::kpColorCollection() { d = new kpColorCollectionPrivate(); } kpColorCollection::kpColorCollection(const kpColorCollection &p) { d = new kpColorCollectionPrivate(*p.d); } kpColorCollection::~kpColorCollection() { // Need auto-save? delete d; } static void CouldNotOpenDialog (const QUrl &url, QWidget *parent) { KMessageBox::sorry (parent, i18n ("Could not open color palette \"%1\".", kpUrlFormatter::PrettyFilename (url))); } // TODO: Set d->editable? bool kpColorCollection::open(const QUrl &url, QWidget *parent) { QString tempPaletteFilePath; if (url.isEmpty () || !KIO::NetAccess::download (url, tempPaletteFilePath, parent)) { qCDebug(kpLogMisc) << "\tcould not download"; ::CouldNotOpenDialog (url, parent); return false; } // sync: remember to "KIO::NetAccess::removeTempFile (tempPaletteFilePath)" in all exit paths QFile paletteFile(tempPaletteFilePath); if (!paletteFile.exists() || !paletteFile.open(QIODevice::ReadOnly)) { qCDebug(kpLogMisc) << "\tcould not open qfile"; KIO::NetAccess::removeTempFile (tempPaletteFilePath); ::CouldNotOpenDialog (url, parent); return false; } // Read first line // Expected "GIMP Palette" QString line = QString::fromLocal8Bit(paletteFile.readLine()); if (line.indexOf(" Palette") == -1) { KIO::NetAccess::removeTempFile (tempPaletteFilePath); KMessageBox::sorry (parent, i18n ("Could not open color palette \"%1\" - unsupported format.\n" "The file may be corrupt.", kpUrlFormatter::PrettyFilename (url))); return false; } QList newColorList; QString newDesc; while( !paletteFile.atEnd() ) { line = QString::fromLocal8Bit(paletteFile.readLine()); if (line[0] == '#') { // This is a comment line line = line.mid(1); // Strip '#' line = line.trimmed(); // Strip remaining white space.. if (!line.isEmpty()) { newDesc += line+'\n'; // Add comment to description } } else { // This is a color line, hopefully line = line.trimmed(); if (line.isEmpty()) continue; int r, g, b; int pos = 0; if (sscanf(line.toLatin1(), "%d %d %d%n", &r, &g, &b, &pos) >= 3) { r = qBound(0, r, 255); g = qBound(0, g, 255); b = qBound(0, b, 255); QString name = line.mid(pos).trimmed(); newColorList.append(ColorNode(QColor(r, g, b), name)); } } } d->colorList = newColorList; d->name.clear (); d->desc = newDesc; KIO::NetAccess::removeTempFile (tempPaletteFilePath); return true; } static void CouldNotOpenKDEDialog (const QString &name, QWidget *parent) { KMessageBox::sorry (parent, i18n ("Could not open KDE color palette \"%1\".", name)); } bool kpColorCollection::openKDE(const QString &name, QWidget *parent) { qCDebug(kpLogMisc) << "name=" << name; if (name.isEmpty()) { qCDebug(kpLogMisc) << "name.isEmpty"; ::CouldNotOpenKDEDialog (name, parent); return false; } QString filename = QStandardPaths::locate(QStandardPaths::GenericConfigLocation, "colors/" + name); if (filename.isEmpty()) { qCDebug(kpLogMisc) << "could not find file"; ::CouldNotOpenKDEDialog (name, parent); return false; } // (this will pop up an error dialog on failure) if (!open (QUrl::fromLocalFile (filename), parent)) { qCDebug(kpLogMisc) << "could not open"; return false; } d->name = name; qCDebug(kpLogMisc) << "opened"; return true; } static void CouldNotSaveDialog (const QUrl &url, QWidget *parent) { // TODO: use file.errorString() KMessageBox::error (parent, i18n ("Could not save color palette as \"%1\".", kpUrlFormatter::PrettyFilename (url))); } static void SaveToFile (kpColorCollectionPrivate *d, QIODevice *device) { // HITODO: QTextStream can fail but does not report errors. // Bug in KColorCollection too. QTextStream str (device); QString description = d->desc.trimmed(); description = '#'+description.split( '\n', QString::KeepEmptyParts).join("\n#"); str << "KDE RGB Palette\n"; str << description << "\n"; - foreach (const ColorNode &node, d->colorList) + for (const auto &node : d->colorList) { // Added for KolourPaint. if(!node.color.isValid ()) continue; int r,g,b; node.color.getRgb(&r, &g, &b); str << r << " " << g << " " << b << " " << node.name << "\n"; } str.flush(); } bool kpColorCollection::saveAs(const QUrl &url, bool showOverwritePrompt, QWidget *parent) const { if (showOverwritePrompt && KIO::NetAccess::exists (url, KIO::NetAccess::DestinationSide/*write*/, parent)) { int result = KMessageBox::warningContinueCancel (parent, i18n ("A color palette called \"%1\" already exists.\n" "Do you want to overwrite it?", kpUrlFormatter::PrettyFilename (url)), QString (), KStandardGuiItem::overwrite ()); if (result != KMessageBox::Continue) return false; } if (url.isLocalFile ()) { const QString filename = url.toLocalFile (); // sync: All failure exit paths _must_ call QSaveFile::cancelWriting() or // else, the QSaveFile destructor will overwrite the file, // , despite the failure. QSaveFile atomicFileWriter (filename); { if (!atomicFileWriter.open (QIODevice::WriteOnly)) { // We probably don't need this as has not been // opened. atomicFileWriter.cancelWriting (); qCDebug(kpLogMisc) << "\treturning false because could not open QSaveFile" - << " error=" << atomicFileWriter.error () << endl; + << " error=" << atomicFileWriter.error (); ::CouldNotSaveDialog (url, parent); return false; } // Write to local temporary file. ::SaveToFile (d, &atomicFileWriter); // Atomically overwrite local file with the temporary file // we saved to. if (!atomicFileWriter.commit ()) { atomicFileWriter.cancelWriting (); qCDebug(kpLogMisc) << "\tcould not close QSaveFile"; ::CouldNotSaveDialog (url, parent); return false; } } // sync QSaveFile.cancelWriting() } // Remote file? else { // Create temporary file that is deleted when the variable goes // out of scope. QTemporaryFile tempFile; if (!tempFile.open ()) { qCDebug(kpLogMisc) << "\treturning false because could not open tempFile"; ::CouldNotSaveDialog (url, parent); return false; } // Write to local temporary file. ::SaveToFile (d, &tempFile); // Collect name of temporary file now, as QTemporaryFile::fileName() // stops working after close() is called. const QString tempFileName = tempFile.fileName (); qCDebug(kpLogMisc) << "\ttempFileName='" << tempFileName << "'"; Q_ASSERT (!tempFileName.isEmpty ()); tempFile.close (); if (tempFile.error () != QFile::NoError) { qCDebug(kpLogMisc) << "\treturning false because could not close"; ::CouldNotSaveDialog (url, parent); return false; } // Copy local temporary file to overwrite remote. // TODO: No one seems to know how to do this atomically // [http://lists.kde.org/?l=kde-core-devel&m=117845162728484&w=2]. // At least, fish:// (ssh) is definitely not atomic. if (!KIO::NetAccess::upload (tempFileName, url, parent)) { qCDebug(kpLogMisc) << "\treturning false because could not upload"; ::CouldNotSaveDialog (url, parent); return false; } } d->name.clear (); return true; } bool kpColorCollection::saveKDE(QWidget *parent) const { const QString name = d->name; QString filename = QStandardPaths::writableLocation(QStandardPaths::GenericConfigLocation) + "colors/" + name; const bool ret = saveAs (QUrl::fromLocalFile (filename), false/*no overwite prompt*/, parent); // (d->name is wiped by saveAs()). d->name = name; return ret; } QString kpColorCollection::description() const { return d->desc; } void kpColorCollection::setDescription(const QString &desc) { d->desc = desc; } QString kpColorCollection::name() const { return d->name; } void kpColorCollection::setName(const QString &name) { d->name = name; } kpColorCollection::Editable kpColorCollection::editable() const { return d->editable; } void kpColorCollection::setEditable(Editable editable) { d->editable = editable; } int kpColorCollection::count() const { return (int) d->colorList.count(); } void kpColorCollection::resize(int newCount) { if (newCount == count()) return; else if (newCount < count()) { d->colorList.erase(d->colorList.begin() + newCount, d->colorList.end()); } else if (newCount > count()) { while(newCount > count()) { const int ret = addColor(QColor(), QString()/*color name*/); Q_ASSERT(ret == count() - 1); } } } kpColorCollection& kpColorCollection::operator=( const kpColorCollection &p) { if (&p == this) return *this; d->colorList = p.d->colorList; d->name = p.d->name; d->desc = p.d->desc; d->editable = p.d->editable; return *this; } QColor kpColorCollection::color(int index) const { if ((index < 0) || (index >= count())) return QColor(); return d->colorList[index].color; } int kpColorCollection::findColor(const QColor &color) const { for (int i = 0; i < d->colorList.size(); ++i) { if (d->colorList[i].color == color) return i; } return -1; } QString kpColorCollection::name(int index) const { if ((index < 0) || (index >= count())) return QString(); return d->colorList[index].name; } QString kpColorCollection::name(const QColor &color) const { return name(findColor(color)); } int kpColorCollection::addColor(const QColor &newColor, const QString &newColorName) { d->colorList.append(ColorNode(newColor, newColorName)); return count() - 1; } int kpColorCollection::changeColor(int index, const QColor &newColor, const QString &newColorName) { if ((index < 0) || (index >= count())) return -1; ColorNode& node = d->colorList[index]; node.color = newColor; node.name = newColorName; return index; } int kpColorCollection::changeColor(const QColor &oldColor, const QColor &newColor, const QString &newColorName) { return changeColor( findColor(oldColor), newColor, newColorName); } diff --git a/lgpl/generic/widgets/kpColorCellsBase.cpp b/lgpl/generic/widgets/kpColorCellsBase.cpp index 66a7a8f7..b66907c6 100644 --- a/lgpl/generic/widgets/kpColorCellsBase.cpp +++ b/lgpl/generic/widgets/kpColorCellsBase.cpp @@ -1,545 +1,543 @@ /* This file is part of the KDE libraries Copyright (C) 1997 Martin Jones (mjones@kde.org) Copyright (C) 2007 Roberto Raggi (roberto@kdevelop.org) Copyright (C) 2007 Clarence Dang (dang@kde.org) This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This library 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 Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with this library; see the file COPYING.LIB. If not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ //----------------------------------------------------------------------------- #define DEBUG_KP_COLOR_CELLS_BASE 0 #include "kpColorCellsBase.h" #include #include #include #include #include #include #include #include #include #include #include "kpLogCategories.h" #include class kpColorCellsBase::kpColorCellsBasePrivate { public: kpColorCellsBasePrivate(kpColorCellsBase *q): q(q) { colors = nullptr; inMouse = false; selected = -1; shade = false; acceptDrags = false; cellsResizable = true; } kpColorCellsBase *q; // Note: This is a good thing and is _not_ data duplication with the // colors of QTableWidget cells, for the following reasons: // // 1. QColor in Qt4 is full-quality RGB. However, QTableWidget // cells are lossy as their colors may be dithered on the screen. // // Eventually, this field will be changed to a kpColor. // // 2. We change the QTableWidget cells' colors when the widget is // disabled (see changeEvent()). // // Therefore, do not remove this field without better reasons. QColor *colors; QPoint mousePos; int selected; bool shade; bool acceptDrags; bool cellsResizable; bool inMouse; }; kpColorCellsBase::kpColorCellsBase( QWidget *parent, int rows, int cols ) : QTableWidget( parent ), d(new kpColorCellsBasePrivate(this)) { setItemDelegate(new QItemDelegate(this)); setFrameShape(QFrame::NoFrame); d->shade = true; setRowCount( rows ); setColumnCount( cols ); verticalHeader()->setMinimumSectionSize(16); verticalHeader()->hide(); horizontalHeader()->setMinimumSectionSize(16); horizontalHeader()->hide(); d->colors = new QColor [ rows * cols ]; d->selected = 0; d->inMouse = false; // Drag'n'Drop setAcceptDrops( true); setHorizontalScrollBarPolicy( Qt::ScrollBarAlwaysOff ); setVerticalScrollBarPolicy( Qt::ScrollBarAlwaysOff ); viewport()->setBackgroundRole( QPalette::Window ); setBackgroundRole( QPalette::Window ); } kpColorCellsBase::~kpColorCellsBase() { delete [] d->colors; delete d; } void kpColorCellsBase::invalidateAllColors () { for (int r = 0; r < rowCount (); r++) for (int c = 0; c < columnCount (); c++) d->colors [r * columnCount () + c] = QColor (); } void kpColorCellsBase::clear() { invalidateAllColors (); QTableWidget::clear (); } void kpColorCellsBase::clearContents() { invalidateAllColors (); QTableWidget::clearContents (); } void kpColorCellsBase::setRowColumnCounts (int rows, int columns) { const int oldRows = rowCount (), oldCols = columnCount (); const int newRows = rows, newCols = columns; qCDebug(kpLogMisc) << "oldRows=" << oldRows << "oldCols=" << oldCols << "newRows=" << newRows << "newCols=" << newCols; if (oldRows == newRows && oldCols == newCols) return; QTableWidget::setColumnCount (newCols); QTableWidget::setRowCount (newRows); QColor *oldColors = d->colors; d->colors = new QColor [newRows * newCols]; for (int r = 0; r < qMin (oldRows, newRows); r++) for (int c = 0; c < qMin (oldCols, newCols); c++) d->colors [r * newCols + c] = oldColors [r * oldCols + c]; delete [] oldColors; } void kpColorCellsBase::setColumnCount (int newColumns) { setRowColumnCounts (rowCount (), newColumns); } void kpColorCellsBase::setRowCount (int newRows) { setRowColumnCounts (newRows, columnCount ()); } QColor kpColorCellsBase::color(int index) const { return d->colors[index]; } int kpColorCellsBase::count() const { return rowCount() * columnCount(); } void kpColorCellsBase::setShading(bool _shade) { d->shade = _shade; } void kpColorCellsBase::setAcceptDrags(bool _acceptDrags) { d->acceptDrags = _acceptDrags; } void kpColorCellsBase::setCellsResizable(bool yes) { d->cellsResizable = yes; } void kpColorCellsBase::setSelected(int index) { Q_ASSERT( index >= 0 && index < count() ); d->selected = index; } int kpColorCellsBase::selectedIndex() const { return d->selected; } //--------------------------------------------------------------------- static void TableWidgetItemSetColor (QTableWidgetItem *tableItem, const QColor &color) { Q_ASSERT (tableItem); QImage image(16, 16, QImage::Format_ARGB32_Premultiplied); QPainter painter(&image); const int StippleSize = 4; QColor useColor; for (int dy = 0; dy < 16; dy += StippleSize) { for (int dx = 0; dx < 16; dx += StippleSize) { const bool parity = ((dy + dx) / StippleSize) % 2; if (!parity) useColor = Qt::white; else useColor = Qt::lightGray; painter.fillRect(dx, dy, StippleSize, StippleSize, useColor); } } painter.fillRect(image.rect(), color); painter.end(); tableItem->setData(Qt::BackgroundRole , QBrush(image)); } //--------------------------------------------------------------------- void kpColorCellsBase::setColor( int column, const QColor &colorIn ) { const int tableRow = column / columnCount(); const int tableColumn = column % columnCount(); Q_ASSERT( tableRow >= 0 && tableRow < rowCount() ); Q_ASSERT( tableColumn >= 0 && tableColumn < columnCount() ); QColor color = colorIn; d->colors[column] = color; QTableWidgetItem* tableItem = item(tableRow,tableColumn); if (color.isValid ()) { if ( tableItem == nullptr ) { tableItem = new QTableWidgetItem(); setItem(tableRow,tableColumn,tableItem); } if (isEnabled ()) ::TableWidgetItemSetColor (tableItem, color); } else { delete tableItem; } emit colorChanged (column, color); } void kpColorCellsBase::changeEvent( QEvent* event ) { QTableWidget::changeEvent (event); if (event->type () != QEvent::EnabledChange) return; for (int r = 0; r < rowCount (); r++) { for (int c = 0; c < columnCount (); c++) { const int index = r * columnCount () + c; QTableWidgetItem* tableItem = item(r, c); // See API Doc for this invariant. Q_ASSERT (!!tableItem == d->colors [index].isValid ()); if (!tableItem) continue; QColor color; if (isEnabled ()) color = d->colors [index]; else color = palette ().color (backgroundRole ()); ::TableWidgetItemSetColor (tableItem, color); } } } /*void kpColorCellsBase::paintCell( QPainter *painter, int row, int col ) { painter->setRenderHint( QPainter::Antialiasing , true ); QBrush brush; int w = 1; if (shade) { qDrawShadePanel( painter, 1, 1, cellWidth()-2, cellHeight()-2, palette(), true, 1, &brush ); w = 2; } QColor color = colors[ row * numCols() + col ]; if (!color.isValid()) { if (!shade) return; color = palette().color(backgroundRole()); } const QRect colorRect( w, w, cellWidth()-w*2, cellHeight()-w*2 ); painter->fillRect( colorRect, color ); if ( row * numCols() + col == selected ) { painter->setPen( qGray(color.rgb())>=127 ? Qt::black : Qt::white ); painter->drawLine( colorRect.topLeft(), colorRect.bottomRight() ); painter->drawLine( colorRect.topRight(), colorRect.bottomLeft() ); } }*/ void kpColorCellsBase::resizeEvent( QResizeEvent* e ) { if (d->cellsResizable) { // According to the Qt doc: // If you need to set the width of a given column to a fixed value, call // QHeaderView::resizeSection() on the table's {horizontal,vertical} // header. // Therefore we iterate over each row and column and set the header section // size, as the sizeHint does indeed appear to be ignored in favor of a // minimum size that is larger than what we want. for ( int index = 0 ; index < columnCount() ; index++ ) horizontalHeader()->resizeSection( index, sizeHintForColumn(index) ); for ( int index = 0 ; index < rowCount() ; index++ ) verticalHeader()->resizeSection( index, sizeHintForRow(index) ); } else { // Update scrollbars if they're forced on by a subclass. // TODO: Should the d->cellsResizable path (from kdelibs) do this as well? QTableWidget::resizeEvent (e); } } int kpColorCellsBase::sizeHintForColumn(int /*column*/) const { // TODO: Should it be "(width() - frameWidth() * 2) / columnCount()"? return width() / columnCount() ; } int kpColorCellsBase::sizeHintForRow(int /*row*/) const { // TODO: Should be "(height() - frameWidth() * 2) / rowCount()"? return height() / rowCount() ; } void kpColorCellsBase::mousePressEvent( QMouseEvent *e ) { d->inMouse = true; d->mousePos = e->pos(); } int kpColorCellsBase::positionToCell(const QPoint &pos, bool ignoreBorders, bool allowEmptyCell) const { //TODO ignoreBorders not yet handled Q_UNUSED( ignoreBorders ) const int r = indexAt (pos).row (), c = indexAt (pos).column (); qCDebug(kpLogMisc) << "r=" << r << "c=" << c; if (r == -1 || c == -1) return -1; if (!allowEmptyCell && !itemAt(pos)) return -1; const int cell = r * columnCount() + c; /*if (!ignoreBorders) { int border = 2; int x = pos.x() - col * cellWidth(); int y = pos.y() - row * cellHeight(); if ( (x < border) || (x > cellWidth()-border) || (y < border) || (y > cellHeight()-border)) return -1; }*/ return cell; } void kpColorCellsBase::mouseMoveEvent( QMouseEvent *e ) { if( !(e->buttons() & Qt::LeftButton)) return; if(d->inMouse) { int delay = QApplication::startDragDistance(); if(e->x() > d->mousePos.x()+delay || e->x() < d->mousePos.x()-delay || e->y() > d->mousePos.y()+delay || e->y() < d->mousePos.y()-delay){ // Drag color object int cell = positionToCell(d->mousePos); if (cell != -1) { qCDebug(kpLogMisc) << "beginning drag from cell=" << cell << "color: isValid=" << d->colors [cell].isValid () << " rgba=" << (int *) d->colors [cell].rgba(); Q_ASSERT (d->colors[cell].isValid()); KColorMimeData::createDrag(d->colors[cell], this)->start(Qt::CopyAction | Qt::MoveAction); qCDebug(kpLogMisc) << "finished drag"; } } } } // LOTODO: I'm not quite clear on how the drop actions logic is supposed // to be done e.g.: // // 1. Who is supposed to call setDropAction(). // 2. Which variant of accept(), setAccepted(), acceptProposedAction() etc. // is supposed to be called to accept a move -- rather than copy -- // action. // // Nevertheless, it appears to work -- probably because we restrict // the non-Qt-default move/swap action to be intrawidget. static void SetDropAction (QWidget *self, QDropEvent *event) { // TODO: Would be nice to default to CopyAction if the destination cell // is null. if (event->source () == self && (event->keyboardModifiers () & Qt::ControlModifier) == 0) event->setDropAction(Qt::MoveAction); else event->setDropAction(Qt::CopyAction); } void kpColorCellsBase::dragEnterEvent( QDragEnterEvent *event) { qCDebug(kpLogMisc) << "kpColorCellsBase::dragEnterEvent() acceptDrags=" << d->acceptDrags - << " canDecode=" << KColorMimeData::canDecode(event->mimeData()) - << endl; + << " canDecode=" << KColorMimeData::canDecode(event->mimeData()); event->setAccepted( d->acceptDrags && KColorMimeData::canDecode( event->mimeData())); if (event->isAccepted ()) ::SetDropAction (this, event); } // Reimplemented to override QTableWidget's override. Else dropping doesn't work. void kpColorCellsBase::dragMoveEvent (QDragMoveEvent *event) { qCDebug(kpLogMisc) << "kpColorCellsBase::dragMoveEvent() acceptDrags=" << d->acceptDrags - << " canDecode=" << KColorMimeData::canDecode(event->mimeData()) - << endl; + << " canDecode=" << KColorMimeData::canDecode(event->mimeData()); // TODO: Disallow drag that isn't onto a cell. event->setAccepted( d->acceptDrags && KColorMimeData::canDecode( event->mimeData())); if (event->isAccepted ()) ::SetDropAction (this, event); } void kpColorCellsBase::dropEvent( QDropEvent *event) { QColor c=KColorMimeData::fromMimeData(event->mimeData()); const int dragSourceCell = event->source () == this ? positionToCell (d->mousePos, true) : -1; qCDebug(kpLogMisc) << "kpColorCellsBase::dropEvent()" << "color: rgba=" << (const int *) c.rgba () << "isValid=" << c.isValid() << "source=" << event->source () << "dragSourceCell=" << dragSourceCell; if( c.isValid()) { ::SetDropAction (this, event); int cell = positionToCell(event->pos(), true, true/*allow empty cell*/); qCDebug(kpLogMisc) << "\tcell=" << cell; // TODO: I believe kdelibs forgets to do this. if (cell == -1) return; // Avoid NOP. if (cell == dragSourceCell) return; QColor destOldColor = d->colors [cell]; setColor(cell,c); qCDebug(kpLogMisc) << "\tdropAction=" << event->dropAction () << "destOldColor.rgba=" << (const int *) destOldColor.rgba (); if (event->dropAction () == Qt::MoveAction && dragSourceCell != -1) { setColor(dragSourceCell, destOldColor); } } } void kpColorCellsBase::mouseReleaseEvent( QMouseEvent *e ) { int cell = positionToCell(d->mousePos); int currentCell = positionToCell(e->pos()); // If we release the mouse in another cell and we don't have // a drag we should ignore this event. if (currentCell != cell) cell = -1; if ( (cell != -1) && (d->selected != cell) ) { d->selected = cell; const int newRow = cell/columnCount(); const int newColumn = cell%columnCount(); clearSelection(); // we do not want old violet selected cells item(newRow,newColumn)->setSelected(true); } d->inMouse = false; if (cell != -1) { emit colorSelected( cell , color(cell) ); emit colorSelectedWhitButton( cell , color(cell), e->button() ); } } void kpColorCellsBase::mouseDoubleClickEvent( QMouseEvent * /*e*/ ) { int cell = positionToCell(d->mousePos, false, true/*allow empty cell*/); if (cell != -1) emit colorDoubleClicked( cell , color(cell) ); } diff --git a/mainWindow/kpMainWindow.cpp b/mainWindow/kpMainWindow.cpp index 73532300..136797e8 100644 --- a/mainWindow/kpMainWindow.cpp +++ b/mainWindow/kpMainWindow.cpp @@ -1,870 +1,872 @@ /* Copyright (c) 2003-2007 Clarence Dang All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include "kpMainWindow.h" #include "kpMainWindowPrivate.h" #include "layers/selections/image/kpAbstractImageSelection.h" #include "environments/commands/kpCommandEnvironment.h" #include "environments/tools/kpToolEnvironment.h" #include "widgets/kpColorCells.h" #include "widgets/toolbars/kpColorToolBar.h" #include "commands/kpCommandHistory.h" #include "kpDefs.h" #include "document/kpDocument.h" #include "environments/document/kpDocumentEnvironment.h" #include "layers/selections/kpSelectionDrag.h" #include "kpThumbnail.h" #include "tools/kpTool.h" #include "widgets/toolbars/kpToolToolBar.h" #include "views/manager/kpViewManager.h" #include "kpViewScrollableContainer.h" #include "generic/kpWidgetMapper.h" #include "views/kpZoomedThumbnailView.h" #include "views/kpZoomedView.h" #include #include #include #include #include #include #include "kpLogCategories.h" //--------------------------------------------------------------------- kpMainWindow::kpMainWindow () : KXmlGuiWindow (nullptr/*parent*/) { init (); open (QUrl (), true/*create an empty doc*/); d->isFullyConstructed = true; } //--------------------------------------------------------------------- kpMainWindow::kpMainWindow (const QUrl &url) : KXmlGuiWindow (nullptr/*parent*/) { init (); open (url, true/*create an empty doc with the same url if url !exist*/); d->isFullyConstructed = true; } //--------------------------------------------------------------------- kpMainWindow::kpMainWindow (kpDocument *newDoc) : KXmlGuiWindow (nullptr/*parent*/) { init (); setDocument (newDoc); d->isFullyConstructed = true; } //--------------------------------------------------------------------- // TODO: Move into appropriate kpMainWindow_*.cpp or another class // private void kpMainWindow::readGeneralSettings () { qCDebug(kpLogMainWindow) << "\tkpMainWindow(" << objectName () << ")::readGeneralSettings()"; KConfigGroup cfg (KSharedConfig::openConfig (), kpSettingsGroupGeneral); d->configFirstTime = cfg.readEntry (kpSettingFirstTime, true); d->configShowGrid = cfg.readEntry (kpSettingShowGrid, false); d->configShowPath = cfg.readEntry (kpSettingShowPath, false); d->moreEffectsDialogLastEffect = cfg.readEntry (kpSettingMoreEffectsLastEffect, 0); kpToolEnvironment::drawAntiAliased = cfg.readEntry(kpSettingDrawAntiAliased, true); if (cfg.hasKey (kpSettingOpenImagesInSameWindow)) { d->configOpenImagesInSameWindow = cfg.readEntry (kpSettingOpenImagesInSameWindow, false); } else { d->configOpenImagesInSameWindow = false; qCDebug(kpLogMainWindow) << "\tconfigOpenImagesInSameWindow: first time" - << " - writing default: " << d->configOpenImagesInSameWindow - << endl; + << " - writing default: " << d->configOpenImagesInSameWindow; // TODO: More hidden options have to write themselves out on startup, // not on use, to be discoverable (e.g. printing centered on page). cfg.writeEntry (kpSettingOpenImagesInSameWindow, d->configOpenImagesInSameWindow); cfg.sync (); } d->configPrintImageCenteredOnPage = cfg.readEntry (kpSettingPrintImageCenteredOnPage, true); qCDebug(kpLogMainWindow) << "\t\tGeneral Settings: firstTime=" << d->configFirstTime << " showGrid=" << d->configShowGrid << " showPath=" << d->configShowPath << " moreEffectsDialogLastEffect=" << d->moreEffectsDialogLastEffect << " openImagesInSameWindow=" << d->configOpenImagesInSameWindow << " printImageCenteredOnPage=" << d->configPrintImageCenteredOnPage; } //--------------------------------------------------------------------- // private void kpMainWindow::readThumbnailSettings () { qCDebug(kpLogMainWindow) << "\tkpMainWindow(" << objectName () << ")::readThumbnailSettings()"; KConfigGroup cfg (KSharedConfig::openConfig (), kpSettingsGroupThumbnail); d->configThumbnailShown = cfg.readEntry (kpSettingThumbnailShown, false); d->configThumbnailGeometry = cfg.readEntry (kpSettingThumbnailGeometry, QRect ()); d->configZoomedThumbnail = cfg.readEntry (kpSettingThumbnailZoomed, true); d->configThumbnailShowRectangle = cfg.readEntry (kpSettingThumbnailShowRectangle, true); qCDebug(kpLogMainWindow) << "\t\tThumbnail Settings: shown=" << d->configThumbnailShown << " geometry=" << d->configThumbnailGeometry << " zoomed=" << d->configZoomedThumbnail - << " showRectangle=" << d->configThumbnailShowRectangle - << endl; + << " showRectangle=" << d->configThumbnailShowRectangle; } //--------------------------------------------------------------------- void kpMainWindow::finalizeGUI(KXMLGUIClient *client) { if ( client == this ) { const QList menuToHide = findChildren("toolToolBarHiddenMenu"); // should only contain one but... - foreach (QMenu *menu, menuToHide) + for (auto *menu : menuToHide) { menu->menuAction()->setVisible(false); } } } //--------------------------------------------------------------------- // private void kpMainWindow::init () { qCDebug(kpLogMainWindow) << "kpMainWindow(" << objectName () << ")::init()"; QTime totalTime; totalTime.start (); d = new kpMainWindowPrivate; // // set mainwindow properties // setMinimumSize (320, 260); setAcceptDrops (true); // // read config // // KConfig::readEntry() does not actually reread from disk, hence doesn't // realize what other processes have done e.g. Settings / Show Path KSharedConfig::openConfig ()->reparseConfiguration (); readGeneralSettings (); readThumbnailSettings (); // // create GUI // setupActions (); createStatusBar (); createGUI (); createColorBox (); createToolBox (); // Let the Tool Box take all the vertical space, since it can be quite // tall with all its tool option widgets. This also avoids occasional // bugs like the Tool Box overlapping the Color Tool Bar. setCorner(Qt::BottomLeftCorner, Qt::LeftDockWidgetArea); setCorner(Qt::BottomRightCorner, Qt::RightDockWidgetArea); // no tabbed docks; does not make sense with only 2 dock widgets setDockOptions(QMainWindow::AnimatedDocks | QMainWindow::AllowNestedDocks); addDockWidget(Qt::BottomDockWidgetArea, d->colorToolBar, Qt::Horizontal); d->scrollView = new kpViewScrollableContainer (this); d->scrollView->setObjectName ( QLatin1String("scrollView" )); connect (d->scrollView, &kpViewScrollableContainer::beganDocResize, this, &kpMainWindow::slotBeganDocResize); connect (d->scrollView, &kpViewScrollableContainer::continuedDocResize, this, &kpMainWindow::slotContinuedDocResize); connect (d->scrollView, &kpViewScrollableContainer::cancelledDocResize, this, &kpMainWindow::slotCancelledDocResize); connect (d->scrollView, &kpViewScrollableContainer::endedDocResize, this, &kpMainWindow::slotEndedDocResize); connect (d->scrollView, &kpViewScrollableContainer::statusMessageChanged, this, &kpMainWindow::slotDocResizeMessageChanged); connect (d->scrollView, &kpViewScrollableContainer::contentsMoved, this, &kpMainWindow::slotScrollViewAfterScroll); setCentralWidget (d->scrollView); // // set initial pos/size of GUI // setAutoSaveSettings (); // our non-XMLGUI tools-toolbar will get initially the toolButtonStyle as // all other toolbars, but we want to show only icons for the tools by default // (have to do this _after_ setAutoSaveSettings as that applies the default settings) if (d->configFirstTime) { d->toolToolBar->setToolButtonStyle(Qt::ToolButtonIconOnly); KConfigGroup cfg(KSharedConfig::openConfig(), kpSettingsGroupGeneral); cfg.writeEntry(kpSettingFirstTime, d->configFirstTime = false); cfg.sync(); } qCDebug(kpLogMainWindow) << "\tall done in " << totalTime.elapsed () << "msec"; } //--------------------------------------------------------------------- // private virtual [base KMainWindow] void kpMainWindow::readProperties (const KConfigGroup &configGroup) { qCDebug(kpLogMainWindow) << "kpMainWindow<" << this << ">::readProperties()"; // No document at all? if (!configGroup.hasKey (kpSessionSettingDocumentUrl)) { qCDebug(kpLogMainWindow) << "\tno url - no document"; setDocument (nullptr); } // Have a document. else { const QUrl url = QUrl (configGroup.readEntry (kpSessionSettingDocumentUrl, QString ())); qCDebug(kpLogMainWindow) << "\turl=" << url; const QSize notFromURLDocSize = configGroup.readEntry (kpSessionSettingNotFromUrlDocumentSize, QSize ()); // Is from URL? if (notFromURLDocSize.isEmpty ()) { // If this fails, the empty document that kpMainWindow::kpMainWindow() // created is left untouched. openInternal (url, defaultDocSize (), false/*show error message if url !exist*/); } // Not from URL? else { qCDebug(kpLogMainWindow) << "\tnot from url; doc size=" << notFromURLDocSize; // Either we have an empty URL or we have a "kolourpaint doesnotexist.png" // URL. Regarding the latter case, if a file now actually exists at that // URL, we do open it - ignoring notFromURLDocSize - to avoid putting // the user in a situation where he might accidentally overwrite an // existing file. openInternal (url, notFromURLDocSize, true/*create an empty doc with the same url if url !exist*/); } } } //--------------------------------------------------------------------- // private virtual [base KMainWindow] // WARNING: KMainWindow API Doc says "No user interaction is allowed // in this function!" void kpMainWindow::saveProperties (KConfigGroup &configGroup) { qCDebug(kpLogMainWindow) << "kpMainWindow<" << this << ">::saveProperties()"; // No document at all? if (!d->document) { qCDebug(kpLogMainWindow) << "\tno url - no document"; } // Have a document. else { // Save URL in all cases: // // a) d->document->isFromURL() // b) !d->document->isFromURL() [save size in this case] // i) No URL // ii) URL (from "kolourpaint doesnotexist.png") const QUrl url = d->document->url (); qCDebug(kpLogMainWindow) << "\turl=" << url; configGroup.writeEntry (kpSessionSettingDocumentUrl, url.url ()); // Not from URL e.g. "kolourpaint doesnotexist.png"? // // Note that "kolourpaint doesexist.png" is considered to be from // a URL even if it was deleted in the background (hence the // "false" arg to isFromURL()). This is because the user expects // it to be from a URL, so when we session restore, we pop up a // "cannot find file" dialog, instead of silently creating a new, // blank document. if (!d->document->isFromURL (false/*don't bother checking exists*/)) { // If we don't have a URL either: // // a) it was not modified - so we can use either width() or // constructorWidth() (they'll be equal). // b) the changes were discarded so we use the initial width, // constructorWidth(). // // Similarly for height() and constructorHeight(). const QSize docSize (d->document->constructorWidth (), d->document->constructorHeight ()); qCDebug(kpLogMainWindow) << "\tnot from url; doc size=" << docSize; configGroup.writeEntry (kpSessionSettingNotFromUrlDocumentSize, docSize); } } } //--------------------------------------------------------------------- kpMainWindow::~kpMainWindow () { d->isFullyConstructed = false; // Get the kpTool to finish up. This makes sure that the kpTool destructor // will not need to access any other class (that might be deleted before // the destructor is called by the QObject child-deletion mechanism). - if (tool ()) + if (tool ()) { tool ()->endInternal (); + } // Delete document & views. // Note: This will disconnects signals from the current kpTool, so kpTool // must not be destructed yet. setDocument (nullptr); delete d->commandHistory; d->commandHistory = nullptr; delete d->scrollView; d->scrollView = nullptr; delete d; d = nullptr; } //--------------------------------------------------------------------- // public kpDocument *kpMainWindow::document () const { return d->document; } //--------------------------------------------------------------------- // public kpDocumentEnvironment *kpMainWindow::documentEnvironment () { - if (!d->documentEnvironment) + if (!d->documentEnvironment) { d->documentEnvironment = new kpDocumentEnvironment (this); + } return d->documentEnvironment; } //--------------------------------------------------------------------- // public kpViewManager *kpMainWindow::viewManager () const { return d->viewManager; } //--------------------------------------------------------------------- // public kpColorToolBar *kpMainWindow::colorToolBar () const { return d->colorToolBar; } //--------------------------------------------------------------------- // public kpColorCells *kpMainWindow::colorCells () const { return d->colorToolBar ? d->colorToolBar->colorCells () : nullptr; } //--------------------------------------------------------------------- // public kpToolToolBar *kpMainWindow::toolToolBar () const { return d->toolToolBar; } //--------------------------------------------------------------------- // public kpCommandHistory *kpMainWindow::commandHistory () const { return d->commandHistory; } //--------------------------------------------------------------------- kpCommandEnvironment *kpMainWindow::commandEnvironment () { - if (!d->commandEnvironment) + if (!d->commandEnvironment) { d->commandEnvironment = new kpCommandEnvironment (this); + } return d->commandEnvironment; } //--------------------------------------------------------------------- // private void kpMainWindow::setupActions () { setupFileMenuActions (); setupEditMenuActions (); setupViewMenuActions (); setupImageMenuActions (); setupColorsMenuActions (); setupSettingsMenuActions (); setupTextToolBarActions (); setupToolActions (); } //--------------------------------------------------------------------- // private void kpMainWindow::enableDocumentActions (bool enable) { enableFileMenuDocumentActions (enable); enableEditMenuDocumentActions (enable); enableViewMenuDocumentActions (enable); enableImageMenuDocumentActions (enable); enableColorsMenuDocumentActions (enable); enableSettingsMenuDocumentActions (enable); } //--------------------------------------------------------------------- // private void kpMainWindow::setDocument (kpDocument *newDoc) { //qCDebug(kpLogMainWindow) << newDoc; // is it a close operation? if (!newDoc) { qCDebug(kpLogMainWindow) << "\tdisabling actions"; // sync with the bit marked "sync" below // TODO: Never disable the Color Box because the user should be // able to manipulate the colors, even without a currently // open document. // // We just have to make sure that signals from the Color // Box aren't fired and received unexpectedly when there's // no document. Q_ASSERT (d->colorToolBar); d->colorToolBar->setEnabled (false); enableTextToolBarActions (false); } // Always disable the tools. // If we decide to open a new document/mainView we want // kpTool::begin() to be called again e.g. in case it sets the cursor. // kpViewManager won't do this because we nuke it to avoid stale state. enableToolsDocumentActions (false); if (!newDoc) { enableDocumentActions (false); } delete d->mainView; d->mainView = nullptr; slotDestroyThumbnail (); // viewManager will die and so will the selection d->actionCopy->setEnabled (false); d->actionCut->setEnabled (false); d->actionDelete->setEnabled (false); d->actionDeselect->setEnabled (false); d->actionCopyToFile->setEnabled (false); delete d->viewManager; d->viewManager = nullptr; qCDebug(kpLogMainWindow) << "\tdestroying document"; qCDebug(kpLogMainWindow) << "\t\td->document=" << d->document; // destroy current document delete d->document; d->document = newDoc; if (!d->lastCopyToURL.isEmpty ()) { // remove file name from path QString path = d->lastCopyToURL.path (); path = path.left (path.lastIndexOf (QLatin1Char ('/')) + 1); d->lastCopyToURL.setPath (path); } d->copyToFirstTime = true; if (!d->lastExportURL.isEmpty ()) { QString path = d->lastExportURL.path (); path = path.left (path.lastIndexOf (QLatin1Char ('/')) + 1); d->lastExportURL.setPath (path); } d->exportFirstTime = true; // not a close operation? if (d->document) { qCDebug(kpLogMainWindow) << "\treparenting doc that may have been created into a" - << " different mainWindiow" << endl; + << " different mainWindiow"; d->document->setEnviron (documentEnvironment ()); d->viewManager = new kpViewManager (this); d->mainView = new kpZoomedView (d->document, d->toolToolBar, d->viewManager, nullptr/*buddyView*/, d->scrollView, d->scrollView->viewport ()); d->mainView->setObjectName ( QLatin1String("mainView" )); d->viewManager->registerView (d->mainView); d->scrollView->setView (d->mainView); d->mainView->show (); qCDebug(kpLogMainWindow) << "\thooking up document signals"; // Copy/Cut/Deselect/Delete connect (d->document, &kpDocument::selectionEnabled, d->actionCut, &QAction::setEnabled); connect (d->document, &kpDocument::selectionEnabled, d->actionCopy, &QAction::setEnabled); connect (d->document, &kpDocument::selectionEnabled, d->actionDelete, &QAction::setEnabled); connect (d->document, &kpDocument::selectionEnabled, d->actionDeselect, &QAction::setEnabled); connect (d->document, &kpDocument::selectionEnabled, d->actionCopyToFile, &QAction::setEnabled); // this code won't actually enable any actions at this stage // (fresh document) but better safe than sorry d->actionCopy->setEnabled (d->document->selection ()); d->actionCut->setEnabled (d->document->selection ()); d->actionDeselect->setEnabled (d->document->selection ()); d->actionDelete->setEnabled (d->document->selection ()); d->actionCopyToFile->setEnabled (d->document->selection ()); connect (d->document, &kpDocument::selectionEnabled, this, &kpMainWindow::slotImageMenuUpdateDueToSelection); connect (d->document, &kpDocument::selectionIsTextChanged, this, &kpMainWindow::slotImageMenuUpdateDueToSelection); // Status bar connect (d->document, &kpDocument::documentOpened, this, &kpMainWindow::recalculateStatusBar); connect (d->document, SIGNAL (sizeChanged(QSize)), this, SLOT (setStatusBarDocSize(QSize))); // Caption (url, modified) connect (d->document, &kpDocument::documentModified, this, &kpMainWindow::slotUpdateCaption); connect (d->document, &kpDocument::documentOpened, this, &kpMainWindow::slotUpdateCaption); connect (d->document, &kpDocument::documentSaved, this, &kpMainWindow::slotUpdateCaption); // File/Reload action only available with non-empty URL connect (d->document, &kpDocument::documentSaved, this, &kpMainWindow::slotEnableReload); connect (d->document, &kpDocument::documentSaved, this, &kpMainWindow::slotEnableSettingsShowPath); // Command history Q_ASSERT (d->commandHistory); connect (d->commandHistory, &kpCommandHistory::documentRestored, this, &kpMainWindow::slotDocumentRestored); // caption "!modified" connect (d->document, &kpDocument::documentSaved, d->commandHistory, &kpCommandHistory::documentSaved); // Sync document -> views connect (d->document, &kpDocument::contentsChanged, d->viewManager, &kpViewManager::updateViews); connect (d->document, static_cast(&kpDocument::sizeChanged), d->viewManager, &kpViewManager::adjustViewsToEnvironment); connect (d->document, static_cast(&kpDocument::sizeChanged), d->viewManager, &kpViewManager::adjustViewsToEnvironment); qCDebug(kpLogMainWindow) << "\tenabling actions"; // sync with the bit marked "sync" above Q_ASSERT (d->colorToolBar); d->colorToolBar->setEnabled (true); // Hide the text toolbar - it will be shown by kpToolText::begin() enableTextToolBarActions (false); enableToolsDocumentActions (true); enableDocumentActions (true); } qCDebug(kpLogMainWindow) << "\tupdating mainWindow elements"; slotImageMenuUpdateDueToSelection (); recalculateStatusBar (); slotUpdateCaption (); // Untitled to start with slotEnableReload (); slotEnableSettingsShowPath (); - if (d->commandHistory) + if (d->commandHistory) { d->commandHistory->clear (); + } qCDebug(kpLogMainWindow) << "\tdocument and views ready to go!"; } //--------------------------------------------------------------------- // private virtual [base QWidget] void kpMainWindow::dragEnterEvent (QDragEnterEvent *e) { // It's faster to test for QMimeData::hasText() first due to the // lazy evaluation of the '||' operator. e->setAccepted (e->mimeData ()->hasText () || e->mimeData ()->hasUrls () || kpSelectionDrag::canDecode (e->mimeData ())); } //--------------------------------------------------------------------- // private virtual [base QWidget] void kpMainWindow::dropEvent (QDropEvent *e) { qCDebug(kpLogMainWindow) << "kpMainWindow::dropEvent" << e->pos (); QList urls; kpAbstractImageSelection *sel = kpSelectionDrag::decode (e->mimeData ()); if (sel) { // TODO: How do you actually drop a selection or ordinary images on // the clipboard)? Will this code path _ever_ execute? sel->setTransparency (imageSelectionTransparency ()); // TODO: drop at point like with QTextDrag below? paste (*sel); delete sel; } else if (!(urls = e->mimeData ()->urls ()).isEmpty ()) { // LOTODO: kpSetOverrideCursorSaver cursorSaver (Qt::waitCursor); // // However, you would need to prefix all possible error/warning // dialogs that might be called, with Qt::arrowCursor e.g. in // kpDocument and probably a lot more places. - foreach (const QUrl &u, urls) + for (const auto &u : urls) open (u); } else if (e->mimeData ()->hasText ()) { const QString text = e->mimeData ()->text (); QPoint selTopLeft = KP_INVALID_POINT; const QPoint globalPos = QWidget::mapToGlobal (e->pos ()); qCDebug(kpLogMainWindow) << "\tpos toGlobal=" << globalPos; kpView *view = nullptr; if (d->viewManager) { view = d->viewManager->viewUnderCursor (); qCDebug(kpLogMainWindow) << "\t\tviewUnderCursor=" << view; if (!view) { // HACK: see kpViewManager::setViewUnderCursor() to see why // it's not reliable qCDebug(kpLogMainWindow) << "\t\tattempting to discover view"; if (d->mainView && d->scrollView) { qCDebug(kpLogMainWindow) << "\t\t\tmainView->globalRect=" << kpWidgetMapper::toGlobal (d->mainView, d->mainView->rect ()) << " scrollView->globalRect=" << kpWidgetMapper::toGlobal (d->scrollView, QRect (0, 0, d->scrollView->viewport()->width (), - d->scrollView->viewport()->height ())) - << endl; + d->scrollView->viewport()->height ())); } if (d->thumbnailView && kpWidgetMapper::toGlobal (d->thumbnailView, d->thumbnailView->rect ()) .contains (globalPos)) { // TODO: Code will never get executed. // Thumbnail doesn't accept drops. view = d->thumbnailView; } else if (d->mainView && kpWidgetMapper::toGlobal (d->mainView, d->mainView->rect ()) .contains (globalPos) && d->scrollView && kpWidgetMapper::toGlobal (d->scrollView, QRect (0, 0, d->scrollView->viewport()->width (), d->scrollView->viewport()->height ())) .contains (globalPos)) { view = d->mainView; } } } if (view) { const QPoint viewPos = view->mapFromGlobal (globalPos); const QPoint docPoint = view->transformViewToDoc (viewPos); // viewUnderCursor() is hacky and can return a view when we aren't // over one thanks to drags. if (d->document && d->document->rect ().contains (docPoint)) { selTopLeft = docPoint; // TODO: In terms of doc pixels, would be inconsistent behaviour // based on zoomLevel of view. // selTopLeft -= QPoint (-view->selectionResizeHandleAtomicSize (), // -view->selectionResizeHandleAtomicSize ()); } } pasteText (text, true/*force new text selection*/, selTopLeft); } } //--------------------------------------------------------------------- // private slot void kpMainWindow::slotScrollViewAfterScroll () { // OPT: Why can't this be moved into kpViewScrollableContainer::slotDragScroll(), // grouping all drag-scroll-related repaints, which would potentially avoid // double repainting? if (tool ()) { tool ()->somethingBelowTheCursorChanged (); } } //--------------------------------------------------------------------- // private virtual [base QWidget] void kpMainWindow::moveEvent (QMoveEvent * /*e*/) { if (d->thumbnail) { // Disabled because it lags too far behind the mainWindow // d->thumbnail->move (d->thumbnail->pos () + (e->pos () - e->oldPos ())); notifyThumbnailGeometryChanged (); } } //--------------------------------------------------------------------- // private slot void kpMainWindow::slotUpdateCaption () { if (d->document) { setCaption (d->configShowPath ? d->document->prettyUrl () : d->document->prettyFilename (), d->document->isModified ()); } else { setCaption (QString(), false); } } //--------------------------------------------------------------------- // private slot void kpMainWindow::slotDocumentRestored () { - if (d->document) + if (d->document) { d->document->setModified (false); + } slotUpdateCaption (); } //--------------------------------------------------------------------- diff --git a/mainWindow/kpMainWindow_Colors.cpp b/mainWindow/kpMainWindow_Colors.cpp index 21b2bc32..fa6b7b7e 100644 --- a/mainWindow/kpMainWindow_Colors.cpp +++ b/mainWindow/kpMainWindow_Colors.cpp @@ -1,479 +1,482 @@ /* Copyright (c) 2003-2007 Clarence Dang All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include "kpMainWindow.h" #include "kpMainWindowPrivate.h" #include "widgets/kpColorCells.h" #include "lgpl/generic/kpColorCollection.h" #include "lgpl/generic/kpUrlFormatter.h" #include "widgets/toolbars/kpColorToolBar.h" #include #include #include #include #include "kpLogCategories.h" #include #include //--------------------------------------------------------------------- static QStringList KDEColorCollectionNames () { return kpColorCollection::installedCollections (); } //--------------------------------------------------------------------- // private void kpMainWindow::setupColorsMenuActions () { KActionCollection *ac = actionCollection (); d->actionColorsDefault = ac->addAction ("colors_default"); d->actionColorsDefault->setText (i18n ("Use KolourPaint Defaults")); connect (d->actionColorsDefault, &QAction::triggered, this, &kpMainWindow::slotColorsDefault); d->actionColorsKDE = ac->add ("colors_kde"); d->actionColorsKDE->setText (i18nc ("@item:inmenu colors", "Use KDE's")); // TODO: Will this slot be called spuriously if there are no colors // installed? connect (d->actionColorsKDE, static_cast(&KSelectAction::triggered), this, &kpMainWindow::slotColorsKDE); - foreach (const QString &colName, ::KDEColorCollectionNames ()) + for (const auto &colName : ::KDEColorCollectionNames ()) { d->actionColorsKDE->addAction (colName); + } d->actionColorsOpen = ac->addAction ("colors_open"); d->actionColorsOpen->setText (i18nc ("@item:inmenu colors", "&Open...")); connect (d->actionColorsOpen, &QAction::triggered, this, &kpMainWindow::slotColorsOpen); d->actionColorsReload = ac->addAction ("colors_reload"); d->actionColorsReload->setText (i18nc ("@item:inmenu colors", "Reloa&d")); connect (d->actionColorsReload, &QAction::triggered, this, &kpMainWindow::slotColorsReload); d->actionColorsSave = ac->addAction ("colors_save"); d->actionColorsSave->setText (i18nc ("@item:inmenu colors", "&Save")); connect (d->actionColorsSave, &QAction::triggered, this, &kpMainWindow::slotColorsSave); d->actionColorsSaveAs = ac->addAction ("colors_save_as"); d->actionColorsSaveAs->setText (i18nc ("@item:inmenu colors", "Save &As...")); connect (d->actionColorsSaveAs, &QAction::triggered, this, &kpMainWindow::slotColorsSaveAs); d->actionColorsAppendRow = ac->addAction ("colors_append_row"); d->actionColorsAppendRow->setText (i18nc ("@item:inmenu colors", "Add Row")); connect (d->actionColorsAppendRow, &QAction::triggered, this, &kpMainWindow::slotColorsAppendRow); d->actionColorsDeleteRow = ac->addAction ("colors_delete_row"); d->actionColorsDeleteRow->setText (i18nc ("@item:inmenu colors", "Delete Last Row")); connect (d->actionColorsDeleteRow, &QAction::triggered, this, &kpMainWindow::slotColorsDeleteRow); enableColorsMenuDocumentActions (false); } //--------------------------------------------------------------------- // private void kpMainWindow::createColorBox () { d->colorToolBar = new kpColorToolBar (i18n ("Color Box"), this); // (needed for QMainWindow::saveState()) d->colorToolBar->setObjectName ( QLatin1String("Color Box" )); connect (colorCells (), &kpColorCells::rowCountChanged, this, &kpMainWindow::slotUpdateColorsDeleteRowActionEnabled); } //--------------------------------------------------------------------- // private void kpMainWindow::enableColorsMenuDocumentActions (bool enable) { d->actionColorsDefault->setEnabled (enable); d->actionColorsKDE->setEnabled (enable); d->actionColorsOpen->setEnabled (enable); d->actionColorsReload->setEnabled (enable); d->actionColorsSave->setEnabled (enable); d->actionColorsSaveAs->setEnabled (enable); d->actionColorsAppendRow->setEnabled (enable); d->colorMenuDocumentActionsEnabled = enable; slotUpdateColorsDeleteRowActionEnabled (); } //--------------------------------------------------------------------- // private slot void kpMainWindow::slotUpdateColorsDeleteRowActionEnabled () { // Currently, this is always enabled since kpColorCells guarantees that // there will be at least one row of cells (which might all be of the // invalid color). // // But this method is left here for future extensibility. d->actionColorsDeleteRow->setEnabled ( d->colorMenuDocumentActionsEnabled && (colorCells ()->rowCount () > 0)); } //--------------------------------------------------------------------- // Used in 2 situations: // // 1. User opens a color without using the "Use KDE's" submenu. // 2. User attempts to open a color using the "Use KDE's" submenu but the // opening fails. // // TODO: Maybe we could put the 3 actions (for different ways of opening // colors) in an exclusive group -- this might elminate the need for // this hack. // // private void kpMainWindow::deselectActionColorsKDE () { d->actionColorsKDE->setCurrentItem (-1); } //--------------------------------------------------------------------- // private bool kpMainWindow::queryCloseColors () { qCDebug(kpLogMainWindow) << "kpMainWindow::queryCloseColors() colorCells.modified=" << colorCells ()->isModified (); toolEndShape (); - if (!colorCells ()->isModified ()) + if (!colorCells ()->isModified ()) { return true; // ok to close + } int result = KMessageBox::Cancel; if (!colorCells ()->url ().isEmpty ()) { result = KMessageBox::warningYesNoCancel (this, i18n ("The color palette \"%1\" has been modified.\n" "Do you want to save it?", kpUrlFormatter::PrettyFilename (colorCells ()->url ())), QString ()/*caption*/, KStandardGuiItem::save (), KStandardGuiItem::discard ()); } else { const QString name = colorCells ()->colorCollection ()->name (); if (!name.isEmpty ()) { result = KMessageBox::warningYesNoCancel (this, i18n ("The KDE color palette \"%1\" has been modified.\n" "Do you want to save it to a file?", name), QString ()/*caption*/, KStandardGuiItem::save (), KStandardGuiItem::discard ()); } else { result = KMessageBox::warningYesNoCancel (this, i18n ("The default color palette has been modified.\n" "Do you want to save it to a file?"), QString ()/*caption*/, KStandardGuiItem::save (), KStandardGuiItem::discard ()); } } switch (result) { case KMessageBox::Yes: return slotColorsSave (); // close only if save succeeds case KMessageBox::No: return true; // close without saving default: return false; // don't close current doc } } //--------------------------------------------------------------------- // private void kpMainWindow::openDefaultColors () { colorCells ()->setColorCollection ( kpColorCells::DefaultColorCollection ()); } //--------------------------------------------------------------------- // private slot void kpMainWindow::slotColorsDefault () { // Call just in case. toolEndShape (); - if (!queryCloseColors ()) + if (!queryCloseColors ()) { return; + } openDefaultColors (); deselectActionColorsKDE (); } //--------------------------------------------------------------------- // private bool kpMainWindow::openKDEColors (const QString &name) { qCDebug(kpLogMainWindow) << "kpMainWindow::openKDEColors(" << name << ")"; kpColorCollection colorCol; if (colorCol.openKDE (name, this)) { qCDebug(kpLogMainWindow) << "opened"; colorCells ()->setColorCollection (colorCol); return true; } - else - { - qCDebug(kpLogMainWindow) << "failed to open"; - return false; - } + + qCDebug(kpLogMainWindow) << "failed to open"; + return false; } //--------------------------------------------------------------------- // private slot void kpMainWindow::slotColorsKDE () { // Call in case an error dialog appears. toolEndShape (); const int curItem = d->actionColorsKDE->currentItem (); if (!queryCloseColors ()) { deselectActionColorsKDE (); return; } - else - { - // queryCloseColors() calls slotColorSave(), which can call - // slotColorSaveAs(), which can call deselectActionColorsKDE(). - d->actionColorsKDE->setCurrentItem (curItem); - } + + // queryCloseColors() calls slotColorSave(), which can call + // slotColorSaveAs(), which can call deselectActionColorsKDE(). + d->actionColorsKDE->setCurrentItem (curItem); const QStringList colNames = ::KDEColorCollectionNames (); const int selected = d->actionColorsKDE->currentItem (); Q_ASSERT (selected >= 0 && selected < colNames.size ()); - if (!openKDEColors (colNames [selected])) + if (!openKDEColors (colNames [selected])) { deselectActionColorsKDE (); + } } //--------------------------------------------------------------------- // private bool kpMainWindow::openColors (const QUrl &url) { - if (!colorCells ()->openColorCollection (url)) - return false; - - return true; + return colorCells ()->openColorCollection (url); } //--------------------------------------------------------------------- // private slot void kpMainWindow::slotColorsOpen () { // Call due to dialog. toolEndShape (); QFileDialog fd(this); fd.setDirectoryUrl(colorCells ()->url()); fd.setWindowTitle(i18nc ("@title:window", "Open Color Palette")); if (fd.exec ()) { - if (!queryCloseColors ()) + if (!queryCloseColors ()) { return; + } QList selected = fd.selectedUrls(); - if ( selected.count() && openColors(selected[0]) ) + if ( selected.count() && openColors(selected[0]) ) { deselectActionColorsKDE(); + } } } //--------------------------------------------------------------------- // private slot void kpMainWindow::slotColorsReload () { toolEndShape (); if (colorCells ()->isModified ()) { int result = KMessageBox::Cancel; if (!colorCells ()->url ().isEmpty ()) { result = KMessageBox::warningContinueCancel (this, i18n ("The color palette \"%1\" has been modified.\n" "Reloading will lose all changes since you last saved it.\n" "Are you sure?", kpUrlFormatter::PrettyFilename (colorCells ()->url ())), QString ()/*caption*/, KGuiItem(i18n ("&Reload"))); } else { const QString name = colorCells ()->colorCollection ()->name (); if (!name.isEmpty ()) { result = KMessageBox::warningContinueCancel (this, i18n ("The KDE color palette \"%1\" has been modified.\n" "Reloading will lose all changes.\n" "Are you sure?", colorCells ()->colorCollection ()->name ()), QString ()/*caption*/, KGuiItem (i18n ("&Reload"))); } else { result = KMessageBox::warningContinueCancel (this, i18n ("The default color palette has been modified.\n" "Reloading will lose all changes.\n" "Are you sure?"), QString ()/*caption*/, KGuiItem (i18n ("&Reload"))); } } qCDebug(kpLogMainWindow) << "result=" << result << "vs KMessageBox::Continue" << KMessageBox::Continue; - if (result != KMessageBox::Continue) + if (result != KMessageBox::Continue) { return; + } } if (!colorCells ()->url ().isEmpty ()) { openColors (colorCells ()->url ()); } else { const QString name = colorCells ()->colorCollection ()->name (); - if (!name.isEmpty ()) + if (!name.isEmpty ()) { openKDEColors (name); - else + } + else { openDefaultColors (); + } } } //--------------------------------------------------------------------- // private slot bool kpMainWindow::slotColorsSave () { // Call due to dialog. toolEndShape (); if (colorCells ()->url ().isEmpty ()) { return slotColorsSaveAs (); } return colorCells ()->saveColorCollection (); } //--------------------------------------------------------------------- // private slot bool kpMainWindow::slotColorsSaveAs () { // Call due to dialog. toolEndShape (); QFileDialog fd(this); fd.setDirectoryUrl(colorCells ()->url()); fd.setWindowTitle(i18n("Save Color Palette As")); fd.setAcceptMode(QFileDialog::AcceptSave); if (fd.exec ()) { QList selected = fd.selectedUrls(); - if ( !selected.count() || !colorCells ()->saveColorCollectionAs(selected[0]) ) + if ( !selected.count() || !colorCells ()->saveColorCollectionAs(selected[0]) ) { return false; + } // We're definitely using our own color collection now. deselectActionColorsKDE (); return true; } - else - return false; + + return false; } //--------------------------------------------------------------------- // private slot void kpMainWindow::slotColorsAppendRow () { // Call just in case. toolEndShape (); kpColorCells *colorCells = d->colorToolBar->colorCells (); colorCells->appendRow (); } //--------------------------------------------------------------------- // private slot void kpMainWindow::slotColorsDeleteRow () { // Call just in case. toolEndShape (); kpColorCells *colorCells = d->colorToolBar->colorCells (); colorCells->deleteLastRow (); } diff --git a/mainWindow/kpMainWindow_Edit.cpp b/mainWindow/kpMainWindow_Edit.cpp index c5bf7739..b5bf31a2 100644 --- a/mainWindow/kpMainWindow_Edit.cpp +++ b/mainWindow/kpMainWindow_Edit.cpp @@ -1,875 +1,888 @@ /* Copyright (c) 2003-2007 Clarence Dang Copyright (c) 2011 Martin Koller All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include "kpMainWindow.h" #include "kpMainWindowPrivate.h" #include #include #include #include #include #include #include #include #include "kpLogCategories.h" #include #include #include #include #include #include "layers/selections/image/kpAbstractImageSelection.h" #include "widgets/toolbars/kpColorToolBar.h" #include "commands/kpCommandHistory.h" #include "document/kpDocument.h" #include "imagelib/kpDocumentMetaInfo.h" #include "document/kpDocumentSaveOptions.h" #include "layers/selections/image/kpImageSelectionTransparency.h" #include "commands/kpMacroCommand.h" #include "pixmapfx/kpPixmapFX.h" #include "layers/selections/image/kpRectangularImageSelection.h" #include "layers/selections/kpSelectionDrag.h" #include "generic/kpSetOverrideCursorSaver.h" #include "layers/selections/text/kpTextSelection.h" #include "tools/kpTool.h" #include "commands/tools/selection/text/kpToolTextGiveContentCommand.h" #include "commands/tools/selection/kpToolSelectionCreateCommand.h" #include "commands/tools/selection/kpToolSelectionDestroyCommand.h" #include "commands/tools/selection/text/kpToolTextEnterCommand.h" #include "commands/tools/selection/text/kpToolTextInsertCommand.h" #include "imagelib/transforms/kpTransformCrop.h" #include "commands/imagelib/transforms/kpTransformResizeScaleCommand.h" #include "views/manager/kpViewManager.h" #include "kpViewScrollableContainer.h" #include "views/kpZoomedView.h" //--------------------------------------------------------------------- // private void kpMainWindow::setupEditMenuActions () { KActionCollection *ac = actionCollection (); // Undo/Redo // CONFIG: Need GUI for config history size. d->commandHistory = new kpCommandHistory (true/*read config*/, this); if (d->configFirstTime) { // (so that cfg-file-editing user can modify in the meantime) d->commandHistory->writeConfig (); } d->actionCut = KStandardAction::cut (this, SLOT (slotCut()), ac); d->actionCopy = KStandardAction::copy (this, SLOT (slotCopy()), ac); d->actionPaste = KStandardAction::paste (this, SLOT (slotPaste()), ac); d->actionPasteInNewWindow = ac->addAction ("edit_paste_in_new_window"); d->actionPasteInNewWindow->setText (i18n ("Paste in &New Window")); connect (d->actionPasteInNewWindow, &QAction::triggered, this, &kpMainWindow::slotPasteInNewWindow); ac->setDefaultShortcut (d->actionPasteInNewWindow, Qt::CTRL + Qt::SHIFT + Qt::Key_V); //d->actionDelete = KStandardAction::clear (this, SLOT (slotDelete()), ac); d->actionDelete = ac->addAction ("edit_clear"); d->actionDelete->setText (i18n ("&Delete Selection")); connect (d->actionDelete, &QAction::triggered, this, &kpMainWindow::slotDelete); d->actionSelectAll = KStandardAction::selectAll (this, SLOT (slotSelectAll()), ac); d->actionDeselect = KStandardAction::deselect (this, SLOT (slotDeselect()), ac); d->actionCopyToFile = ac->addAction ("edit_copy_to_file"); d->actionCopyToFile->setText (i18n ("C&opy to File...")); connect (d->actionCopyToFile, &QAction::triggered, this, &kpMainWindow::slotCopyToFile); d->actionPasteFromFile = ac->addAction ("edit_paste_from_file"); d->actionPasteFromFile->setText (i18n ("Paste &From File...")); connect (d->actionPasteFromFile, &QAction::triggered, this, &kpMainWindow::slotPasteFromFile); d->editMenuDocumentActionsEnabled = false; enableEditMenuDocumentActions (false); // Paste should always be enabled, as long as there is something to paste // (independent of whether we have a document or not) connect (QApplication::clipboard(), &QClipboard::dataChanged, this, &kpMainWindow::slotEnablePaste); slotEnablePaste (); } //--------------------------------------------------------------------- // private void kpMainWindow::enableEditMenuDocumentActions (bool enable) { // d->actionCut // d->actionCopy // d->actionPaste // d->actionPasteInNewWindow // d->actionDelete d->actionSelectAll->setEnabled (enable); // d->actionDeselect d->editMenuDocumentActionsEnabled = enable; // d->actionCopyToFile // Unlike d->actionPaste, we disable this if there is no document. // This is because "File / Open" would do the same thing, if there is // no document. d->actionPasteFromFile->setEnabled (enable); } //--------------------------------------------------------------------- // public QMenu *kpMainWindow::selectionToolRMBMenu () { return qobject_cast (guiFactory ()->container ("selectionToolRMBMenu", this)); } //--------------------------------------------------------------------- // private slot void kpMainWindow::slotCut () { qCDebug(kpLogMainWindow) << "kpMainWindow::slotCut() CALLED"; kpSetOverrideCursorSaver cursorSaver (Qt::WaitCursor); Q_ASSERT (d->document && d->document->selection ()); toolEndShape (); slotCopy (); slotDelete (); } //--------------------------------------------------------------------- static QMimeData *NewTextMimeData (const QString &text) { - QMimeData *md = new QMimeData (); + auto *md = new QMimeData (); md->setText (text); return md; } //--------------------------------------------------------------------- // private slot void kpMainWindow::slotCopy () { qCDebug(kpLogMainWindow) << "kpMainWindow::slotCopy() CALLED"; kpSetOverrideCursorSaver cursorSaver (Qt::WaitCursor); Q_ASSERT (d->document && d->document->selection ()); toolEndShape (); kpAbstractSelection *sel = d->document->selection ()->clone (); if (dynamic_cast (sel)) { - kpTextSelection *textSel = static_cast (sel); + auto *textSel = dynamic_cast (sel); if (!textSel->text ().isEmpty ()) { QApplication::clipboard ()->setMimeData ( ::NewTextMimeData (textSel->text ()), QClipboard::Clipboard); // SYNC: Normally, users highlight text and press CTRL+C. // Highlighting text copies it to the X11 "middle // mouse button" clipboard. CTRL+C copies it to the // separate, Windows-like "CTRL+V" clipboard. // // However, KolourPaint doesn't support highlighting. // So when they press CTRL+C to copy all text, simulate // the highlighting by copying the text to the "middle // mouse button" clipboard. We don't do this for images // as no one ever middle-mouse-pastes images. // // Note that we don't share the QMimeData pointer with // the above in case Qt doesn't expect it. // // Once we change KolourPaint to support highlighted text // and CTRL+C to copy only the highlighted text, delete // this code. QApplication::clipboard ()->setMimeData ( ::NewTextMimeData (textSel->text ()), QClipboard::Selection); } } else if (dynamic_cast (sel)) { - kpAbstractImageSelection *imageSel = - static_cast (sel); + auto *imageSel = dynamic_cast (sel); // Transparency doesn't get sent across the aether so nuke it now // so that transparency mask doesn't get needlessly recalculated // if we ever call sel.setBaseImage(). imageSel->setTransparency (kpImageSelectionTransparency ()); kpImage rawImage; - if (imageSel->hasContent ()) + if (imageSel->hasContent ()) { rawImage = imageSel->baseImage (); - else + } + else { rawImage = d->document->getSelectedBaseImage (); + } imageSel->setBaseImage ( rawImage ); QApplication::clipboard ()->setMimeData ( new kpSelectionDrag (*imageSel), QClipboard::Clipboard); } - else + else { Q_ASSERT (!"Unknown selection type"); + } delete sel; } //--------------------------------------------------------------------- // private slot void kpMainWindow::slotEnablePaste () { const QMimeData *md = QApplication::clipboard()->mimeData(QClipboard::Clipboard); // It's faster to test for QMimeData::hasText() first due to the // lazy evaluation of the '||' operator. const bool shouldEnable = md && (md->hasText() || kpSelectionDrag::canDecode(md)); d->actionPasteInNewWindow->setEnabled(shouldEnable); d->actionPaste->setEnabled(shouldEnable); } //--------------------------------------------------------------------- // private QRect kpMainWindow::calcUsefulPasteRect (int imageWidth, int imageHeight) { qCDebug(kpLogMainWindow) << "kpMainWindow::calcUsefulPasteRect(" << imageWidth << "," << imageHeight - << ")" - << endl; + << ")"; Q_ASSERT (d->document); // TODO: 1st choice is to paste sel near but not overlapping last deselect point if (d->mainView && d->scrollView) { const QPoint viewTopLeft (d->scrollView->horizontalScrollBar()->value (), d->scrollView->verticalScrollBar()->value ()); const QPoint docTopLeft = d->mainView->transformViewToDoc (viewTopLeft); if ((docTopLeft.x () + imageWidth <= d->document->width () && docTopLeft.y () + imageHeight <= d->document->height ()) || imageWidth <= docTopLeft.x () || imageHeight <= docTopLeft.y ()) { - return QRect (docTopLeft.x (), docTopLeft.y (), - imageWidth, imageHeight); + return {docTopLeft.x (), docTopLeft.y (), imageWidth, imageHeight}; } } - return QRect (0, 0, imageWidth, imageHeight); + return {0, 0, imageWidth, imageHeight}; } //--------------------------------------------------------------------- // private void kpMainWindow::paste(const kpAbstractSelection &sel, bool forceTopLeft) { - qCDebug(kpLogMainWindow) << "kpMainWindow::paste(forceTopLeft=" << forceTopLeft << ")" - << endl; + qCDebug(kpLogMainWindow) << "kpMainWindow::paste(forceTopLeft=" << forceTopLeft << ")"; kpSetOverrideCursorSaver cursorSaver (Qt::WaitCursor); toolEndShape (); // // Make sure we've got a document (esp. with File/Close) // if (!d->document) { - kpDocument *newDoc = new kpDocument ( + auto *newDoc = new kpDocument ( sel.width (), sel.height (), documentEnvironment ()); // will also create viewManager setDocument (newDoc); } // // Paste as new selection // - const kpAbstractImageSelection *imageSel = - dynamic_cast (&sel); + const auto *imageSel = dynamic_cast (&sel); + if (imageSel && imageSel->hasContent () && imageSel->transparency ().isTransparent ()) { d->colorToolBar->flashColorSimilarityToolBarItem (); } kpAbstractSelection *selInUsefulPos = sel.clone (); - if (!forceTopLeft) + if (!forceTopLeft) { selInUsefulPos->moveTo (calcUsefulPasteRect (sel.width (), sel.height ()).topLeft ()); + } // TODO: Should use kpCommandHistory::addCreateSelectionCommand(), // as well, to really support pasting selection borders. addDeselectFirstCommand (new kpToolSelectionCreateCommand ( dynamic_cast (selInUsefulPos) ? i18n ("Text: Create Box") : i18n ("Selection: Create"), *selInUsefulPos, commandEnvironment ())); delete selInUsefulPos; qCDebug(kpLogMainWindow) << "sel.size=" << QSize (sel.width (), sel.height ()) << " document.size=" - << QSize (d->document->width (), d->document->height ()) - << endl; + << QSize (d->document->width (), d->document->height ()); // If the selection is bigger than the document, automatically // resize the document (with the option of Undo'ing) to fit // the selection. // // No annoying dialog necessary. // if (sel.width () > d->document->width () || sel.height () > d->document->height ()) { d->commandHistory->addCommand ( new kpTransformResizeScaleCommand ( false/*act on doc, not sel*/, qMax (sel.width (), d->document->width ()), qMax (sel.height (), d->document->height ()), kpTransformResizeScaleCommand::Resize, commandEnvironment ())); } } //--------------------------------------------------------------------- // public void kpMainWindow::pasteText (const QString &text, bool forceNewTextSelection, const QPoint &newTextSelectionTopLeft) { qCDebug(kpLogMainWindow) << "kpMainWindow::pasteText(" << text << ",forceNewTextSelection=" << forceNewTextSelection << ",newTextSelectionTopLeft=" << newTextSelectionTopLeft - << ")" << endl; + << ")"; - if ( text.isEmpty() ) + if ( text.isEmpty() ) { return; + } kpSetOverrideCursorSaver cursorSaver (Qt::WaitCursor); toolEndShape (); QStringList textLines = text.split('\n'); if (!forceNewTextSelection && d->document && d->document->textSelection () && d->commandHistory && d->viewManager) { qCDebug(kpLogMainWindow) << "\treusing existing Text Selection"; d->viewManager->setQueueUpdates(); kpTextSelection *textSel = d->document->textSelection (); if (!textSel->hasContent ()) { qCDebug(kpLogMainWindow) << "\t\tneeds content"; commandHistory ()->addCreateSelectionCommand ( new kpToolSelectionCreateCommand ( i18n ("Text: Create Box"), *textSel, commandEnvironment ()), false/*no exec*/); } kpMacroCommand *macroCmd = new kpMacroCommand (i18n ("Text: Paste"), commandEnvironment ()); // (yes, this is the same check as the previous "if") if (!textSel->hasContent ()) { kpCommand *giveContentCmd = new kpToolTextGiveContentCommand ( *textSel, QString ()/*uninteresting child of macro cmd*/, commandEnvironment ()); giveContentCmd->execute (); macroCmd->addCommand (giveContentCmd); } for (int i = 0; i < static_cast (textLines.size ()); i++) { if (i > 0) { macroCmd->addCommand ( new kpToolTextEnterCommand ( QString()/*uninteresting child of macroCmd*/, d->viewManager->textCursorRow (), d->viewManager->textCursorCol (), kpToolTextEnterCommand::AddEnterNow, commandEnvironment ())); } macroCmd->addCommand ( new kpToolTextInsertCommand ( QString()/*uninteresting child of macroCmd*/, d->viewManager->textCursorRow (), d->viewManager->textCursorCol (), textLines [i], commandEnvironment ())); } d->commandHistory->addCommand (macroCmd, false/*no exec*/); d->viewManager->restoreQueueUpdates(); } else { qCDebug(kpLogMainWindow) << "\tcreating Text Selection"; const kpTextStyle ts = textStyle (); const QFontMetrics fontMetrics = ts.fontMetrics (); int height = textLines.size () * fontMetrics.height (); - if (textLines.size () >= 1) + if (textLines.size () >= 1) { height += (textLines.size () - 1) * fontMetrics.leading (); + } int width = 0; for (QList ::const_iterator it = textLines.constBegin (); it != textLines.constEnd (); ++it) { const int w = fontMetrics.width (*it); - if (w > width) + if (w > width) { width = w; + } } // limit the size to avoid memory overflow width = qMin(qMax(QApplication::desktop()->width(), d->document ? d->document->width() : 0), width); height = qMin(qMax(QApplication::desktop()->height(), d->document ? d->document->height() : 0), height); const int selWidth = qMax (kpTextSelection::MinimumWidthForTextStyle (ts), width + kpTextSelection::TextBorderSize () * 2); const int selHeight = qMax (kpTextSelection::MinimumHeightForTextStyle (ts), height + kpTextSelection::TextBorderSize () * 2); kpTextSelection newTextSel (QRect (0, 0, selWidth, selHeight), textLines, ts); if (newTextSelectionTopLeft != KP_INVALID_POINT) { newTextSel.moveTo (newTextSelectionTopLeft); paste (newTextSel, true/*force topLeft*/); } else { paste (newTextSel); } } } //--------------------------------------------------------------------- // public void kpMainWindow::pasteTextAt (const QString &text, const QPoint &point, bool allowNewTextSelectionPointShift) { qCDebug(kpLogMainWindow) << "kpMainWindow::pasteTextAt(" << text << ",point=" << point << ",allowNewTextSelectionPointShift=" << allowNewTextSelectionPointShift - << ")" << endl; + << ")"; kpSetOverrideCursorSaver cursorSaver (Qt::WaitCursor); toolEndShape (); if (d->document && d->document->textSelection () && d->document->textSelection ()->pointIsInTextArea (point)) { kpTextSelection *textSel = d->document->textSelection (); int row, col; if (textSel->hasContent ()) { row = textSel->closestTextRowForPoint (point); col = textSel->closestTextColForPoint (point); } else { row = col = 0; } d->viewManager->setTextCursorPosition (row, col); pasteText (text); } else { QPoint pointToUse = point; if (allowNewTextSelectionPointShift) { // TODO: In terms of doc pixels, would be inconsistent behaviour // based on zoomLevel of view. // pointToUse -= QPoint (-view->selectionResizeHandleAtomicSize (), // -view->selectionResizeHandleAtomicSize ()); } pasteText (text, true/*force new text selection*/, pointToUse); } } //--------------------------------------------------------------------- // public slot void kpMainWindow::slotPaste() { kpSetOverrideCursorSaver cursorSaver(Qt::WaitCursor); toolEndShape(); const QMimeData *mimeData = QApplication::clipboard()->mimeData(QClipboard::Clipboard); kpAbstractImageSelection *sel = kpSelectionDrag::decode(mimeData); if ( sel ) { sel->setTransparency(imageSelectionTransparency()); paste(*sel); delete sel; } else if ( mimeData->hasText() ) { pasteText(mimeData->text()); } else { kpSetOverrideCursorSaver cursorSaver(Qt::ArrowCursor); KMessageBox::sorry(this, i18n("KolourPaint cannot paste the contents of" " the clipboard as it has an unknown format."), i18n("Cannot Paste")); } } //--------------------------------------------------------------------- // private slot void kpMainWindow::slotPasteInNewWindow () { qCDebug(kpLogMainWindow) << "kpMainWindow::slotPasteInNewWindow() CALLED"; kpSetOverrideCursorSaver cursorSaver (Qt::WaitCursor); toolEndShape (); // // Pasting must ensure that: // // Requirement 1. the document is the same size as the image to be pasted. // Requirement 2. transparent pixels in the image must remain as transparent. // - kpMainWindow *win = new kpMainWindow (nullptr/*no document*/); + auto *win = new kpMainWindow (nullptr/*no document*/); win->show (); // Make "Edit / Paste in New Window" always paste white pixels as white. // Don't let selection transparency get in the way and paste them as // transparent. kpImageSelectionTransparency transparency = win->imageSelectionTransparency (); if (transparency.isTransparent ()) { qCDebug(kpLogMainWindow) << "\tchanging image selection transparency to opaque"; transparency.setOpaque (); // Since we are setting selection transparency programmatically // -- as opposed to in response to user input -- this will not // affect the selection transparency tool option widget's "last used" // config setting. win->setImageSelectionTransparency (transparency); } // (this handles Requirement 1. above) win->slotPaste (); // if slotPaste could not decode clipboard data, no document was created if ( win->document() ) { // (this handles Requirement 2. above; // slotDeselect() is not enough unless the document is filled with the // transparent color in advance) win->slotCrop(); } } //--------------------------------------------------------------------- // public slot void kpMainWindow::slotDelete () { qCDebug(kpLogMainWindow) << "kpMainWindow::slotDelete() CALLED"; if (!d->actionDelete->isEnabled ()) { qCDebug(kpLogMainWindow) << "\taction not enabled - was probably called from kpTool::keyPressEvent()"; return; } Q_ASSERT (d->document && d->document->selection ()); toolEndShape (); addImageOrSelectionCommand (new kpToolSelectionDestroyCommand ( d->document->textSelection () ? i18n ("Text: Delete Box") : // not to be confused with i18n ("Text: Delete") i18n ("Selection: Delete"), false/*no push onto doc*/, commandEnvironment ())); } //--------------------------------------------------------------------- // private slot void kpMainWindow::slotSelectAll () { qCDebug(kpLogMainWindow) << "kpMainWindow::slotSelectAll() CALLED"; Q_ASSERT (d->document); toolEndShape (); - if (d->document->selection ()) + if (d->document->selection ()) { slotDeselect (); + } // just the border - don't actually pull image from doc yet d->document->setSelection ( kpRectangularImageSelection (d->document->rect (), imageSelectionTransparency ())); - if (tool ()) + if (tool ()) { tool ()->somethingBelowTheCursorChanged (); + } } //--------------------------------------------------------------------- // private void kpMainWindow::addDeselectFirstCommand (kpCommand *cmd) { qCDebug(kpLogMainWindow) << "kpMainWindow::addDeselectFirstCommand(" << cmd - << ")" - << endl; + << ")"; kpAbstractSelection *sel = d->document->selection (); qCDebug(kpLogMainWindow) << "\tsel=" << sel; if (sel) { // if you just dragged out something with no action then // forget the drag if (!sel->hasContent ()) { qCDebug(kpLogMainWindow) << "\tjust a fresh border - was nop - delete"; d->document->selectionDelete (); - if (tool ()) + if (tool ()) { tool ()->somethingBelowTheCursorChanged (); + } - if (cmd) + if (cmd) { d->commandHistory->addCommand (cmd); + } } else { qCDebug(kpLogMainWindow) << "\treal selection with image - push onto doc cmd"; kpCommand *deselectCommand = new kpToolSelectionDestroyCommand ( dynamic_cast (sel) ? i18n ("Text: Finish") : i18n ("Selection: Deselect"), true/*push onto document*/, commandEnvironment ()); if (cmd) { kpMacroCommand *macroCmd = new kpMacroCommand (cmd->name (), commandEnvironment ()); macroCmd->addCommand (deselectCommand); macroCmd->addCommand (cmd); d->commandHistory->addCommand (macroCmd); } - else + else { d->commandHistory->addCommand (deselectCommand); + } } } else { - if (cmd) + if (cmd) { d->commandHistory->addCommand (cmd); + } } } //--------------------------------------------------------------------- // public slot void kpMainWindow::slotDeselect () { qCDebug(kpLogMainWindow) << "kpMainWindow::slotDeselect() CALLED"; Q_ASSERT (d->document && d->document->selection ()); toolEndShape (); addDeselectFirstCommand (nullptr); } //--------------------------------------------------------------------- // private slot void kpMainWindow::slotCopyToFile () { qCDebug(kpLogMainWindow) << "kpMainWindow::slotCopyToFile()"; toolEndShape (); - if (!d->document->selection ()) + if (!d->document->selection ()) { return; + } kpImage imageToSave; if (d->document->imageSelection ()) { kpAbstractImageSelection *imageSel = d->document->imageSelection (); if (!imageSel->hasContent ()) { // Not a floating selection - user has just selected a region; // haven't pulled it off yet so probably don't expect and can't // visualize selection transparency so give opaque, not transparent // image. imageToSave = d->document->getSelectedBaseImage (); } - else + else { imageToSave = imageSel->transparentImage (); + } } else if (d->document->textSelection ()) { imageToSave = d->document->textSelection ()->approximateImage (); } - else + else { Q_ASSERT (!"Unknown selection type"); + } kpDocumentSaveOptions chosenSaveOptions; bool allowOverwritePrompt, allowLossyPrompt; QUrl chosenURL = askForSaveURL (i18nc ("@title:window", "Copy to File"), d->lastCopyToURL.url (), imageToSave, d->lastCopyToSaveOptions, kpDocumentMetaInfo (), kpSettingsGroupEditCopyTo, false/*allow remote files*/, &chosenSaveOptions, d->copyToFirstTime, &allowOverwritePrompt, &allowLossyPrompt); - if (chosenURL.isEmpty ()) + if (chosenURL.isEmpty ()) { return; + } if (!kpDocument::savePixmapToFile (imageToSave, chosenURL, chosenSaveOptions, kpDocumentMetaInfo (), allowOverwritePrompt, allowLossyPrompt, this)) { return; } addRecentURL (chosenURL); d->lastCopyToURL = chosenURL; d->lastCopyToSaveOptions = chosenSaveOptions; d->copyToFirstTime = false; } //--------------------------------------------------------------------- // private slot void kpMainWindow::slotPasteFromFile () { qCDebug(kpLogMainWindow) << "kpMainWindow::slotPasteFromFile()"; toolEndShape (); QList urls = askForOpenURLs(i18nc ("@title:window", "Paste From File"), false/*only 1 URL*/); - if (urls.count () != 1) + if (urls.count () != 1) { return; + } QUrl url = urls.first (); kpImage image = kpDocument::getPixmapFromFile (url, false/*show error message if doesn't exist*/, this); - if (image.isNull ()) + if (image.isNull ()) { return; + } addRecentURL (url); paste (kpRectangularImageSelection ( QRect (0, 0, image.width (), image.height ()), image, imageSelectionTransparency ())); } //--------------------------------------------------------------------- diff --git a/mainWindow/kpMainWindow_File.cpp b/mainWindow/kpMainWindow_File.cpp index ca888b91..6b617adb 100644 --- a/mainWindow/kpMainWindow_File.cpp +++ b/mainWindow/kpMainWindow_File.cpp @@ -1,1435 +1,1443 @@ /* Copyright (c) 2003-2007 Clarence Dang Copyright (c) 2007 John Layt Copyright (c) 2007,2011,2015 Martin Koller All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include "kpMainWindow.h" #include "kpMainWindowPrivate.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include // kdelibs4support #include #include // kdelibs4support #include #include #include #include #include #include #include // kdelibs4support #include "kpLogCategories.h" #include "commands/kpCommandHistory.h" #include "kpDefs.h" #include "document/kpDocument.h" #include "commands/imagelib/kpDocumentMetaInfoCommand.h" #include "dialogs/imagelib/kpDocumentMetaInfoDialog.h" #include "widgets/kpDocumentSaveOptionsWidget.h" #include "pixmapfx/kpPixmapFX.h" #include "widgets/kpPrintDialogPage.h" #include "views/kpView.h" #include "views/manager/kpViewManager.h" #if HAVE_KSANE #include "../scan/sanedialog.h" #endif // HAVE_KSANE // private void kpMainWindow::setupFileMenuActions () { qCDebug(kpLogMainWindow) << "kpMainWindow::setupFileMenuActions()"; KActionCollection *ac = actionCollection (); d->actionNew = KStandardAction::openNew (this, SLOT (slotNew()), ac); d->actionOpen = KStandardAction::open (this, SLOT (slotOpen()), ac); d->actionOpenRecent = KStandardAction::openRecent(this, &kpMainWindow::slotOpenRecent, ac); connect(d->actionOpenRecent, &KRecentFilesAction::recentListCleared, this, &kpMainWindow::slotRecentListCleared); d->actionOpenRecent->loadEntries (KSharedConfig::openConfig ()->group (kpSettingsGroupRecentFiles)); qCDebug(kpLogMainWindow) << "\trecent URLs=" << d->actionOpenRecent->items (); d->actionSave = KStandardAction::save (this, SLOT (slotSave()), ac); d->actionSaveAs = KStandardAction::saveAs (this, SLOT (slotSaveAs()), ac); d->actionExport = ac->addAction("file_export"); d->actionExport->setText (i18n ("E&xport...")); d->actionExport->setIcon(KDE::icon("document-export")); connect (d->actionExport, &QAction::triggered, this, &kpMainWindow::slotExport); d->actionScan = ac->addAction("file_scan"); d->actionScan->setText(i18n ("Scan...")); d->actionScan->setIcon(SmallIcon("scanner")); #if HAVE_KSANE connect (d->actionScan, &QAction::triggered, this, &kpMainWindow::slotScan); #else d->actionScan->setEnabled(false); #endif // HAVE_KSANE d->actionScreenshot = ac->addAction("file_screenshot"); d->actionScreenshot->setText(i18n("Acquire Screenshot")); connect (d->actionScreenshot, &QAction::triggered, this, &kpMainWindow::slotScreenshot); d->actionProperties = ac->addAction ("file_properties"); d->actionProperties->setText (i18n ("Properties")); d->actionProperties->setIcon(KDE::icon("document-properties")); connect (d->actionProperties, &QAction::triggered, this, &kpMainWindow::slotProperties); //d->actionRevert = KStandardAction::revert (this, SLOT (slotRevert()), ac); d->actionReload = ac->addAction ("file_revert"); d->actionReload->setText (i18n ("Reloa&d")); d->actionReload->setIcon(KDE::icon("view-refresh")); connect (d->actionReload, &QAction::triggered, this, &kpMainWindow::slotReload); ac->setDefaultShortcuts (d->actionReload, KStandardShortcut::reload ()); slotEnableReload (); d->actionPrint = KStandardAction::print (this, SLOT (slotPrint()), ac); d->actionPrintPreview = KStandardAction::printPreview (this, SLOT (slotPrintPreview()), ac); d->actionMail = KStandardAction::mail (this, SLOT (slotMail()), ac); d->actionClose = KStandardAction::close (this, SLOT (slotClose()), ac); d->actionQuit = KStandardAction::quit (this, SLOT (slotQuit()), ac); d->scanDialog = nullptr; enableFileMenuDocumentActions (false); } //--------------------------------------------------------------------- // private void kpMainWindow::enableFileMenuDocumentActions (bool enable) { // d->actionNew // d->actionOpen // d->actionOpenRecent d->actionSave->setEnabled (enable); d->actionSaveAs->setEnabled (enable); d->actionExport->setEnabled (enable); // d->actionScan d->actionProperties->setEnabled (enable); // d->actionReload d->actionPrint->setEnabled (enable); d->actionPrintPreview->setEnabled (enable); d->actionMail->setEnabled (enable); d->actionClose->setEnabled (enable); // d->actionQuit->setEnabled (enable); } //--------------------------------------------------------------------- // private void kpMainWindow::addRecentURL (const QUrl &url_) { // HACK: KRecentFilesAction::loadEntries() clears the KRecentFilesAction::d->urls // map. // // So afterwards, the URL ref, our method is given, points to an // element in this now-cleared map (see KRecentFilesAction::urlSelected(QAction*)). // Accessing it would result in a crash. // // To avoid the crash, make a copy of it before calling // loadEntries() and use this copy, instead of the to-be-dangling // ref. - const QUrl url = url_; + const QUrl& url = url_; qCDebug(kpLogMainWindow) << "kpMainWindow::addRecentURL(" << url << ")"; if (url.isEmpty ()) return; KSharedConfig::Ptr cfg = KSharedConfig::openConfig(); // KConfig::readEntry() does not actually reread from disk, hence doesn't // realize what other processes have done e.g. Settings / Show Path cfg->reparseConfiguration (); qCDebug(kpLogMainWindow) << "\trecent URLs=" << d->actionOpenRecent->items (); // HACK: Something might have changed interprocess. // If we could PROPAGATE: interprocess, then this wouldn't be required. d->actionOpenRecent->loadEntries (cfg->group (kpSettingsGroupRecentFiles)); qCDebug(kpLogMainWindow) << "\tafter loading config=" << d->actionOpenRecent->items (); d->actionOpenRecent->addUrl (url); d->actionOpenRecent->saveEntries (cfg->group (kpSettingsGroupRecentFiles)); cfg->sync (); qCDebug(kpLogMainWindow) << "\tnew recent URLs=" << d->actionOpenRecent->items (); // TODO: PROPAGATE: interprocess // TODO: Is this loop safe since a KMainWindow later along in the list, // could be closed as the code in the body almost certainly re-enters // the event loop? Problem for KDE 3 as well, I think. - foreach (KMainWindow *kmw, KMainWindow::memberList ()) + for (auto *kmw : KMainWindow::memberList ()) { Q_ASSERT (dynamic_cast (kmw)); - kpMainWindow *mw = static_cast (kmw); + auto *mw = dynamic_cast (kmw); qCDebug(kpLogMainWindow) << "\t\tmw=" << mw; if (mw != this) { // WARNING: Do not use KRecentFilesAction::setItems() // - it does not work since only its superclass, // KSelectAction, implements setItems() and can't // update KRecentFilesAction's URL list. // Avoid URL memory leak in KRecentFilesAction::loadEntries(). mw->d->actionOpenRecent->clear (); mw->d->actionOpenRecent->loadEntries (cfg->group (kpSettingsGroupRecentFiles)); qCDebug(kpLogMainWindow) << "\t\t\tcheck recent URLs=" - << mw->d->actionOpenRecent->items () << endl; + << mw->d->actionOpenRecent->items (); } } } //--------------------------------------------------------------------- // private slot // TODO: Disable action if // (d->configOpenImagesInSameWindow && d->document && d->document->isEmpty()) // as it does nothing if this is true. void kpMainWindow::slotNew () { toolEndShape (); if (d->document && !d->configOpenImagesInSameWindow) { // A document -- empty or otherwise -- is open. // Force open a new window. In contrast, open() might not open // a new window in this case. - kpMainWindow *win = new kpMainWindow (); + auto *win = new kpMainWindow (); win->show (); } else { open (QUrl (), true/*create an empty doc*/); } } //--------------------------------------------------------------------- // private QSize kpMainWindow::defaultDocSize () const { // KConfig::readEntry() does not actually reread from disk, hence doesn't // realize what other processes have done e.g. Settings / Show Path KSharedConfig::openConfig ()->reparseConfiguration (); KConfigGroup cfg (KSharedConfig::openConfig (), kpSettingsGroupGeneral); QSize docSize = cfg.readEntry (kpSettingLastDocSize, QSize ()); if (docSize.isEmpty ()) { docSize = QSize (400, 300); } else { // Don't get too big or you'll thrash (or even lock up) the computer // just by opening a window docSize = QSize (qMin (2048, docSize.width ()), qMin (2048, docSize.height ())); } return docSize; } //--------------------------------------------------------------------- // private void kpMainWindow::saveDefaultDocSize (const QSize &size) { qCDebug(kpLogMainWindow) << "\tCONFIG: saving Last Doc Size = " << size; KConfigGroup cfg (KSharedConfig::openConfig (), kpSettingsGroupGeneral); cfg.writeEntry (kpSettingLastDocSize, size); cfg.sync (); } //--------------------------------------------------------------------- // private bool kpMainWindow::shouldOpen () { if (d->configOpenImagesInSameWindow) { qCDebug(kpLogMainWindow) << "\topenImagesInSameWindow"; // (this brings up a dialog and might save the current doc) if (!queryCloseDocument ()) { qCDebug(kpLogMainWindow) << "\t\tqueryCloseDocument() aborts open"; return false; } } return true; } //--------------------------------------------------------------------- // private void kpMainWindow::setDocumentChoosingWindow (kpDocument *doc) { // Want new window? if (d->document && !d->document->isEmpty () && !d->configOpenImagesInSameWindow) { // Send doc to new window. - kpMainWindow *win = new kpMainWindow (doc); + auto *win = new kpMainWindow (doc); win->show (); } else { // (sets up views, doc signals) setDocument (doc); } } //--------------------------------------------------------------------- // private kpDocument *kpMainWindow::openInternal (const QUrl &url, const QSize &fallbackDocSize, bool newDocSameNameIfNotExist) { // If using OpenImagesInSameWindow mode, ask whether to close the // current document. if (!shouldOpen ()) return nullptr; // Create/open doc. - kpDocument *newDoc = new kpDocument (fallbackDocSize.width (), - fallbackDocSize.height (), - documentEnvironment ()); + auto *newDoc = new kpDocument (fallbackDocSize.width (), + fallbackDocSize.height (), documentEnvironment ()); + if (!newDoc->open (url, newDocSameNameIfNotExist)) { qCDebug(kpLogMainWindow) << "\topen failed"; delete newDoc; return nullptr; } qCDebug(kpLogMainWindow) << "\topen OK"; // Send document to current or new window. setDocumentChoosingWindow (newDoc); return newDoc; } //--------------------------------------------------------------------- // private bool kpMainWindow::open (const QUrl &url, bool newDocSameNameIfNotExist) { qCDebug(kpLogMainWindow) << "kpMainWindow::open(" << url << ",newDocSameNameIfNotExist=" << newDocSameNameIfNotExist - << ")" << endl; + << ")"; kpDocument *newDoc = openInternal (url, defaultDocSize (), newDocSameNameIfNotExist); if (newDoc) { if (newDoc->isFromURL (false/*don't bother checking exists*/)) addRecentURL (url); return true; } - else - { - return false; - } + + return false; } //--------------------------------------------------------------------- // private QList kpMainWindow::askForOpenURLs(const QString &caption, bool allowMultipleURLs) { QMimeDatabase db; QStringList filterList; QString filter; - foreach(const QByteArray &type, QImageReader::supportedMimeTypes()) + for (const auto &type : QImageReader::supportedMimeTypes()) { - if ( !filter.isEmpty() ) + if ( !filter.isEmpty() ) { filter += QLatin1Char(' '); + } QMimeType mime(db.mimeTypeForName(QString::fromLatin1(type))); if ( mime.isValid() ) { QString glob = mime.globPatterns().join(QLatin1Char(' ')); filter += glob; // I want to show the mime comment AND the file glob pattern, // but to avoid that the "All Supported Files" entry shows ALL glob patterns, // I must add the pattern here a second time so that QFileDialog::HideNameFilterDetails // can hide the first pattern and I still see the second one filterList << mime.comment() + QString(" (%1)(%2)").arg(glob).arg(glob); } } filterList.prepend(i18n("All Supported Files (%1)", filter)); QFileDialog fd(this); fd.setNameFilters(filterList); fd.setOption(QFileDialog::HideNameFilterDetails); fd.setWindowTitle(caption); - if ( allowMultipleURLs ) + if ( allowMultipleURLs ) { fd.setFileMode(QFileDialog::ExistingFiles); + } - if ( fd.exec() ) + if ( fd.exec() ) { return fd.selectedUrls(); - else - return QList(); + } + + return QList(); } //--------------------------------------------------------------------- // private slot void kpMainWindow::slotOpen () { toolEndShape (); const QList urls = askForOpenURLs(i18nc("@title:window", "Open Image")); - for (QList::const_iterator it = urls.begin (); - it != urls.end (); - ++it) + for (const auto & url : urls) { - open (*it); + open (url); } } //--------------------------------------------------------------------- // private slot void kpMainWindow::slotOpenRecent (const QUrl &url) { qCDebug(kpLogMainWindow) << "kpMainWindow::slotOpenRecent(" << url << ")"; qCDebug(kpLogMainWindow) << "\titems=" << d->actionOpenRecent->items (); toolEndShape (); open (url); // If the open is successful, addRecentURL() would have bubbled up the // URL in the File / Open Recent action. As a side effect, the URL is // deselected. // // If the open fails, we should deselect the URL: // // 1. for consistency // // 2. because it has not been opened. // d->actionOpenRecent->setCurrentItem (-1); } //--------------------------------------------------------------------- void kpMainWindow::slotRecentListCleared() { d->actionOpenRecent->saveEntries(KSharedConfig::openConfig()->group(kpSettingsGroupRecentFiles)); } //--------------------------------------------------------------------- #if HAVE_KSANE // private slot void kpMainWindow::slotScan () { qCDebug(kpLogMainWindow) << "kpMainWindow::slotScan() scanDialog=" << d->scanDialog; toolEndShape (); if (!d->scanDialog) { // Create scan dialog d->scanDialog = new SaneDialog(this); // No scanning support (kdegraphics/libkscan) installed? if (!d->scanDialog) { KMessageBox::sorry (this, i18n("Failed to open scanning dialog."), i18nc("@title:window", "Scanning Failed")); return; } qCDebug(kpLogMainWindow) << "\tcreated scanDialog=" << d->scanDialog; connect (d->scanDialog, &SaneDialog::finalImage, this, &kpMainWindow::slotScanned); } // If using OpenImagesInSameWindow mode, ask whether to close the // current document. // // Do this after scan support is detected. Because if it's not, what // would be the point of closing the document? // // Ideally, we would do this after the user presses "Final Scan" in // the scan dialog and before the scan begins (if the user wants to // cancel the scan operation, it would be annoying to offer this choice // only after the slow scan is completed) but the KScanDialog API does // not allow this. So we settle for doing this before any // scan dialogs are shown. We don't do this between KScanDialog::setup() // and KScanDialog::exec() as it could be confusing alternating between // scanning and KolourPaint dialogs. - if (!shouldOpen ()) + if (!shouldOpen ()) { return; + } qCDebug(kpLogMainWindow) << "\tcalling setup"; // Bring up dialog to select scan device. // If there is no scanner, we find that this does not bring up a dialog // but still returns true. if (d->scanDialog->setup ()) { qCDebug(kpLogMainWindow) << "\t\tOK - showing dialog"; // Called only if scanner configured/available. // // In reality, this seems to be called even if you press "Cancel" in // the KScanDialog::setup() dialog! // // We use exec() to make sure it's modal. show() seems to work too // but better safe than sorry. d->scanDialog->exec (); } else { // Have never seen this code path execute even if "Cancel" is pressed. qCDebug(kpLogMainWindow) << "\t\tFAIL"; } } //--------------------------------------------------------------------- // private slot void kpMainWindow::slotScanned (const QImage &image, int) { qCDebug(kpLogMainWindow) << "kpMainWindow::slotScanned() image.rect=" << image.rect (); qCDebug(kpLogMainWindow) << "\thiding dialog"; // (KScanDialog does not close itself after a scan is made) // // Close the dialog, first thing: // // 1. This means that any dialogs we bring up won't be nested on top. // // 2. We don't want to return from this method but forget to close // the dialog. So do it before anything else. d->scanDialog->hide (); // (just in case there's some drawing between slotScan() exiting and // us being called) toolEndShape (); // TODO: Maybe this code should be moved into kpdocument.cpp - // since it resembles the responsibilities of kpDocument::open(). kpDocumentSaveOptions saveOptions; kpDocumentMetaInfo metaInfo; kpDocument::getDataFromImage(image, saveOptions, metaInfo); // Create document from image and meta info. - kpDocument *doc = new kpDocument (image.width (), image.height (), - documentEnvironment ()); + auto *doc = new kpDocument (image.width (), image.height (), documentEnvironment ()); doc->setImage (image); doc->setSaveOptions (saveOptions); doc->setMetaInfo (metaInfo); // Send document to current or new window. setDocumentChoosingWindow (doc); } #endif // HAVE_KSANE //--------------------------------------------------------------------- void kpMainWindow::slotScreenshot() { toolEndShape(); - QDialog *dialog = new QDialog(this); - QDialogButtonBox *buttons = new QDialogButtonBox(QDialogButtonBox::Ok | + auto *dialog = new QDialog(this); + auto *buttons = new QDialogButtonBox(QDialogButtonBox::Ok | QDialogButtonBox::Cancel, dialog); connect (buttons, &QDialogButtonBox::accepted, dialog, &QDialog::accept); connect (buttons, &QDialogButtonBox::rejected, dialog, &QDialog::reject); - QLabel *label = new QLabel(i18n("Snapshot Delay")); - KPluralHandlingSpinBox *seconds = new KPluralHandlingSpinBox; + auto *label = new QLabel(i18n("Snapshot Delay")); + auto *seconds = new KPluralHandlingSpinBox; seconds->setRange(0, 99); seconds->setSuffix(ki18np(" second", " seconds")); seconds->setSpecialValueText(i18n("No delay")); - QCheckBox *hideWindow = new QCheckBox(i18n("Hide Main Window")); + auto *hideWindow = new QCheckBox(i18n("Hide Main Window")); hideWindow->setChecked(true); - QVBoxLayout *vbox = new QVBoxLayout(dialog); + auto *vbox = new QVBoxLayout(dialog); vbox->addWidget(label); vbox->addWidget(seconds); vbox->addWidget(hideWindow); vbox->addWidget(buttons); if ( dialog->exec() == QDialog::Rejected ) { delete dialog; return; } - if ( hideWindow->isChecked() ) + if ( hideWindow->isChecked() ) { hide(); + } // at least 1 seconds to make sure the window is hidden and the hide effect already stopped QTimer::singleShot((seconds->value() + 1) * 1000, this, SLOT(slotMakeScreenshot())); delete dialog; } //--------------------------------------------------------------------- void kpMainWindow::slotMakeScreenshot() { QCoreApplication::processEvents(); QPixmap pixmap = QGuiApplication::primaryScreen()->grabWindow(QApplication::desktop()->winId()); - kpDocument *doc = new kpDocument(pixmap.width(), pixmap.height(), documentEnvironment()); + auto *doc = new kpDocument(pixmap.width(), pixmap.height(), documentEnvironment()); doc->setImage(pixmap.toImage()); // Send document to current or new window. setDocumentChoosingWindow(doc); show(); // in case we hid the mainwindow, show it again } //--------------------------------------------------------------------- // private slot void kpMainWindow::slotProperties () { toolEndShape (); kpDocumentMetaInfoDialog dialog (document ()->metaInfo (), this); if (dialog.exec () && !dialog.isNoOp ()) { commandHistory ()->addCommand ( new kpDocumentMetaInfoCommand ( i18n ("Document Properties"), dialog.metaInfo ()/*new*/, *document ()->metaInfo ()/*old*/, commandEnvironment ())); } } //--------------------------------------------------------------------- // private slot bool kpMainWindow::save (bool localOnly) { if (d->document->url ().isEmpty () || !QImageWriter::supportedMimeTypes() .contains(d->document->saveOptions ()->mimeType().toLatin1()) || // SYNC: kpDocument::getPixmapFromFile() can't determine quality // from file so it has been set initially to an invalid value. (d->document->saveOptions ()->mimeTypeHasConfigurableQuality () && d->document->saveOptions ()->qualityIsInvalid ()) || (localOnly && !d->document->url ().isLocalFile ())) { return saveAs (localOnly); } - else + + if (d->document->save (false/*no overwrite prompt*/, + !d->document->savedAtLeastOnceBefore ()/*lossy prompt*/)) { - if (d->document->save (false/*no overwrite prompt*/, - !d->document->savedAtLeastOnceBefore ()/*lossy prompt*/)) - { - addRecentURL (d->document->url ()); - return true; - } - else - return false; + addRecentURL (d->document->url ()); + return true; } + + return false; } //--------------------------------------------------------------------- // private slot bool kpMainWindow::slotSave () { toolEndShape (); return save (); } //--------------------------------------------------------------------- // private QUrl kpMainWindow::askForSaveURL (const QString &caption, const QString &startURL, const kpImage &imageToBeSaved, const kpDocumentSaveOptions &startSaveOptions, const kpDocumentMetaInfo &docMetaInfo, const QString &forcedSaveOptionsGroup, bool localOnly, kpDocumentSaveOptions *chosenSaveOptions, bool isSavingForFirstTime, bool *allowOverwritePrompt, bool *allowLossyPrompt) { #if DEBUG_KP_MAIN_WINDOW qCDebug(kpLogMainWindow) << "kpMainWindow::askForURL() startURL=" << startURL; startSaveOptions.printDebug ("\tstartSaveOptions"); #endif bool reparsedConfiguration = false; // KConfig::readEntry() does not actually reread from disk, hence doesn't // realize what other processes have done e.g. Settings / Show Path // so reparseConfiguration() must be called #define SETUP_READ_CFG() \ if (!reparsedConfiguration) \ { \ KSharedConfig::openConfig ()->reparseConfiguration (); \ reparsedConfiguration = true; \ } \ \ KConfigGroup cfg (KSharedConfig::openConfig (), forcedSaveOptionsGroup); - if (chosenSaveOptions) + if (chosenSaveOptions) { *chosenSaveOptions = kpDocumentSaveOptions (); + } - if (allowOverwritePrompt) + if (allowOverwritePrompt) { *allowOverwritePrompt = true; // play it safe for now + } - if (allowLossyPrompt) + if (allowLossyPrompt) { *allowLossyPrompt = true; // play it safe for now + } kpDocumentSaveOptions fdSaveOptions = startSaveOptions; QStringList mimeTypes; - foreach(const QByteArray &type, QImageWriter::supportedMimeTypes()) + for (const auto &type : QImageWriter::supportedMimeTypes()) { mimeTypes << QString::fromLatin1(type); + } qCDebug(kpLogMainWindow) << "\tmimeTypes=" << mimeTypes - << "\tsortedMimeTypes=" << endl; + << "\tsortedMimeTypes="; if (mimeTypes.isEmpty ()) { - qCCritical(kpLogMainWindow) << "No output mimetypes!" << endl; + qCCritical(kpLogMainWindow) << "No output mimetypes!"; return QUrl (); } #define MIME_TYPE_IS_VALID() (!fdSaveOptions.mimeTypeIsInvalid () && \ mimeTypes.contains (fdSaveOptions.mimeType ())) if (!MIME_TYPE_IS_VALID ()) { qCDebug(kpLogMainWindow) << "\tmimeType=" << fdSaveOptions.mimeType () - << " not valid, get default" << endl; + << " not valid, get default"; SETUP_READ_CFG (); fdSaveOptions.setMimeType (kpDocumentSaveOptions::defaultMimeType (cfg)); if (!MIME_TYPE_IS_VALID ()) { qCDebug(kpLogMainWindow) << "\tmimeType=" << fdSaveOptions.mimeType () - << " not valid, get hardcoded" << endl; - if (mimeTypes.contains ("image/png")) + << " not valid, get hardcoded"; + if (mimeTypes.contains ("image/png")) { fdSaveOptions.setMimeType ("image/png"); - else if (mimeTypes.contains ("image/bmp")) + } + else if (mimeTypes.contains ("image/bmp")) { fdSaveOptions.setMimeType ("image/bmp"); - else + } + else { fdSaveOptions.setMimeType (mimeTypes.first ()); + } } } #undef MIME_TYPE_IS_VALID if (fdSaveOptions.colorDepthIsInvalid ()) { SETUP_READ_CFG (); fdSaveOptions.setColorDepth (kpDocumentSaveOptions::defaultColorDepth (cfg)); fdSaveOptions.setDither (kpDocumentSaveOptions::defaultDither (cfg)); } if (fdSaveOptions.qualityIsInvalid ()) { SETUP_READ_CFG (); fdSaveOptions.setQuality (kpDocumentSaveOptions::defaultQuality (cfg)); } fdSaveOptions.printDebug ("\tcorrected saveOptions passed to fileDialog"); - kpDocumentSaveOptionsWidget *saveOptionsWidget = + auto *saveOptionsWidget = new kpDocumentSaveOptionsWidget (imageToBeSaved, fdSaveOptions, docMetaInfo, this); KFileDialog fd (QUrl (startURL), QString(), this, saveOptionsWidget); saveOptionsWidget->setVisualParent (&fd); fd.setWindowTitle (caption); fd.setOperationMode (KFileDialog::Saving); fd.setMimeFilter (mimeTypes, fdSaveOptions.mimeType ()); - if (localOnly) + if (localOnly) { fd.setMode (KFile::File | KFile::LocalOnly); + } connect (&fd, &KFileDialog::filterChanged, saveOptionsWidget, &kpDocumentSaveOptionsWidget::setMimeType); if ( fd.exec() == QDialog::Accepted ) { kpDocumentSaveOptions newSaveOptions = saveOptionsWidget->documentSaveOptions (); newSaveOptions.printDebug ("\tnewSaveOptions"); KConfigGroup cfg (KSharedConfig::openConfig (), forcedSaveOptionsGroup); // Save options user forced - probably want to use them in future kpDocumentSaveOptions::saveDefaultDifferences (cfg, fdSaveOptions, newSaveOptions); cfg.sync (); - if (chosenSaveOptions) + if (chosenSaveOptions) { *chosenSaveOptions = newSaveOptions; + } bool shouldAllowOverwritePrompt = (fd.selectedUrl () != QUrl (startURL) || newSaveOptions.mimeType () != startSaveOptions.mimeType ()); if (allowOverwritePrompt) { *allowOverwritePrompt = shouldAllowOverwritePrompt; qCDebug(kpLogMainWindow) << "\tallowOverwritePrompt=" << *allowOverwritePrompt; } if (allowLossyPrompt) { // SYNC: kpDocumentSaveOptions elements - everything except quality // (one quality setting is "just as lossy" as another so no // need to continually warn due to quality change) *allowLossyPrompt = (isSavingForFirstTime || shouldAllowOverwritePrompt || newSaveOptions.mimeType () != startSaveOptions.mimeType () || newSaveOptions.colorDepth () != startSaveOptions.colorDepth () || newSaveOptions.dither () != startSaveOptions.dither ()); qCDebug(kpLogMainWindow) << "\tallowLossyPrompt=" << *allowLossyPrompt; } qCDebug(kpLogMainWindow) << "\tselectedUrl=" << fd.selectedUrl (); return fd.selectedUrl (); } - else - return QUrl (); + + return QUrl (); #undef SETUP_READ_CFG } //--------------------------------------------------------------------- // private slot bool kpMainWindow::saveAs (bool localOnly) { kpDocumentSaveOptions chosenSaveOptions; bool allowOverwritePrompt, allowLossyPrompt; QUrl chosenURL = askForSaveURL (i18nc ("@title:window", "Save Image As"), d->document->url ().url (), d->document->imageWithSelection (), *d->document->saveOptions (), *d->document->metaInfo (), kpSettingsGroupFileSaveAs, localOnly, &chosenSaveOptions, !d->document->savedAtLeastOnceBefore (), &allowOverwritePrompt, &allowLossyPrompt); - if (chosenURL.isEmpty ()) + if (chosenURL.isEmpty ()) { return false; + } if (!d->document->saveAs (chosenURL, chosenSaveOptions, allowOverwritePrompt, allowLossyPrompt)) { return false; } addRecentURL (chosenURL); return true; } //--------------------------------------------------------------------- // private slot bool kpMainWindow::slotSaveAs () { toolEndShape (); return saveAs (); } //--------------------------------------------------------------------- // private slot bool kpMainWindow::slotExport () { toolEndShape (); kpDocumentSaveOptions chosenSaveOptions; bool allowOverwritePrompt, allowLossyPrompt; QUrl chosenURL = askForSaveURL (i18nc ("@title:window", "Export"), d->lastExportURL.url (), d->document->imageWithSelection (), d->lastExportSaveOptions, *d->document->metaInfo (), kpSettingsGroupFileExport, false/*allow remote files*/, &chosenSaveOptions, d->exportFirstTime, &allowOverwritePrompt, &allowLossyPrompt); - if (chosenURL.isEmpty ()) + if (chosenURL.isEmpty ()) { return false; + } if (!kpDocument::savePixmapToFile (d->document->imageWithSelection (), chosenURL, chosenSaveOptions, *d->document->metaInfo (), allowOverwritePrompt, allowLossyPrompt, this)) { return false; } addRecentURL (chosenURL); d->lastExportURL = chosenURL; d->lastExportSaveOptions = chosenSaveOptions; d->exportFirstTime = false; return true; } //--------------------------------------------------------------------- // private slot void kpMainWindow::slotEnableReload () { d->actionReload->setEnabled (d->document); } //--------------------------------------------------------------------- // private slot bool kpMainWindow::slotReload () { toolEndShape (); Q_ASSERT (d->document); QUrl oldURL = d->document->url (); if (d->document->isModified ()) { int result = KMessageBox::Cancel; if (d->document->isFromURL (false/*don't bother checking exists*/) && !oldURL.isEmpty ()) { result = KMessageBox::warningContinueCancel (this, i18n ("The document \"%1\" has been modified.\n" "Reloading will lose all changes since you last saved it.\n" "Are you sure?", d->document->prettyFilename ()), QString()/*caption*/, KGuiItem(i18n ("&Reload"))); } else { result = KMessageBox::warningContinueCancel (this, i18n ("The document \"%1\" has been modified.\n" "Reloading will lose all changes.\n" "Are you sure?", d->document->prettyFilename ()), QString()/*caption*/, KGuiItem(i18n ("&Reload"))); } - if (result != KMessageBox::Continue) + if (result != KMessageBox::Continue) { return false; + } } kpDocument *doc = nullptr; // If it's _supposed to_ come from a URL or it exists if (d->document->isFromURL (false/*don't bother checking exists*/) || (!oldURL.isEmpty () && KIO::NetAccess::exists (oldURL, KIO::NetAccess::SourceSide/*open*/, this))) { qCDebug(kpLogMainWindow) << "kpMainWindow::slotReload() reloading from disk!"; doc = new kpDocument (1, 1, documentEnvironment ()); if (!doc->open (oldURL)) { delete doc; doc = nullptr; return false; } addRecentURL (oldURL); } else { qCDebug(kpLogMainWindow) << "kpMainWindow::slotReload() create doc"; doc = new kpDocument (d->document->constructorWidth (), d->document->constructorHeight (), documentEnvironment ()); doc->setURL (oldURL, false/*not from URL*/); } setDocument (doc); return true; } // private void kpMainWindow::sendDocumentNameToPrinter (QPrinter *printer) { QUrl url = d->document->url (); if (!url.isEmpty ()) { int dot; QString fileName = url.fileName (); dot = fileName.lastIndexOf ('.'); // file.ext but not .hidden-file? - if (dot > 0) + if (dot > 0) { fileName.truncate (dot); + } qCDebug(kpLogMainWindow) << "kpMainWindow::sendDocumentNameToPrinter() fileName=" << fileName << " dir=" - << url.path() - << endl; + << url.path(); printer->setDocName (fileName); } } //-------------------------------------------------------------------------------- void kpMainWindow::sendPreviewToPrinter(QPrinter *printer) { sendImageToPrinter(printer, false); } //-------------------------------------------------------------------------------- // private void kpMainWindow::sendImageToPrinter (QPrinter *printer, bool showPrinterSetupDialog) { // Get image to be printed. kpImage image = d->document->imageWithSelection (); // Get image DPI. - double imageDotsPerMeterX = - double (d->document->metaInfo ()->dotsPerMeterX ()); - double imageDotsPerMeterY = - double (d->document->metaInfo ()->dotsPerMeterY ()); + auto imageDotsPerMeterX = double (d->document->metaInfo ()->dotsPerMeterX ()); + auto imageDotsPerMeterY = double (d->document->metaInfo ()->dotsPerMeterY ()); qCDebug(kpLogMainWindow) << "kpMainWindow::sendImageToPrinter() image:" << " width=" << image.width () << " height=" << image.height () << " dotsPerMeterX=" << imageDotsPerMeterX - << " dotsPerMeterY=" << imageDotsPerMeterY - << endl; + << " dotsPerMeterY=" << imageDotsPerMeterY; // Image DPI invalid (e.g. new image, could not read from file // or Qt3 doesn't implement DPI for JPEG)? if (imageDotsPerMeterX <= 0 || imageDotsPerMeterY <= 0) { // Even if just one DPI dimension is invalid, mutate both DPI // dimensions as we have no information about the intended // aspect ratio anyway (and other dimension likely to be invalid). // When rendering text onto a document, the fonts are rasterised // according to the screen's DPI. // TODO: I think we should use the image's DPI. Technically // possible? // // So no matter what computer you draw text on, you get // the same pixels. // // So we must print at the screen's DPI to get the right text size. // // Unfortunately, this means that moving to a different screen DPI // affects printing. If you edited the image at a different screen // DPI than when you print, you get incorrect results. Furthermore, // this is bogus if you don't have text in your image. Worse still, // what if you have multiple screens connected to the same computer // with different DPIs? // TODO: mysteriously, someone else is setting this to 96dpi always. QPixmap arbitraryScreenElement(1, 1); const QPaintDevice *screenDevice = &arbitraryScreenElement; - const int dpiX = screenDevice->logicalDpiX (), - dpiY = screenDevice->logicalDpiY (); + const auto dpiX = screenDevice->logicalDpiX (); + const auto dpiY = screenDevice->logicalDpiY (); qCDebug(kpLogMainWindow) << "\tusing screen dpi: x=" << dpiX << " y=" << dpiY; imageDotsPerMeterX = dpiX * KP_INCHES_PER_METER; imageDotsPerMeterY = dpiY * KP_INCHES_PER_METER; } // Get page size (excluding margins). // Coordinate (0,0) is the X here: // mmmmm // mX m // m m m = margin // m m // mmmmm - const int printerWidthMM = printer->widthMM (); - const int printerHeightMM = printer->heightMM (); + const auto printerWidthMM = printer->widthMM (); + const auto printerHeightMM = printer->heightMM (); qCDebug(kpLogMainWindow) << "\tprinter: widthMM=" << printerWidthMM - << " heightMM=" << printerHeightMM - << endl; + << " heightMM=" << printerHeightMM; - double dpiX = imageDotsPerMeterX / KP_INCHES_PER_METER; - double dpiY = imageDotsPerMeterY / KP_INCHES_PER_METER; + auto dpiX = imageDotsPerMeterX / KP_INCHES_PER_METER; + auto dpiY = imageDotsPerMeterY / KP_INCHES_PER_METER; qCDebug(kpLogMainWindow) << "\timage: dpiX=" << dpiX << " dpiY=" << dpiY; # // // If image doesn't fit on page at intended DPI, change the DPI. // - const double scaleDpiX = - (image.width () / (printerWidthMM / KP_MILLIMETERS_PER_INCH)) - / dpiX; - const double scaleDpiY = - (image.height () / (printerHeightMM / KP_MILLIMETERS_PER_INCH)) - / dpiY; - const double scaleDpi = qMax (scaleDpiX, scaleDpiY); + const auto scaleDpiX = + (image.width () / (printerWidthMM / KP_MILLIMETERS_PER_INCH)) / dpiX; + const auto scaleDpiY = + (image.height () / (printerHeightMM / KP_MILLIMETERS_PER_INCH)) / dpiY; + const auto scaleDpi = qMax (scaleDpiX, scaleDpiY); qCDebug(kpLogMainWindow) << "\t\tscaleDpi: x=" << scaleDpiX << " y=" << scaleDpiY - << " --> scale at " << scaleDpi << " to fit?" - << endl; + << " --> scale at " << scaleDpi << " to fit?"; // Need to increase resolution to fit page? if (scaleDpi > 1.0) { dpiX *= scaleDpi; dpiY *= scaleDpi; qCDebug(kpLogMainWindow) << "\t\t\tto fit page, scaled to:" - << " dpiX=" << dpiX << " dpiY=" << dpiY << endl; + << " dpiX=" << dpiX << " dpiY=" << dpiY; } // Make sure DPIs are equal as that's all QPrinter::setResolution() // supports. We do this in such a way that we only ever stretch an // image, to avoid losing information. Don't antialias as the printer // will do that to translate our DPI to its physical resolution and // double-antialiasing looks bad. if (dpiX > dpiY) { qCDebug(kpLogMainWindow) << "\tdpiX > dpiY; stretching image height to equalise DPIs to dpiX=" - << dpiX << endl; + << dpiX; kpPixmapFX::scale (&image, image.width (), qMax (1, qRound (image.height () * dpiX / dpiY)), false/*don't antialias*/); dpiY = dpiX; } else if (dpiY > dpiX) { qCDebug(kpLogMainWindow) << "\tdpiY > dpiX; stretching image width to equalise DPIs to dpiY=" - << dpiY << endl; + << dpiY; kpPixmapFX::scale (&image, qMax (1, qRound (image.width () * dpiY / dpiX)), image.height (), false/*don't antialias*/); dpiX = dpiY; } Q_ASSERT (dpiX == dpiY); // QPrinter::setResolution() has to be called before QPrinter::setup(). printer->setResolution (qMax (1, qRound (dpiX))); sendDocumentNameToPrinter (printer); if (showPrinterSetupDialog) { - kpPrintDialogPage *optionsPage = new kpPrintDialogPage (this); + auto *optionsPage = new kpPrintDialogPage (this); optionsPage->setPrintImageCenteredOnPage (d->configPrintImageCenteredOnPage); QPrintDialog *printDialog = KdePrint::createPrintDialog ( printer, QList () << optionsPage, this); printDialog->setWindowTitle (i18nc ("@title:window", "Print Image")); // Display dialog. const bool wantToPrint = printDialog->exec (); if (optionsPage->printImageCenteredOnPage () != d->configPrintImageCenteredOnPage) { // Save config option even if the dialog was cancelled. d->configPrintImageCenteredOnPage = optionsPage->printImageCenteredOnPage (); KConfigGroup cfg (KSharedConfig::openConfig (), kpSettingsGroupGeneral); cfg.writeEntry (kpSettingPrintImageCenteredOnPage, d->configPrintImageCenteredOnPage); cfg.sync (); } delete printDialog; - if (!wantToPrint) + if (!wantToPrint) { return; + } } // Send image to printer. QPainter painter; painter.begin(printer); double originX = 0, originY = 0; // Center image on page? if (d->configPrintImageCenteredOnPage) { originX = (printer->width() - image.width ()) / 2; originY = (printer->height() - image.height ()) / 2; } painter.drawImage(qRound(originX), qRound(originY), image); painter.end(); } //--------------------------------------------------------------------- // private slot void kpMainWindow::slotPrint () { toolEndShape (); QPrinter printer; sendImageToPrinter (&printer, true/*showPrinterSetupDialog*/); } //--------------------------------------------------------------------- // private slot void kpMainWindow::slotPrintPreview () { toolEndShape (); QPrintPreviewDialog printPreview(this); connect(&printPreview, &QPrintPreviewDialog::paintRequested, this, &kpMainWindow::sendPreviewToPrinter); printPreview.exec (); } //--------------------------------------------------------------------- // private slot void kpMainWindow::slotMail () { toolEndShape (); if (d->document->url ().isEmpty ()/*no name*/ || !d->document->isFromURL () || d->document->isModified ()/*needs to be saved*/) { int result = KMessageBox::questionYesNo (this, i18n ("You must save this image before sending it.\n" "Do you want to save it?"), QString(), KStandardGuiItem::save (), KStandardGuiItem::cancel ()); if (result == KMessageBox::Yes) { if (!save ()) { // save failed or aborted - don't email return; } } else { // don't want to save - don't email return; } } KToolInvocation::invokeMailer ( QString()/*to*/, QString()/*cc*/, QString()/*bcc*/, d->document->prettyFilename()/*subject*/, QString()/*body*/, QString()/*messageFile*/, QStringList(d->document->url().url())/*attachments*/); } //--------------------------------------------------------------------- // private bool kpMainWindow::queryCloseDocument () { toolEndShape (); - if (!d->document || !d->document->isModified ()) + if (!d->document || !d->document->isModified ()) { return true; // ok to close current doc + } int result = KMessageBox::warningYesNoCancel (this, i18n ("The document \"%1\" has been modified.\n" "Do you want to save it?", d->document->prettyFilename ()), QString()/*caption*/, KStandardGuiItem::save (), KStandardGuiItem::discard ()); switch (result) { case KMessageBox::Yes: return slotSave (); // close only if save succeeds case KMessageBox::No: return true; // close without saving default: return false; // don't close current doc } } //--------------------------------------------------------------------- // private virtual [base KMainWindow] bool kpMainWindow::queryClose () { #if DEBUG_KP_MAIN_WINDOW qCDebug(kpLogMainWindow) << "kpMainWindow::queryClose()"; #endif toolEndShape (); - if (!queryCloseDocument ()) + if (!queryCloseDocument ()) { return false; + } - if (!queryCloseColors ()) + if (!queryCloseColors ()) { return false; + } return true; } //--------------------------------------------------------------------- // private slot void kpMainWindow::slotClose () { toolEndShape (); - if (!queryCloseDocument ()) + if (!queryCloseDocument ()) { return; + } setDocument (nullptr); } //--------------------------------------------------------------------- // private slot void kpMainWindow::slotQuit () { toolEndShape (); close (); // will call queryClose() } //--------------------------------------------------------------------- diff --git a/mainWindow/kpMainWindow_Image.cpp b/mainWindow/kpMainWindow_Image.cpp index 7fa204c1..e5d43c78 100644 --- a/mainWindow/kpMainWindow_Image.cpp +++ b/mainWindow/kpMainWindow_Image.cpp @@ -1,617 +1,621 @@ /* Copyright (c) 2003-2007 Clarence Dang All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include "mainWindow/kpMainWindow.h" #include "kpMainWindowPrivate.h" #include "layers/selections/image/kpAbstractImageSelection.h" #include "imagelib/kpColor.h" #include "kpDefs.h" #include "widgets/toolbars/kpColorToolBar.h" #include "commands/kpCommandHistory.h" #include "document/kpDocument.h" #include "commands/imagelib/effects/kpEffectInvertCommand.h" #include "commands/imagelib/effects/kpEffectReduceColorsCommand.h" #include "dialogs/imagelib/effects/kpEffectsDialog.h" #include "commands/imagelib/effects/kpEffectClearCommand.h" #include "commands/imagelib/effects/kpEffectGrayscaleCommand.h" #include "commands/kpMacroCommand.h" #include "layers/selections/text/kpTextSelection.h" #include "commands/tools/selection/kpToolSelectionCreateCommand.h" #include "commands/tools/selection/kpToolSelectionPullFromDocumentCommand.h" #include "commands/tools/selection/text/kpToolTextGiveContentCommand.h" #include "imagelib/transforms/kpTransformAutoCrop.h" #include "imagelib/transforms/kpTransformCrop.h" #include "environments/dialogs/imagelib/transforms/kpTransformDialogEnvironment.h" #include "commands/imagelib/transforms/kpTransformFlipCommand.h" #include "commands/imagelib/transforms/kpTransformResizeScaleCommand.h" #include "dialogs/imagelib/transforms/kpTransformResizeScaleDialog.h" #include "commands/imagelib/transforms/kpTransformRotateCommand.h" #include "dialogs/imagelib/transforms/kpTransformRotateDialog.h" #include "commands/imagelib/transforms/kpTransformSkewCommand.h" #include "dialogs/imagelib/transforms/kpTransformSkewDialog.h" #include "views/manager/kpViewManager.h" #include "commands/imagelib/effects/kpEffectBlurSharpenCommand.h" #include "imagelib/effects/kpEffectBlurSharpen.h" #include "kpLogCategories.h" #include #include #include #include #include #include #include #include //--------------------------------------------------------------------- // private kpTransformDialogEnvironment *kpMainWindow::transformDialogEnvironment () { if (!d->transformDialogEnvironment) d->transformDialogEnvironment = new kpTransformDialogEnvironment (this); return d->transformDialogEnvironment; } //--------------------------------------------------------------------- // private bool kpMainWindow::isSelectionActive () const { return (d->document ? bool (d->document->selection ()) : false); } //--------------------------------------------------------------------- // private bool kpMainWindow::isTextSelection () const { return (d->document && d->document->textSelection ()); } //--------------------------------------------------------------------- // private QString kpMainWindow::autoCropText () const { return kpTransformAutoCropCommand::text(isSelectionActive(), kpTransformAutoCropCommand::ShowAccel); } //--------------------------------------------------------------------- // private void kpMainWindow::setupImageMenuActions () { KActionCollection *ac = actionCollection (); d->actionResizeScale = ac->addAction ("image_resize_scale"); d->actionResizeScale->setText (i18n ("R&esize / Scale...")); connect (d->actionResizeScale, &QAction::triggered, this, &kpMainWindow::slotResizeScale); ac->setDefaultShortcut (d->actionResizeScale, Qt::CTRL + Qt::Key_E); d->actionCrop = ac->addAction ("image_crop"); d->actionCrop->setText (i18n ("Se&t as Image (Crop)")); connect (d->actionCrop, &QAction::triggered, this, &kpMainWindow::slotCrop); ac->setDefaultShortcut (d->actionCrop, Qt::CTRL + Qt::Key_T); d->actionAutoCrop = ac->addAction ("image_auto_crop"); d->actionAutoCrop->setText (autoCropText ()); connect (d->actionAutoCrop, &QAction::triggered, this, &kpMainWindow::slotAutoCrop); ac->setDefaultShortcut (d->actionAutoCrop, Qt::CTRL + Qt::Key_U); d->actionFlip = ac->addAction ("image_flip"); d->actionFlip->setText (i18n ("&Flip (upside down)")); connect (d->actionFlip, &QAction::triggered, this, &kpMainWindow::slotFlip); ac->setDefaultShortcut (d->actionFlip, Qt::CTRL + Qt::Key_F); d->actionMirror = ac->addAction ("image_mirror"); d->actionMirror->setText (i18n ("Mirror (horizontally)")); connect (d->actionMirror, &QAction::triggered, this, &kpMainWindow::slotMirror); //ac->setDefaultShortcut (d->actionMirror, Qt::CTRL + Qt::Key_M); d->actionRotate = ac->addAction ("image_rotate"); d->actionRotate->setText (i18n ("&Rotate...")); d->actionRotate->setIcon(KDE::icon("transform-rotate")); connect (d->actionRotate, &QAction::triggered, this, &kpMainWindow::slotRotate); ac->setDefaultShortcut (d->actionRotate, Qt::CTRL + Qt::Key_R); d->actionRotateLeft = ac->addAction ("image_rotate_270deg"); d->actionRotateLeft->setText (i18n ("Rotate &Left")); d->actionRotateLeft->setIcon(KDE::icon("object-rotate-left")); connect (d->actionRotateLeft, &QAction::triggered, this, &kpMainWindow::slotRotate270); ac->setDefaultShortcut (d->actionRotateLeft, Qt::CTRL + Qt::SHIFT + Qt::Key_Left); d->actionRotateRight = ac->addAction ("image_rotate_90deg"); d->actionRotateRight->setText (i18n ("Rotate Righ&t")); d->actionRotateRight->setIcon(KDE::icon("object-rotate-right")); connect (d->actionRotateRight, &QAction::triggered, this, &kpMainWindow::slotRotate90); ac->setDefaultShortcut (d->actionRotateRight, Qt::CTRL + Qt::SHIFT + Qt::Key_Right); d->actionSkew = ac->addAction ("image_skew"); d->actionSkew->setText (i18n ("S&kew...")); connect (d->actionSkew, &QAction::triggered, this, &kpMainWindow::slotSkew); ac->setDefaultShortcut (d->actionSkew, Qt::CTRL + Qt::Key_K); d->actionConvertToBlackAndWhite = ac->addAction ("image_convert_to_black_and_white"); d->actionConvertToBlackAndWhite->setText (i18n ("Reduce to Mo&nochrome (Dithered)")); connect (d->actionConvertToBlackAndWhite, &QAction::triggered, this, &kpMainWindow::slotConvertToBlackAndWhite); d->actionConvertToGrayscale = ac->addAction ("image_convert_to_grayscale"); d->actionConvertToGrayscale->setText (i18n ("Reduce to &Grayscale")); connect (d->actionConvertToGrayscale, &QAction::triggered, this, &kpMainWindow::slotConvertToGrayscale); d->actionInvertColors = ac->addAction ("image_invert_colors"); d->actionInvertColors->setText (i18n ("&Invert Colors")); connect (d->actionInvertColors, &QAction::triggered, this, &kpMainWindow::slotInvertColors); ac->setDefaultShortcut (d->actionInvertColors, Qt::CTRL + Qt::Key_I); d->actionClear = ac->addAction ("image_clear"); d->actionClear->setText (i18n ("C&lear")); connect (d->actionClear, &QAction::triggered, this, &kpMainWindow::slotClear); ac->setDefaultShortcut (d->actionClear, Qt::CTRL + Qt::SHIFT + Qt::Key_N); d->actionBlur = ac->addAction("image_make_confidential"); d->actionBlur->setText(i18n("Make Confidential")); connect(d->actionBlur, &QAction::triggered, this, &kpMainWindow::slotMakeConfidential); d->actionMoreEffects = ac->addAction ("image_more_effects"); d->actionMoreEffects->setText (i18n ("&More Effects...")); connect (d->actionMoreEffects, &QAction::triggered, this, &kpMainWindow::slotMoreEffects); ac->setDefaultShortcut (d->actionMoreEffects, Qt::CTRL + Qt::Key_M); enableImageMenuDocumentActions (false); } //--------------------------------------------------------------------- // private void kpMainWindow::enableImageMenuDocumentActions (bool enable) { d->actionResizeScale->setEnabled (enable); d->actionCrop->setEnabled (enable); d->actionAutoCrop->setEnabled (enable); d->actionFlip->setEnabled (enable); d->actionMirror->setEnabled (enable); d->actionRotate->setEnabled (enable); d->actionRotateLeft->setEnabled (enable); d->actionRotateRight->setEnabled (enable); d->actionSkew->setEnabled (enable); d->actionConvertToBlackAndWhite->setEnabled (enable); d->actionConvertToGrayscale->setEnabled (enable); d->actionInvertColors->setEnabled (enable); d->actionClear->setEnabled (enable); d->actionBlur->setEnabled (enable); d->actionMoreEffects->setEnabled (enable); d->imageMenuDocumentActionsEnabled = enable; } //--------------------------------------------------------------------- // private slot void kpMainWindow::slotImageMenuUpdateDueToSelection () { // SYNC: kolourpaintui.rc const QString MenuBarItemTextImage = i18nc ( "Image/Selection Menu caption - make sure the translation has" " the same accel as the Select&ion translation", "&Image"); const QString MenuBarItemTextSelection = i18nc ( "Image/Selection Menu caption - make sure that translation has" " the same accel as the &Image translation", "Select&ion"); Q_ASSERT (menuBar ()); - foreach (QAction *action, menuBar ()->actions ()) + for (auto *action : menuBar ()->actions ()) { if (action->text () == MenuBarItemTextImage || action->text () == MenuBarItemTextSelection) { - if (isSelectionActive ()) + if (isSelectionActive ()) { action->setText (MenuBarItemTextSelection); - else + } + else { action->setText (MenuBarItemTextImage); + } break; } } d->actionResizeScale->setEnabled (d->imageMenuDocumentActionsEnabled); d->actionCrop->setEnabled (d->imageMenuDocumentActionsEnabled && isSelectionActive ()); const bool enable = (d->imageMenuDocumentActionsEnabled && !isTextSelection ()); d->actionAutoCrop->setText (autoCropText ()); d->actionAutoCrop->setEnabled (enable); d->actionFlip->setEnabled (enable); d->actionMirror->setEnabled (enable); d->actionRotate->setEnabled (enable); d->actionRotateLeft->setEnabled (enable); d->actionRotateRight->setEnabled (enable); d->actionSkew->setEnabled (enable); d->actionConvertToBlackAndWhite->setEnabled (enable); d->actionConvertToGrayscale->setEnabled (enable); d->actionInvertColors->setEnabled (enable); d->actionClear->setEnabled (enable); d->actionBlur->setEnabled (enable); d->actionMoreEffects->setEnabled (enable); } //--------------------------------------------------------------------- // public kpColor kpMainWindow::backgroundColor (bool ofSelection) const { - if (ofSelection) + if (ofSelection) { return kpColor::Transparent; - else - { - Q_ASSERT (d->colorToolBar); - return d->colorToolBar->backgroundColor (); } + + Q_ASSERT (d->colorToolBar); + return d->colorToolBar->backgroundColor (); } //--------------------------------------------------------------------- // public // REFACTOR: sync: Code dup with kpAbstractSelectionTool::addNeedingContentCommand(). void kpMainWindow::addImageOrSelectionCommand (kpCommand *cmd, bool addSelCreateCmdIfSelAvail, bool addSelContentCmdIfSelAvail) { qCDebug(kpLogMainWindow) << "kpMainWindow::addImageOrSelectionCommand()" << " addSelCreateCmdIfSelAvail=" << addSelCreateCmdIfSelAvail - << " addSelContentCmdIfSelAvail=" << addSelContentCmdIfSelAvail - << endl; + << " addSelContentCmdIfSelAvail=" << addSelContentCmdIfSelAvail; Q_ASSERT (d->document); - if (d->viewManager) + if (d->viewManager) { d->viewManager->setQueueUpdates (); + } kpAbstractSelection *sel = d->document->selection (); qCDebug(kpLogMainWindow) << "\timage sel=" << sel - << " sel->hasContent=" << (sel ? sel->hasContent () : 0) - << endl; + << " sel->hasContent=" << (sel ? sel->hasContent () : 0); if (addSelCreateCmdIfSelAvail && sel && !sel->hasContent ()) { QString createCmdName; - if (dynamic_cast (sel)) + if (dynamic_cast (sel)) { createCmdName = i18n ("Selection: Create"); - else if (dynamic_cast (sel)) + } + else if (dynamic_cast (sel)) { createCmdName = i18n ("Text: Create Box"); - else + } + else { Q_ASSERT (!"Unknown selection type"); + } // create selection region commandHistory ()->addCreateSelectionCommand ( new kpToolSelectionCreateCommand ( createCmdName, *sel, commandEnvironment ()), false/*no exec - user already dragged out sel*/); } if (addSelContentCmdIfSelAvail && sel && !sel->hasContent ()) { - kpAbstractImageSelection *imageSel = - dynamic_cast (sel); - kpTextSelection *textSel = - dynamic_cast (sel); + auto *imageSel = dynamic_cast (sel); + auto *textSel = dynamic_cast (sel); - if (imageSel && imageSel->transparency ().isTransparent ()) + if (imageSel && imageSel->transparency ().isTransparent ()) { d->colorToolBar->flashColorSimilarityToolBarItem (); + } kpMacroCommand *macroCmd = new kpMacroCommand (cmd->name (), commandEnvironment ()); if (imageSel) { macroCmd->addCommand ( new kpToolSelectionPullFromDocumentCommand ( *imageSel, backgroundColor (), QString()/*uninteresting child of macro cmd*/, commandEnvironment ())); } else if (textSel) { macroCmd->addCommand ( new kpToolTextGiveContentCommand ( *textSel, QString()/*uninteresting child of macro cmd*/, commandEnvironment ())); } - else + else { Q_ASSERT (!"Unknown selection type"); + } macroCmd->addCommand (cmd); d->commandHistory->addCommand (macroCmd); } else { d->commandHistory->addCommand (cmd); } - if (d->viewManager) + if (d->viewManager) { d->viewManager->restoreQueueUpdates (); + } } //--------------------------------------------------------------------- // private slot void kpMainWindow::slotResizeScale () { toolEndShape (); kpTransformResizeScaleDialog dialog(transformDialogEnvironment(), this); if (dialog.exec () && !dialog.isNoOp ()) { - kpTransformResizeScaleCommand *cmd = new kpTransformResizeScaleCommand ( + auto *cmd = new kpTransformResizeScaleCommand ( dialog.actOnSelection (), dialog.imageWidth (), dialog.imageHeight (), dialog.type (), commandEnvironment ()); bool addSelCreateCommand = (dialog.actOnSelection () || cmd->scaleSelectionWithImage ()); bool addSelContentCommand = dialog.actOnSelection (); addImageOrSelectionCommand ( cmd, addSelCreateCommand, addSelContentCommand); // Resized document? if (!dialog.actOnSelection () && dialog.type () == kpTransformResizeScaleCommand::Resize) { // TODO: this should be the responsibility of kpDocument saveDefaultDocSize (QSize (dialog.imageWidth (), dialog.imageHeight ())); } } } //--------------------------------------------------------------------- // public slot void kpMainWindow::slotCrop () { toolEndShape (); Q_ASSERT (d->document && d->document->selection ()); ::kpTransformCrop (this); } //--------------------------------------------------------------------- // private slot void kpMainWindow::slotAutoCrop () { toolEndShape (); ::kpTransformAutoCrop (this); } //--------------------------------------------------------------------- // private slot void kpMainWindow::slotFlip() { toolEndShape(); addImageOrSelectionCommand( new kpTransformFlipCommand(d->document->selection(), false, true, commandEnvironment())); } //--------------------------------------------------------------------- // private slot void kpMainWindow::slotMirror() { toolEndShape(); addImageOrSelectionCommand( new kpTransformFlipCommand(d->document->selection(), true, false, commandEnvironment())); } //--------------------------------------------------------------------- // private slot void kpMainWindow::slotRotate () { toolEndShape (); kpTransformRotateDialog dialog (static_cast (d->document->selection ()), transformDialogEnvironment (), this); if (dialog.exec () && !dialog.isNoOp ()) { addImageOrSelectionCommand ( new kpTransformRotateCommand (d->document->selection (), dialog.angle (), commandEnvironment ())); } } // private slot void kpMainWindow::slotRotate270 () { toolEndShape (); // TODO: Special command name instead of just "Rotate"? addImageOrSelectionCommand ( new kpTransformRotateCommand ( d->document->selection (), 270, commandEnvironment ())); } // private slot void kpMainWindow::slotRotate90 () { toolEndShape (); // TODO: Special command name instead of just "Rotate"? addImageOrSelectionCommand ( new kpTransformRotateCommand ( d->document->selection (), 90, commandEnvironment ())); } // private slot void kpMainWindow::slotSkew () { toolEndShape (); kpTransformSkewDialog dialog (static_cast (d->document->selection ()), transformDialogEnvironment (), this); if (dialog.exec () && !dialog.isNoOp ()) { addImageOrSelectionCommand ( new kpTransformSkewCommand (d->document->selection (), dialog.horizontalAngle (), dialog.verticalAngle (), commandEnvironment ())); } } //--------------------------------------------------------------------- // private slot void kpMainWindow::slotConvertToBlackAndWhite () { toolEndShape (); addImageOrSelectionCommand ( new kpEffectReduceColorsCommand (1/*depth*/, true/*dither*/, d->document->selection (), commandEnvironment ())); } //--------------------------------------------------------------------- // private slot void kpMainWindow::slotConvertToGrayscale () { toolEndShape (); addImageOrSelectionCommand ( new kpEffectGrayscaleCommand (d->document->selection (), commandEnvironment ())); } //-------------------------------------------------------------------------------- // private slot void kpMainWindow::slotInvertColors () { toolEndShape (); addImageOrSelectionCommand ( new kpEffectInvertCommand (d->document->selection (), commandEnvironment ())); } //-------------------------------------------------------------------------------- // private slot void kpMainWindow::slotClear () { toolEndShape (); addImageOrSelectionCommand ( new kpEffectClearCommand ( d->document->selection (), backgroundColor (), commandEnvironment ())); } //-------------------------------------------------------------------------------- void kpMainWindow::slotMakeConfidential() { toolEndShape(); addImageOrSelectionCommand( new kpEffectBlurSharpenCommand(kpEffectBlurSharpen::MakeConfidential, kpEffectBlurSharpen::MaxStrength, d->document->selection(), commandEnvironment())); } //-------------------------------------------------------------------------------- // private slot void kpMainWindow::slotMoreEffects () { toolEndShape (); kpEffectsDialog dialog (static_cast (d->document->selection ()), transformDialogEnvironment (), this, d->moreEffectsDialogLastEffect); if (dialog.exec () && !dialog.isNoOp ()) { addImageOrSelectionCommand (dialog.createCommand ()); } if (d->moreEffectsDialogLastEffect != dialog.selectedEffect ()) { d->moreEffectsDialogLastEffect = dialog.selectedEffect (); KConfigGroup cfg (KSharedConfig::openConfig (), kpSettingsGroupGeneral); cfg.writeEntry (kpSettingMoreEffectsLastEffect, d->moreEffectsDialogLastEffect); cfg.sync (); } } //-------------------------------------------------------------------------------- diff --git a/mainWindow/kpMainWindow_Settings.cpp b/mainWindow/kpMainWindow_Settings.cpp index a9f56fba..b3cd86f6 100644 --- a/mainWindow/kpMainWindow_Settings.cpp +++ b/mainWindow/kpMainWindow_Settings.cpp @@ -1,156 +1,156 @@ /* Copyright (c) 2003-2007 Clarence Dang All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include "mainWindow/kpMainWindow.h" #include "kpMainWindowPrivate.h" #include "kpLogCategories.h" #include #include #include #include #include #include #include #include "kpDefs.h" #include "document/kpDocument.h" #include "tools/kpToolAction.h" #include "widgets/toolbars/kpToolToolBar.h" #include "environments/tools/kpToolEnvironment.h" //--------------------------------------------------------------------- // private void kpMainWindow::setupSettingsMenuActions () { KActionCollection *ac = actionCollection (); // Settings/Toolbars |> %s setStandardToolBarMenuEnabled (true); // Settings/Show Statusbar createStandardStatusBarAction (); d->actionFullScreen = KStandardAction::fullScreen (this, SLOT (slotFullScreen()), this/*window*/, ac); d->actionShowPath = ac->add ("settings_show_path"); d->actionShowPath->setText (i18n ("Show &Path")); connect (d->actionShowPath, &QAction::triggered, this, &kpMainWindow::slotShowPathToggled); slotEnableSettingsShowPath (); - KToggleAction *action = ac->add("settings_draw_antialiased"); + auto *action = ac->add("settings_draw_antialiased"); action->setText(i18n("Draw Anti-Aliased")); action->setChecked(kpToolEnvironment::drawAntiAliased); connect (action, &KToggleAction::triggered, this, &kpMainWindow::slotDrawAntiAliasedToggled); d->actionKeyBindings = KStandardAction::keyBindings (this, SLOT (slotKeyBindings()), ac); KStandardAction::configureToolbars(this, SLOT(configureToolbars()), actionCollection()); enableSettingsMenuDocumentActions (false); } //--------------------------------------------------------------------- // private void kpMainWindow::enableSettingsMenuDocumentActions (bool /*enable*/) { } //--------------------------------------------------------------------- // private slot void kpMainWindow::slotFullScreen () { KToggleFullScreenAction::setFullScreen( this, d->actionFullScreen->isChecked ()); } //--------------------------------------------------------------------- // private slot void kpMainWindow::slotEnableSettingsShowPath () { qCDebug(kpLogMainWindow) << "kpMainWindow::slotEnableSettingsShowPath()"; const bool enable = (d->document && !d->document->url ().isEmpty ()); d->actionShowPath->setEnabled (enable); d->actionShowPath->setChecked (enable && d->configShowPath); } //--------------------------------------------------------------------- // private slot void kpMainWindow::slotShowPathToggled () { qCDebug(kpLogMainWindow) << "kpMainWindow::slotShowPathToggled()"; d->configShowPath = d->actionShowPath->isChecked (); slotUpdateCaption (); KConfigGroup cfg (KSharedConfig::openConfig (), kpSettingsGroupGeneral); cfg.writeEntry (kpSettingShowPath, d->configShowPath); cfg.sync (); } //--------------------------------------------------------------------- void kpMainWindow::slotDrawAntiAliasedToggled(bool on) { kpToolEnvironment::drawAntiAliased = on; KConfigGroup cfg(KSharedConfig::openConfig(), kpSettingsGroupGeneral); cfg.writeEntry(kpSettingDrawAntiAliased, kpToolEnvironment::drawAntiAliased); cfg.sync(); } //--------------------------------------------------------------------- // private slot void kpMainWindow::slotKeyBindings () { toolEndShape (); if (KShortcutsDialog::configure (actionCollection (), KShortcutsEditor::LetterShortcutsAllowed, this)) { // TODO: PROPAGATE: thru mainWindow's and interprocess } } //--------------------------------------------------------------------- diff --git a/mainWindow/kpMainWindow_StatusBar.cpp b/mainWindow/kpMainWindow_StatusBar.cpp index 2651cd76..34472d51 100644 --- a/mainWindow/kpMainWindow_StatusBar.cpp +++ b/mainWindow/kpMainWindow_StatusBar.cpp @@ -1,417 +1,414 @@ /* Copyright (c) 2003-2007 Clarence Dang Copyright (c) 2011 Martin Koller All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #define DEBUG_STATUS_BAR (DEBUG_KP_MAIN_WINDOW && 0) #include "mainWindow/kpMainWindow.h" #include "kpMainWindowPrivate.h" #include #include #include #include "kpLogCategories.h" #include "kpDefs.h" #include "document/kpDocument.h" #include "tools/kpTool.h" #include "views/manager/kpViewManager.h" #include "kpViewScrollableContainer.h" #include "views/kpZoomedView.h" #include #include //--------------------------------------------------------------------- // private void kpMainWindow::addPermanentStatusBarItem (int id, int maxTextLen) { QStatusBar *sb = statusBar (); QLabel *label = new QLabel (sb); label->setAlignment (Qt::AlignCenter); label->setFixedHeight (label->fontMetrics ().height () + 2); int maxWidth = label->fontMetrics ().width (QLatin1Char ('8')) * maxTextLen; // add some margins maxWidth += label->fontMetrics ().height (); label->setFixedWidth (maxWidth); // Permanent --> place on the right sb->addPermanentWidget (label); d->statusBarLabels.append (label); Q_ASSERT (d->statusBarLabels.at(id) == label); } //--------------------------------------------------------------------- // private void kpMainWindow::createStatusBar () { QStatusBar *sb = statusBar(); // 9999 pixels "ought to be enough for anybody" const int maxDimenLength = 4; d->statusBarMessageLabel = new KSqueezedTextLabel(sb); // this is done to have the same height as the other labels in status bar; done like in kstatusbar.cpp d->statusBarMessageLabel->setFixedHeight(d->statusBarMessageLabel->fontMetrics().height() + 2); d->statusBarMessageLabel->setTextElideMode(Qt::ElideRight); // this is the reason why we explicitly set a widget sb->addWidget(d->statusBarMessageLabel, 1/*stretch*/); addPermanentStatusBarItem (StatusBarItemShapePoints, (maxDimenLength + 1/*,*/ + maxDimenLength) * 2 + 3/* - */); addPermanentStatusBarItem (StatusBarItemShapeSize, (1/*+/-*/ + maxDimenLength) * 2 + 1/*x*/); QString numSample = i18n("%1 x %2", 5000, 5000); // localized string; can e.g. be "5 000" addPermanentStatusBarItem(StatusBarItemDocSize, numSample.length()); addPermanentStatusBarItem(StatusBarItemDocDepth, 5/*XXbpp*/); addPermanentStatusBarItem (StatusBarItemZoom, 5/*1600%*/); d->statusBarShapeLastPointsInitialised = false; d->statusBarShapeLastSizeInitialised = false; d->statusBarCreated = true; } //--------------------------------------------------------------------- // private slot void kpMainWindow::setStatusBarMessage (const QString &message) { qCDebug(kpLogMainWindow) << "kpMainWindow::setStatusBarMessage(" << message - << ") ok=" << d->statusBarCreated - << endl; + << ") ok=" << d->statusBarCreated; - if (!d->statusBarCreated) + if (!d->statusBarCreated) { return; + } d->statusBarMessageLabel->setText (message); } //--------------------------------------------------------------------- // private slot void kpMainWindow::setStatusBarShapePoints (const QPoint &startPoint, const QPoint &endPoint) { qCDebug(kpLogMainWindow) << "kpMainWindow::setStatusBarShapePoints(" << startPoint << "," << endPoint - << ") ok=" << d->statusBarCreated - << endl; + << ") ok=" << d->statusBarCreated; - if (!d->statusBarCreated) + if (!d->statusBarCreated) { return; + } if (d->statusBarShapeLastPointsInitialised && startPoint == d->statusBarShapeLastStartPoint && endPoint == d->statusBarShapeLastEndPoint) { qCDebug(kpLogMainWindow) << "\tNOP"; return; } QLabel *statusBarLabel = d->statusBarLabels.at (StatusBarItemShapePoints); if (startPoint == KP_INVALID_POINT) { statusBarLabel->setText (QString()); } else if (endPoint == KP_INVALID_POINT) { statusBarLabel->setText (i18n ("%1,%2", startPoint.x (), startPoint.y ())); } else { statusBarLabel->setText (i18n ("%1,%2 - %3,%4", startPoint.x (), startPoint.y (), endPoint.x (), endPoint.y ())); } d->statusBarShapeLastStartPoint = startPoint; d->statusBarShapeLastEndPoint = endPoint; d->statusBarShapeLastPointsInitialised = true; } //--------------------------------------------------------------------- // private slot void kpMainWindow::setStatusBarShapeSize (const QSize &size) { #if DEBUG_STATUS_BAR && 0 qCDebug(kpLogMainWindow) << "kpMainWindow::setStatusBarShapeSize(" << size - << ") ok=" << d->statusBarCreated - << endl; + << ") ok=" << d->statusBarCreated; #endif - if (!d->statusBarCreated) + if (!d->statusBarCreated) { return; + } if (d->statusBarShapeLastSizeInitialised && size == d->statusBarShapeLastSize) { #if DEBUG_STATUS_BAR && 0 qCDebug(kpLogMainWindow) << "\tNOP"; #endif return; } QLabel *statusBarLabel = d->statusBarLabels.at (StatusBarItemShapeSize); if (size == KP_INVALID_SIZE) { statusBarLabel->setText (QString()); } else { statusBarLabel->setText (i18n ("%1x%2", size.width (), size.height ())); } d->statusBarShapeLastSize = size; d->statusBarShapeLastSizeInitialised = true; } //--------------------------------------------------------------------- // private slot void kpMainWindow::setStatusBarDocSize (const QSize &size) { qCDebug(kpLogMainWindow) << "kpMainWindow::setStatusBarDocSize(" << size - << ") ok=" << d->statusBarCreated - << endl; + << ") ok=" << d->statusBarCreated; - if (!d->statusBarCreated) + if (!d->statusBarCreated) { return; + } QLabel *statusBarLabel = d->statusBarLabels.at (StatusBarItemDocSize); if (size == KP_INVALID_SIZE) { statusBarLabel->setText (QString()); } else { statusBarLabel->setText (i18n ("%1 x %2", size.width (), size.height ())); } } //--------------------------------------------------------------------- // private slot void kpMainWindow::setStatusBarDocDepth (int depth) { qCDebug(kpLogMainWindow) << "kpMainWindow::setStatusBarDocDepth(" << depth - << ") ok=" << d->statusBarCreated - << endl; + << ") ok=" << d->statusBarCreated; - if (!d->statusBarCreated) + if (!d->statusBarCreated) { return; + } QLabel *statusBarLabel = d->statusBarLabels.at (StatusBarItemDocDepth); if (depth <= 0) { statusBarLabel->setText (QString()); } else { statusBarLabel->setText (i18n ("%1bpp", depth)); } } //--------------------------------------------------------------------- // private slot void kpMainWindow::setStatusBarZoom (int zoom) { qCDebug(kpLogMainWindow) << "kpMainWindow::setStatusBarZoom(" << zoom - << ") ok=" << d->statusBarCreated - << endl; + << ") ok=" << d->statusBarCreated; - if (!d->statusBarCreated) + if (!d->statusBarCreated) { return; + } QLabel *statusBarLabel = d->statusBarLabels.at (StatusBarItemZoom); if (zoom <= 0) { statusBarLabel->setText (QString()); } else { statusBarLabel->setText (i18n ("%1%", zoom)); } } //--------------------------------------------------------------------- void kpMainWindow::recalculateStatusBarMessage () { qCDebug(kpLogMainWindow) << "kpMainWindow::recalculateStatusBarMessage()"; QString scrollViewMessage = d->scrollView->statusMessage (); qCDebug(kpLogMainWindow) << "\tscrollViewMessage=" << scrollViewMessage; - qCDebug(kpLogMainWindow) << "\tresizing doc? " << !d->scrollView->newDocSize ().isEmpty () - << endl; + qCDebug(kpLogMainWindow) << "\tresizing doc? " << !d->scrollView->newDocSize ().isEmpty (); qCDebug(kpLogMainWindow) << "\tviewUnderCursor? " - << (d->viewManager && d->viewManager->viewUnderCursor ()) - << endl; + << (d->viewManager && d->viewManager->viewUnderCursor ()); // HACK: To work around kpViewScrollableContainer's unreliable // status messages (which in turn is due to Qt not updating // QWidget::underMouse() on drags and we needing to hack around it) if (!scrollViewMessage.isEmpty () && d->scrollView->newDocSize ().isEmpty () && d->viewManager && d->viewManager->viewUnderCursor ()) { #if DEBUG_STATUS_BAR && 1 - qCDebug(kpLogMainWindow) << "\t\tnot resizing & viewUnderCursor - message is wrong - clearing" - << endl; + qCDebug(kpLogMainWindow) << "\t\tnot resizing & viewUnderCursor - message is wrong - clearing"; #endif d->scrollView->blockSignals (true); d->scrollView->clearStatusMessage (); d->scrollView->blockSignals (false); scrollViewMessage.clear (); #if DEBUG_STATUS_BAR && 1 qCDebug(kpLogMainWindow) << "\t\t\tdone"; #endif } if (!scrollViewMessage.isEmpty ()) { setStatusBarMessage (scrollViewMessage); } else { const kpTool *t = tool (); if (t) { setStatusBarMessage (t->userMessage ()); } else { setStatusBarMessage (); } } } //--------------------------------------------------------------------- // private slot void kpMainWindow::recalculateStatusBarShape () { qCDebug(kpLogMainWindow) << "kpMainWindow::recalculateStatusBarShape()"; QSize docResizeTo = d->scrollView->newDocSize (); qCDebug(kpLogMainWindow) << "\tdocResizeTo=" << docResizeTo; if (docResizeTo.isValid ()) { const QPoint startPoint (d->document->width (), d->document->height ()); qCDebug(kpLogMainWindow) << "\thavedMovedFromOrgSize=" - << d->scrollView->haveMovedFromOriginalDocSize () << endl; + << d->scrollView->haveMovedFromOriginalDocSize (); if (!d->scrollView->haveMovedFromOriginalDocSize ()) { setStatusBarShapePoints (startPoint); setStatusBarShapeSize (); } else { const int newWidth = docResizeTo.width (); const int newHeight = docResizeTo.height (); setStatusBarShapePoints (startPoint, QPoint (newWidth, newHeight)); const QPoint sizeAsPoint (QPoint (newWidth, newHeight) - startPoint); setStatusBarShapeSize (QSize (sizeAsPoint.x (), sizeAsPoint.y ())); } } else { const kpTool *t = tool (); qCDebug(kpLogMainWindow) << "\ttool=" << t; if (t) { setStatusBarShapePoints (t->userShapeStartPoint (), t->userShapeEndPoint ()); setStatusBarShapeSize (t->userShapeSize ()); } else { setStatusBarShapePoints (); setStatusBarShapeSize (); } } } //--------------------------------------------------------------------- // private slot void kpMainWindow::recalculateStatusBar () { qCDebug(kpLogMainWindow) << "kpMainWindow::recalculateStatusBar() ok=" - << d->statusBarCreated - << endl; + << d->statusBarCreated; - if (!d->statusBarCreated) + if (!d->statusBarCreated) { return; + } recalculateStatusBarMessage (); recalculateStatusBarShape (); if (d->document) { setStatusBarDocSize (QSize (d->document->width (), d->document->height ())); setStatusBarDocDepth (d->document->image ().depth ()); } else { setStatusBarDocSize (); setStatusBarDocDepth (); } if (d->mainView) { setStatusBarZoom (d->mainView->zoomLevelX ()); } else { setStatusBarZoom (); } } //--------------------------------------------------------------------- diff --git a/mainWindow/kpMainWindow_Text.cpp b/mainWindow/kpMainWindow_Text.cpp index df9a2bf0..6379d263 100644 --- a/mainWindow/kpMainWindow_Text.cpp +++ b/mainWindow/kpMainWindow_Text.cpp @@ -1,417 +1,419 @@ /* Copyright (c) 2003-2007 Clarence Dang All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include "mainWindow/kpMainWindow.h" #include "kpMainWindowPrivate.h" #include #include #include #include "kpLogCategories.h" #include #include #include #include #include #include #include "widgets/toolbars/kpColorToolBar.h" #include "kpDefs.h" #include "layers/selections/text/kpTextStyle.h" #include "tools/selection/text/kpToolText.h" #include "widgets/toolbars/kpToolToolBar.h" #include "widgets/toolbars/options/kpToolWidgetOpaqueOrTransparent.h" #include "views/kpZoomedView.h" // private void kpMainWindow::setupTextToolBarActions () { KActionCollection *ac = actionCollection (); d->actionTextFontFamily = ac->add ("text_font_family"); d->actionTextFontFamily->setText (i18n ("Font Family")); connect (d->actionTextFontFamily, static_cast(&KFontAction::triggered), this, &kpMainWindow::slotTextFontFamilyChanged); d->actionTextFontSize = ac->add ("text_font_size"); d->actionTextFontSize->setText (i18n ("Font Size")); connect (d->actionTextFontSize, static_cast(&KFontSizeAction::triggered), this, &kpMainWindow::slotTextFontSizeChanged); d->actionTextBold = ac->add ("text_bold"); d->actionTextBold->setIcon(KDE::icon("format-text-bold")); d->actionTextBold->setText (i18n ("Bold")); connect (d->actionTextBold, &KToggleAction::triggered, this, &kpMainWindow::slotTextBoldChanged); d->actionTextItalic = ac->add ("text_italic"); d->actionTextItalic->setIcon (KDE::icon("format-text-italic")); d->actionTextItalic->setText (i18n ("Italic")); connect (d->actionTextItalic, &KToggleAction::triggered, this, &kpMainWindow::slotTextItalicChanged); d->actionTextUnderline = ac->add ("text_underline"); d->actionTextUnderline->setIcon (KDE::icon("format-text-underline")); d->actionTextUnderline->setText (i18n ("Underline")); connect (d->actionTextUnderline, &KToggleAction::triggered, this, &kpMainWindow::slotTextUnderlineChanged); d->actionTextStrikeThru = ac->add ("text_strike_thru"); d->actionTextStrikeThru->setIcon(KDE::icon("format-text-strikethrough")); d->actionTextStrikeThru->setText (i18n ("Strike Through")); connect (d->actionTextStrikeThru, &KToggleAction::triggered, this, &kpMainWindow::slotTextStrikeThruChanged); readAndApplyTextSettings (); enableTextToolBarActions (false); } // private void kpMainWindow::readAndApplyTextSettings () { KConfigGroup cfg (KSharedConfig::openConfig (), kpSettingsGroupText); const QString font (cfg.readEntry (kpSettingFontFamily, QString::fromLatin1 ("Times"))); d->actionTextFontFamily->setFont (font); qCDebug(kpLogMainWindow) << "asked setFont to set to=" << font << "- got back=" << d->actionTextFontFamily->font (); d->actionTextFontSize->setFontSize (cfg.readEntry (kpSettingFontSize, 14)); d->actionTextBold->setChecked (cfg.readEntry (kpSettingBold, false)); d->actionTextItalic->setChecked (cfg.readEntry (kpSettingItalic, false)); d->actionTextUnderline->setChecked (cfg.readEntry (kpSettingUnderline, false)); d->actionTextStrikeThru->setChecked (cfg.readEntry (kpSettingStrikeThru, false)); d->textOldFontFamily = d->actionTextFontFamily->font (); d->textOldFontSize = d->actionTextFontSize->fontSize (); } // public void kpMainWindow::enableTextToolBarActions (bool enable) { qCDebug(kpLogMainWindow) << "kpMainWindow::enableTextToolBarActions(" << enable << ")"; d->actionTextFontFamily->setEnabled (enable); d->actionTextFontSize->setEnabled (enable); d->actionTextBold->setEnabled (enable); d->actionTextItalic->setEnabled (enable); d->actionTextUnderline->setEnabled (enable); d->actionTextStrikeThru->setEnabled (enable); if (textToolBar ()) { #if DEBUG_KP_MAIN_WINDOW qCDebug(kpLogMainWindow) << "\thave toolbar - setShown"; #endif // COMPAT: KDE4 does not place the Text Tool Bar in a new row, underneath // the Main Tool Bar, if there isn't enough room. This makes // accessing the Text Tool Bar's buttons difficult. textToolBar ()->setVisible (enable); } } // private slot void kpMainWindow::slotTextFontFamilyChanged () { qCDebug(kpLogMainWindow) << "kpMainWindow::slotTextFontFamilyChanged() alive=" << d->isFullyConstructed << "fontFamily=" << d->actionTextFontFamily->font () << "action.currentItem=" - << d->actionTextFontFamily->currentItem () - << endl; + << d->actionTextFontFamily->currentItem (); - if (!d->isFullyConstructed) + if (!d->isFullyConstructed) { return; + } if (d->toolText && d->toolText->hasBegun ()) { toolEndShape (); d->toolText->slotFontFamilyChanged (d->actionTextFontFamily->font (), d->textOldFontFamily); } // Since editable KSelectAction's steal focus from view, switch back to mainView // TODO: back to the last view - if (d->mainView) + if (d->mainView) { d->mainView->setFocus (); + } KConfigGroup cfg (KSharedConfig::openConfig (), kpSettingsGroupText); cfg.writeEntry (kpSettingFontFamily, d->actionTextFontFamily->font ()); cfg.sync (); d->textOldFontFamily = d->actionTextFontFamily->font (); } // private slot void kpMainWindow::slotTextFontSizeChanged () { qCDebug(kpLogMainWindow) << "kpMainWindow::slotTextFontSizeChanged() alive=" << d->isFullyConstructed << " fontSize=" - << d->actionTextFontSize->fontSize () - << endl; + << d->actionTextFontSize->fontSize (); - if (!d->isFullyConstructed) + if (!d->isFullyConstructed) { return; + } if (d->toolText && d->toolText->hasBegun ()) { toolEndShape (); d->toolText->slotFontSizeChanged (d->actionTextFontSize->fontSize (), d->textOldFontSize); } // Since editable KSelectAction's steal focus from view, switch back to mainView // TODO: back to the last view - if (d->mainView) + if (d->mainView) { d->mainView->setFocus (); + } KConfigGroup cfg (KSharedConfig::openConfig (), kpSettingsGroupText); cfg.writeEntry (kpSettingFontSize, d->actionTextFontSize->fontSize ()); cfg.sync (); d->textOldFontSize = d->actionTextFontSize->fontSize (); } // private slot void kpMainWindow::slotTextBoldChanged () { qCDebug(kpLogMainWindow) << "kpMainWindow::slotTextFontBoldChanged() alive=" << d->isFullyConstructed << " bold=" - << d->actionTextBold->isChecked () - << endl; + << d->actionTextBold->isChecked (); - if (!d->isFullyConstructed) + if (!d->isFullyConstructed) { return; + } if (d->toolText && d->toolText->hasBegun ()) { toolEndShape (); d->toolText->slotBoldChanged (d->actionTextBold->isChecked ()); } KConfigGroup cfg (KSharedConfig::openConfig (), kpSettingsGroupText); cfg.writeEntry (kpSettingBold, d->actionTextBold->isChecked ()); cfg.sync (); } // private slot void kpMainWindow::slotTextItalicChanged () { qCDebug(kpLogMainWindow) << "kpMainWindow::slotTextFontItalicChanged() alive=" << d->isFullyConstructed << " bold=" - << d->actionTextItalic->isChecked () - << endl; + << d->actionTextItalic->isChecked (); - if (!d->isFullyConstructed) + if (!d->isFullyConstructed) { return; + } if (d->toolText && d->toolText->hasBegun ()) { toolEndShape (); d->toolText->slotItalicChanged (d->actionTextItalic->isChecked ()); } KConfigGroup cfg (KSharedConfig::openConfig (), kpSettingsGroupText); cfg.writeEntry (kpSettingItalic, d->actionTextItalic->isChecked ()); cfg.sync (); } // private slot void kpMainWindow::slotTextUnderlineChanged () { qCDebug(kpLogMainWindow) << "kpMainWindow::slotTextFontUnderlineChanged() alive=" << d->isFullyConstructed << " underline=" - << d->actionTextUnderline->isChecked () - << endl; + << d->actionTextUnderline->isChecked (); - if (!d->isFullyConstructed) + if (!d->isFullyConstructed) { return; + } if (d->toolText && d->toolText->hasBegun ()) { toolEndShape (); d->toolText->slotUnderlineChanged (d->actionTextUnderline->isChecked ()); } KConfigGroup cfg (KSharedConfig::openConfig (), kpSettingsGroupText); cfg.writeEntry (kpSettingUnderline, d->actionTextUnderline->isChecked ()); cfg.sync (); } // private slot void kpMainWindow::slotTextStrikeThruChanged () { qCDebug(kpLogMainWindow) << "kpMainWindow::slotTextStrikeThruChanged() alive=" << d->isFullyConstructed << " strikeThru=" - << d->actionTextStrikeThru->isChecked () - << endl; + << d->actionTextStrikeThru->isChecked (); - if (!d->isFullyConstructed) + if (!d->isFullyConstructed) { return; + } if (d->toolText && d->toolText->hasBegun ()) { toolEndShape (); d->toolText->slotStrikeThruChanged (d->actionTextStrikeThru->isChecked ()); } KConfigGroup cfg (KSharedConfig::openConfig (), kpSettingsGroupText); cfg.writeEntry (kpSettingStrikeThru, d->actionTextStrikeThru->isChecked ()); cfg.sync (); } // public KToolBar *kpMainWindow::textToolBar () { return toolBar ("textToolBar"); } bool kpMainWindow::isTextStyleBackgroundOpaque () const { if (d->toolToolBar) { kpToolWidgetOpaqueOrTransparent *oot = d->toolToolBar->toolWidgetOpaqueOrTransparent (); if (oot) { return oot->isOpaque (); } } return true; } // public kpTextStyle kpMainWindow::textStyle () const { return kpTextStyle (d->actionTextFontFamily->font (), d->actionTextFontSize->fontSize (), d->actionTextBold->isChecked (), d->actionTextItalic->isChecked (), d->actionTextUnderline->isChecked (), d->actionTextStrikeThru->isChecked (), d->colorToolBar ? d->colorToolBar->foregroundColor () : kpColor::Invalid, d->colorToolBar ? d->colorToolBar->backgroundColor () : kpColor::Invalid, isTextStyleBackgroundOpaque ()); } // public void kpMainWindow::setTextStyle (const kpTextStyle &textStyle_) { qCDebug(kpLogMainWindow) << "kpMainWindow::setTextStyle()"; d->settingTextStyle++; if (textStyle_.fontFamily () != d->actionTextFontFamily->font ()) { d->actionTextFontFamily->setFont (textStyle_.fontFamily ()); slotTextFontFamilyChanged (); } if (textStyle_.fontSize () != d->actionTextFontSize->fontSize ()) { d->actionTextFontSize->setFontSize (textStyle_.fontSize ()); slotTextFontSizeChanged (); } if (textStyle_.isBold () != d->actionTextBold->isChecked ()) { d->actionTextBold->setChecked (textStyle_.isBold ()); slotTextBoldChanged (); } if (textStyle_.isItalic () != d->actionTextItalic->isChecked ()) { d->actionTextItalic->setChecked (textStyle_.isItalic ()); slotTextItalicChanged (); } if (textStyle_.isUnderline () != d->actionTextUnderline->isChecked ()) { d->actionTextUnderline->setChecked (textStyle_.isUnderline ()); slotTextUnderlineChanged (); } if (textStyle_.isStrikeThru () != d->actionTextStrikeThru->isChecked ()) { d->actionTextStrikeThru->setChecked (textStyle_.isStrikeThru ()); slotTextStrikeThruChanged (); } if (textStyle_.foregroundColor () != d->colorToolBar->foregroundColor ()) { d->colorToolBar->setForegroundColor (textStyle_.foregroundColor ()); } if (textStyle_.backgroundColor () != d->colorToolBar->backgroundColor ()) { d->colorToolBar->setBackgroundColor (textStyle_.backgroundColor ()); } if (textStyle_.isBackgroundOpaque () != isTextStyleBackgroundOpaque ()) { if (d->toolToolBar) { kpToolWidgetOpaqueOrTransparent *oot = d->toolToolBar->toolWidgetOpaqueOrTransparent (); if (oot) { oot->setOpaque (textStyle_.isBackgroundOpaque ()); } } } d->settingTextStyle--; } // public int kpMainWindow::settingTextStyle () const { return d->settingTextStyle; } diff --git a/mainWindow/kpMainWindow_Tools.cpp b/mainWindow/kpMainWindow_Tools.cpp index 30e58033..0647888c 100644 --- a/mainWindow/kpMainWindow_Tools.cpp +++ b/mainWindow/kpMainWindow_Tools.cpp @@ -1,803 +1,812 @@ /* Copyright (c) 2003-2007 Clarence Dang Copyright (c) 2011 Martin Koller All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include "mainWindow/kpMainWindow.h" #include "kpMainWindowPrivate.h" #include #include #include #include #include #include "kpLogCategories.h" #include #include "widgets/toolbars/kpColorToolBar.h" #include "commands/kpCommandHistory.h" #include "document/kpDocument.h" #include "layers/selections/image/kpImageSelectionTransparency.h" #include "tools/kpTool.h" #include "tools/kpToolAction.h" #include "tools/flow/kpToolBrush.h" #include "tools/flow/kpToolColorEraser.h" #include "tools/kpToolColorPicker.h" #include "tools/polygonal/kpToolCurve.h" #include "tools/selection/image/kpToolEllipticalSelection.h" #include "tools/rectangular/kpToolEllipse.h" #include "tools/flow/kpToolEraser.h" #include "tools/kpToolFloodFill.h" #include "tools/selection/image/kpToolFreeFormSelection.h" #include "tools/polygonal/kpToolLine.h" #include "tools/flow/kpToolPen.h" #include "tools/polygonal/kpToolPolygon.h" #include "tools/polygonal/kpToolPolyline.h" #include "tools/rectangular/kpToolRectangle.h" #include "tools/selection/image/kpToolRectSelection.h" #include "tools/rectangular/kpToolRoundedRectangle.h" #include "environments/tools/selection/kpToolSelectionEnvironment.h" #include "tools/flow/kpToolSpraycan.h" #include "tools/selection/text/kpToolText.h" #include "widgets/toolbars/kpToolToolBar.h" #include "widgets/toolbars/options/kpToolWidgetOpaqueOrTransparent.h" #include "tools/kpToolZoom.h" #include "commands/imagelib/transforms/kpTransformResizeScaleCommand.h" #include "kpViewScrollableContainer.h" #include "views/kpZoomedView.h" //--------------------------------------------------------------------- // private kpToolSelectionEnvironment *kpMainWindow::toolSelectionEnvironment () { - if (!d->toolSelectionEnvironment) + if (!d->toolSelectionEnvironment) { d->toolSelectionEnvironment = new kpToolSelectionEnvironment (this); + } return d->toolSelectionEnvironment; } //--------------------------------------------------------------------- // private kpToolEnvironment *kpMainWindow::toolEnvironment () { // It's fine to return a more complex environment than required. return toolSelectionEnvironment (); } //--------------------------------------------------------------------- // private void kpMainWindow::setupToolActions () { kpToolSelectionEnvironment *toolSelEnv = toolSelectionEnvironment (); kpToolEnvironment *toolEnv = toolEnvironment (); d->tools.append (d->toolFreeFormSelection = new kpToolFreeFormSelection (toolSelEnv, this)); d->tools.append (d->toolRectSelection = new kpToolRectSelection (toolSelEnv, this)); d->tools.append (d->toolEllipticalSelection = new kpToolEllipticalSelection (toolSelEnv, this)); d->tools.append (d->toolText = new kpToolText (toolSelEnv, this)); d->tools.append (d->toolLine = new kpToolLine (toolEnv, this)); d->tools.append (d->toolPen = new kpToolPen (toolEnv, this)); d->tools.append (d->toolEraser = new kpToolEraser (toolEnv, this)); d->tools.append (d->toolBrush = new kpToolBrush (toolEnv, this)); d->tools.append (d->toolFloodFill = new kpToolFloodFill (toolEnv, this)); d->tools.append (d->toolColorPicker = new kpToolColorPicker (toolEnv, this)); d->tools.append (d->toolColorEraser = new kpToolColorEraser (toolEnv, this)); d->tools.append (d->toolSpraycan = new kpToolSpraycan (toolEnv, this)); d->tools.append (d->toolRoundedRectangle = new kpToolRoundedRectangle (toolEnv, this)); d->tools.append (d->toolRectangle = new kpToolRectangle (toolEnv, this)); d->tools.append (d->toolPolygon = new kpToolPolygon (toolEnv, this)); d->tools.append (d->toolEllipse = new kpToolEllipse (toolEnv, this)); d->tools.append (d->toolPolyline = new kpToolPolyline (toolEnv, this)); d->tools.append (d->toolCurve = new kpToolCurve (toolEnv, this)); d->tools.append (d->toolZoom = new kpToolZoom (toolEnv, this)); KActionCollection *ac = actionCollection (); d->actionPrevToolOptionGroup1 = ac->addAction ("prev_tool_option_group_1"); d->actionPrevToolOptionGroup1->setText (i18n ("Previous Tool Option (Group #1)")); ac->setDefaultShortcuts (d->actionPrevToolOptionGroup1, kpTool::shortcutForKey (Qt::Key_1)); connect (d->actionPrevToolOptionGroup1, &QAction::triggered, this, &kpMainWindow::slotActionPrevToolOptionGroup1); d->actionNextToolOptionGroup1 = ac->addAction ("next_tool_option_group_1"); d->actionNextToolOptionGroup1->setText (i18n ("Next Tool Option (Group #1)")); ac->setDefaultShortcuts (d->actionNextToolOptionGroup1, kpTool::shortcutForKey (Qt::Key_2)); connect (d->actionNextToolOptionGroup1, &QAction::triggered, this, &kpMainWindow::slotActionNextToolOptionGroup1); d->actionPrevToolOptionGroup2 = ac->addAction ("prev_tool_option_group_2"); d->actionPrevToolOptionGroup2->setText (i18n ("Previous Tool Option (Group #2)")); ac->setDefaultShortcuts (d->actionPrevToolOptionGroup2, kpTool::shortcutForKey (Qt::Key_3)); connect (d->actionPrevToolOptionGroup2, &QAction::triggered, this, &kpMainWindow::slotActionPrevToolOptionGroup2); d->actionNextToolOptionGroup2 = ac->addAction ("next_tool_option_group_2"); d->actionNextToolOptionGroup2->setText (i18n ("Next Tool Option (Group #2)")); ac->setDefaultShortcuts (d->actionNextToolOptionGroup2, kpTool::shortcutForKey (Qt::Key_4)); connect (d->actionNextToolOptionGroup2, &QAction::triggered, this, &kpMainWindow::slotActionNextToolOptionGroup2); // // Implemented in this file (kpMainWindow_Tools.cpp), not // kpImageWindow_Image.cpp since they're really setting tool options. // d->actionDrawOpaque = ac->add ("image_draw_opaque"); d->actionDrawOpaque->setText (i18n ("&Draw Opaque")); connect (d->actionDrawOpaque, &QAction::triggered, this, &kpMainWindow::slotActionDrawOpaqueToggled); d->actionDrawColorSimilarity = ac->addAction ("image_draw_color_similarity"); d->actionDrawColorSimilarity->setText (i18n ("Draw With Color Similarity...")); connect (d->actionDrawColorSimilarity, &QAction::triggered, this, &kpMainWindow::slotActionDrawColorSimilarity); } //--------------------------------------------------------------------- // private void kpMainWindow::createToolBox () { d->toolToolBar = new kpToolToolBar(QLatin1String("Tool Box"), 2/*columns/rows*/, this); d->toolToolBar->setWindowTitle(i18n("Tool Box")); connect (d->toolToolBar, &kpToolToolBar::sigToolSelected, this, &kpMainWindow::slotToolSelected); connect (d->toolToolBar, &kpToolToolBar::toolWidgetOptionSelected, this, &kpMainWindow::updateToolOptionPrevNextActionsEnabled); connect (d->toolToolBar->toolWidgetOpaqueOrTransparent(), &kpToolWidgetOpaqueOrTransparent::isOpaqueChanged, this, &kpMainWindow::updateActionDrawOpaqueChecked); updateActionDrawOpaqueChecked (); - foreach (kpTool *tool, d->tools) + for (auto *tool : d->tools) { d->toolToolBar->registerTool(tool); + } // (from config file) readLastTool (); } //--------------------------------------------------------------------- // private void kpMainWindow::enableToolsDocumentActions (bool enable) { qCDebug(kpLogMainWindow) << "kpMainWindow::enableToolsDocumentsAction(" << enable << ")"; d->toolActionsEnabled = enable; if (enable && !d->toolToolBar->isEnabled ()) { kpTool *previousTool = d->toolToolBar->previousTool (); // select tool for enabled Tool Box - if (previousTool) + if (previousTool) { d->toolToolBar->selectPreviousTool (); + } else { - if (d->lastToolNumber >= 0 && d->lastToolNumber < d->tools.count ()) + if (d->lastToolNumber >= 0 && d->lastToolNumber < d->tools.count ()) { d->toolToolBar->selectTool (d->tools.at (d->lastToolNumber)); - else + } + else { d->toolToolBar->selectTool (d->toolPen); + } } } else if (!enable && d->toolToolBar->isEnabled ()) { // don't have a disabled Tool Box with a checked Tool d->toolToolBar->selectTool (nullptr); } d->toolToolBar->setEnabled (enable); - foreach (kpTool *tool, d->tools) + for (auto *tool : d->tools) { kpToolAction *action = tool->action(); - if (!enable && action->isChecked()) + if (!enable && action->isChecked()) { action->setChecked(false); + } action->setEnabled(enable); } updateToolOptionPrevNextActionsEnabled (); updateActionDrawOpaqueEnabled (); } //--------------------------------------------------------------------- // private slot void kpMainWindow::updateToolOptionPrevNextActionsEnabled () { const bool enable = d->toolActionsEnabled; d->actionPrevToolOptionGroup1->setEnabled (enable && d->toolToolBar->shownToolWidget (0) && d->toolToolBar->shownToolWidget (0)->hasPreviousOption ()); d->actionNextToolOptionGroup1->setEnabled (enable && d->toolToolBar->shownToolWidget (0) && d->toolToolBar->shownToolWidget (0)->hasNextOption ()); d->actionPrevToolOptionGroup2->setEnabled (enable && d->toolToolBar->shownToolWidget (1) && d->toolToolBar->shownToolWidget (1)->hasPreviousOption ()); d->actionNextToolOptionGroup2->setEnabled (enable && d->toolToolBar->shownToolWidget (1) && d->toolToolBar->shownToolWidget (1)->hasNextOption ()); } //--------------------------------------------------------------------- // private slot void kpMainWindow::updateActionDrawOpaqueChecked () { qCDebug(kpLogMainWindow) << "kpMainWindow::updateActionDrawOpaqueChecked()"; const bool drawOpaque = (d->toolToolBar->toolWidgetOpaqueOrTransparent ()->selectedRow () == 0); qCDebug(kpLogMainWindow) << "\tdrawOpaque=" << drawOpaque; d->actionDrawOpaque->setChecked (drawOpaque); } //--------------------------------------------------------------------- // private void kpMainWindow::updateActionDrawOpaqueEnabled () { qCDebug(kpLogMainWindow) << "kpMainWindow::updateActionDrawOpaqueEnabled()"; const bool enable = d->toolActionsEnabled; qCDebug(kpLogMainWindow) << "\tenable=" << enable - << " tool=" << (tool () ? tool ()->objectName () : 0) - << " (is selection=" << toolIsASelectionTool () << ")" - << endl; + << " tool=" << (tool () ? tool ()->objectName () : nullptr) + << " (is selection=" << toolIsASelectionTool () << ")"; d->actionDrawOpaque->setEnabled (enable && toolIsASelectionTool ()); } //--------------------------------------------------------------------- // public QActionGroup *kpMainWindow::toolsActionGroup () { - if (!d->toolsActionGroup) + if (!d->toolsActionGroup) { d->toolsActionGroup = new QActionGroup (this); + } return d->toolsActionGroup; } //--------------------------------------------------------------------- // public kpTool *kpMainWindow::tool () const { return d->toolToolBar ? d->toolToolBar->tool () : nullptr; } //--------------------------------------------------------------------- // public bool kpMainWindow::toolHasBegunShape () const { kpTool *currentTool = tool (); return (currentTool && currentTool->hasBegunShape ()); } //--------------------------------------------------------------------- // public bool kpMainWindow::toolIsASelectionTool (bool includingTextTool) const { kpTool *currentTool = tool (); return ((currentTool == d->toolFreeFormSelection) || (currentTool == d->toolRectSelection) || (currentTool == d->toolEllipticalSelection) || (currentTool == d->toolText && includingTextTool)); } //--------------------------------------------------------------------- // public bool kpMainWindow::toolIsTextTool () const { return (tool () == d->toolText); } //--------------------------------------------------------------------- // private void kpMainWindow::toolEndShape () { - if (toolHasBegunShape ()) + if (toolHasBegunShape ()) { tool ()->endShapeInternal (); + } } //--------------------------------------------------------------------- // public kpImageSelectionTransparency kpMainWindow::imageSelectionTransparency () const { kpToolWidgetOpaqueOrTransparent *oot = d->toolToolBar->toolWidgetOpaqueOrTransparent (); Q_ASSERT (oot); return kpImageSelectionTransparency (oot->isOpaque (), backgroundColor (), d->colorToolBar->colorSimilarity ()); } //--------------------------------------------------------------------- // public void kpMainWindow::setImageSelectionTransparency (const kpImageSelectionTransparency &transparency, bool forceColorChange) { qCDebug(kpLogMainWindow) << "kpMainWindow::setImageSelectionTransparency() isOpaque=" << transparency.isOpaque () - << " color=" << (transparency.transparentColor ().isValid () ? (int *) transparency.transparentColor ().toQRgb () : 0) - << " forceColorChange=" << forceColorChange - << endl; + << " color=" << (transparency.transparentColor ().isValid () ? (int *) transparency.transparentColor ().toQRgb () : nullptr) + << " forceColorChange=" << forceColorChange; kpToolWidgetOpaqueOrTransparent *oot = d->toolToolBar->toolWidgetOpaqueOrTransparent (); Q_ASSERT (oot); d->settingImageSelectionTransparency++; oot->setOpaque (transparency.isOpaque ()); if (transparency.isTransparent () || forceColorChange) { d->colorToolBar->setColor (1, transparency.transparentColor ()); d->colorToolBar->setColorSimilarity (transparency.colorSimilarity ()); } d->settingImageSelectionTransparency--; } //--------------------------------------------------------------------- // public int kpMainWindow::settingImageSelectionTransparency () const { return d->settingImageSelectionTransparency; } //--------------------------------------------------------------------- // private slot void kpMainWindow::slotToolSelected (kpTool *tool) { #if DEBUG_KP_MAIN_WINDOW qCDebug(kpLogMainWindow) << "kpMainWindow::slotToolSelected (" << tool << ")"; #endif kpTool *previousTool = d->toolToolBar ? d->toolToolBar->previousTool () : nullptr; if (previousTool) { disconnect (previousTool, &kpTool::movedAndAboutToDraw, this, &kpMainWindow::slotDragScroll); disconnect (previousTool, &kpTool::endedDraw, this, &kpMainWindow::slotEndDragScroll); disconnect (previousTool, &kpTool::cancelledShape, this, &kpMainWindow::slotEndDragScroll); disconnect (previousTool, &kpTool::userMessageChanged, this, &kpMainWindow::recalculateStatusBarMessage); disconnect (previousTool, &kpTool::userShapePointsChanged, this, &kpMainWindow::recalculateStatusBarShape); disconnect (previousTool, &kpTool::userShapeSizeChanged, this, &kpMainWindow::recalculateStatusBarShape); disconnect (d->colorToolBar, &kpColorToolBar::colorsSwapped, previousTool, &kpTool::slotColorsSwappedInternal); disconnect (d->colorToolBar, &kpColorToolBar::foregroundColorChanged, previousTool, &kpTool::slotForegroundColorChangedInternal); disconnect (d->colorToolBar, &kpColorToolBar::backgroundColorChanged, previousTool, &kpTool::slotBackgroundColorChangedInternal); disconnect (d->colorToolBar, &kpColorToolBar::colorSimilarityChanged, previousTool, &kpTool::slotColorSimilarityChangedInternal); } if (tool) { connect (tool, &kpTool::movedAndAboutToDraw, this, &kpMainWindow::slotDragScroll); connect (tool, &kpTool::endedDraw, this, &kpMainWindow::slotEndDragScroll); connect (tool, &kpTool::cancelledShape, this, &kpMainWindow::slotEndDragScroll); connect (tool, &kpTool::userMessageChanged, this, &kpMainWindow::recalculateStatusBarMessage); connect (tool, &kpTool::userShapePointsChanged, this, &kpMainWindow::recalculateStatusBarShape); connect (tool, &kpTool::userShapeSizeChanged, this, &kpMainWindow::recalculateStatusBarShape); recalculateStatusBar (); connect (d->colorToolBar, &kpColorToolBar::colorsSwapped, tool, &kpTool::slotColorsSwappedInternal); connect (d->colorToolBar, &kpColorToolBar::foregroundColorChanged, tool, &kpTool::slotForegroundColorChangedInternal); connect (d->colorToolBar, &kpColorToolBar::backgroundColorChanged, tool, &kpTool::slotBackgroundColorChangedInternal); connect (d->colorToolBar, &kpColorToolBar::colorSimilarityChanged, tool, &kpTool::slotColorSimilarityChangedInternal); saveLastTool (); } updateToolOptionPrevNextActionsEnabled (); updateActionDrawOpaqueEnabled (); } //--------------------------------------------------------------------- // private void kpMainWindow::readLastTool () { KConfigGroup cfg (KSharedConfig::openConfig (), kpSettingsGroupTools); d->lastToolNumber = cfg.readEntry (kpSettingLastTool, -1); } //--------------------------------------------------------------------- // private int kpMainWindow::toolNumber () const { int number = 0; for (QList ::const_iterator it = d->tools.constBegin (); it != d->tools.constEnd (); ++it) { - if (*it == tool ()) + if (*it == tool ()) { return number; + } number++; } return -1; } //--------------------------------------------------------------------- // private void kpMainWindow::saveLastTool () { int number = toolNumber (); - if (number < 0 || number >= d->tools.count ()) + if (number < 0 || number >= d->tools.count ()) { return; + } KConfigGroup cfg (KSharedConfig::openConfig (), kpSettingsGroupTools); cfg.writeEntry (kpSettingLastTool, number); cfg.sync (); } //--------------------------------------------------------------------- // private bool kpMainWindow::maybeDragScrollingMainView () const { return (tool () && d->mainView && tool ()->viewUnderStartPoint () == d->mainView); } //--------------------------------------------------------------------- // private slot bool kpMainWindow::slotDragScroll (const QPoint &docPoint, const QPoint &docLastPoint, int zoomLevel, bool *scrolled) { Q_UNUSED(docPoint) Q_UNUSED(docLastPoint) qCDebug(kpLogMainWindow) << "kpMainWindow::slotDragScroll() maybeDragScrolling=" - << maybeDragScrollingMainView () - << endl; + << maybeDragScrollingMainView (); if (maybeDragScrollingMainView ()) { return d->scrollView->beginDragScroll(zoomLevel, scrolled); } - else - { - return false; - } + + return false; } //--------------------------------------------------------------------- // private slot bool kpMainWindow::slotEndDragScroll () { // (harmless if haven't started drag scroll) return d->scrollView->endDragScroll (); } //--------------------------------------------------------------------- // private slot void kpMainWindow::slotBeganDocResize () { toolEndShape (); recalculateStatusBarShape (); } //--------------------------------------------------------------------- // private slot void kpMainWindow::slotContinuedDocResize (const QSize &) { recalculateStatusBarShape (); } //--------------------------------------------------------------------- // private slot void kpMainWindow::slotCancelledDocResize () { recalculateStatusBar (); } //--------------------------------------------------------------------- // private slot void kpMainWindow::slotEndedDocResize (const QSize &size) { #define DOC_RESIZE_COMPLETED() \ { \ d->docResizeToBeCompleted = false; \ recalculateStatusBar (); \ } // Prevent statusbar updates d->docResizeToBeCompleted = true; d->docResizeWidth = (size.width () > 0 ? size.width () : 1); d->docResizeHeight = (size.height () > 0 ? size.height () : 1); if (d->docResizeWidth == d->document->width () && d->docResizeHeight == d->document->height ()) { DOC_RESIZE_COMPLETED (); return; } // Blank status to avoid confusion if dialog comes up setStatusBarMessage (); setStatusBarShapePoints (); setStatusBarShapeSize (); if (kpTool::warnIfBigImageSize (d->document->width (), d->document->height (), d->docResizeWidth, d->docResizeHeight, i18n ("

Resizing the image to" " %1x%2 may take a substantial amount of memory." " This can reduce system" " responsiveness and cause other application resource" " problems.

" "

Are you sure you want to resize the" " image?

", d->docResizeWidth, d->docResizeHeight), i18nc ("@title:window", "Resize Image?"), i18n ("R&esize Image"), this)) { d->commandHistory->addCommand ( new kpTransformResizeScaleCommand ( false/*doc, not sel*/, d->docResizeWidth, d->docResizeHeight, kpTransformResizeScaleCommand::Resize, commandEnvironment ())); saveDefaultDocSize (QSize (d->docResizeWidth, d->docResizeHeight)); } DOC_RESIZE_COMPLETED (); #undef DOC_RESIZE_COMPLETED } //--------------------------------------------------------------------- // private slot void kpMainWindow::slotDocResizeMessageChanged (const QString &string) { qCDebug(kpLogMainWindow) << "kpMainWindow::slotDocResizeMessageChanged(" << string - << ") docResizeToBeCompleted=" << d->docResizeToBeCompleted - << endl; + << ") docResizeToBeCompleted=" << d->docResizeToBeCompleted; - if (d->docResizeToBeCompleted) + if (d->docResizeToBeCompleted) { return; + } recalculateStatusBarMessage (); } //--------------------------------------------------------------------- // private slot void kpMainWindow::slotActionPrevToolOptionGroup1 () { - if (!d->toolToolBar->shownToolWidget (0)) + if (!d->toolToolBar->shownToolWidget (0)) { return; + } // We don't call toolEndShape() here because we want #23 in the file BUGS // to later work. d->toolToolBar->shownToolWidget (0)->selectPreviousOption (); updateToolOptionPrevNextActionsEnabled (); } //--------------------------------------------------------------------- // private slot void kpMainWindow::slotActionNextToolOptionGroup1 () { - if (!d->toolToolBar->shownToolWidget (0)) + if (!d->toolToolBar->shownToolWidget (0)) { return; + } // We don't call toolEndShape() here because we want #23 in the file BUGS // to later work. d->toolToolBar->shownToolWidget (0)->selectNextOption (); updateToolOptionPrevNextActionsEnabled (); } //--------------------------------------------------------------------- // private slot void kpMainWindow::slotActionPrevToolOptionGroup2 () { - if (!d->toolToolBar->shownToolWidget (1)) + if (!d->toolToolBar->shownToolWidget (1)) { return; + } // We don't call toolEndShape() here because we want #23 in the file BUGS // to later work. d->toolToolBar->shownToolWidget (1)->selectPreviousOption (); updateToolOptionPrevNextActionsEnabled (); } //--------------------------------------------------------------------- // private slot void kpMainWindow::slotActionNextToolOptionGroup2 () { - if (!d->toolToolBar->shownToolWidget (1)) + if (!d->toolToolBar->shownToolWidget (1)) { return; + } // We don't call toolEndShape() here because we want #23 in the file BUGS // to later work. d->toolToolBar->shownToolWidget (1)->selectNextOption (); updateToolOptionPrevNextActionsEnabled (); } //--------------------------------------------------------------------- // private slot void kpMainWindow::slotActionDrawOpaqueToggled () { qCDebug(kpLogMainWindow) << "kpMainWindow::slotActionDrawOpaqueToggled()"; toolEndShape (); // TODO: How does this differ to setImageSelectionTransparency()? // ("kpToolWidgetBase::" is to access one overload shadowed by the override // of the other overload) d->toolToolBar->toolWidgetOpaqueOrTransparent ()->kpToolWidgetBase::setSelected ( (d->actionDrawOpaque->isChecked () ? 0/*row 0 = opaque*/ : 1/*row 1 = transparent*/), 0/*column*/); } //--------------------------------------------------------------------- // private slot void kpMainWindow::slotActionDrawColorSimilarity () { qCDebug(kpLogMainWindow) << "kpMainWindow::slotActionDrawColorSimilarity()"; toolEndShape (); d->colorToolBar->openColorSimilarityDialog (); } //--------------------------------------------------------------------- // public slots #define SLOT_TOOL(toolName) \ void kpMainWindow::slotTool##toolName () \ { \ if (!d->toolToolBar) \ return; \ \ if (tool () == d->tool##toolName) \ return; \ \ d->toolToolBar->selectTool (d->tool##toolName); \ } SLOT_TOOL (RectSelection) SLOT_TOOL (EllipticalSelection) SLOT_TOOL (FreeFormSelection) SLOT_TOOL (Text) diff --git a/mainWindow/kpMainWindow_View.cpp b/mainWindow/kpMainWindow_View.cpp index 9c7b59cf..d58611a6 100644 --- a/mainWindow/kpMainWindow_View.cpp +++ b/mainWindow/kpMainWindow_View.cpp @@ -1,156 +1,157 @@ /* Copyright (c) 2003-2007 Clarence Dang All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include "mainWindow/kpMainWindow.h" #include "kpMainWindowPrivate.h" #include "kpLogCategories.h" #include #include #include #include #include #include "kpDefs.h" #include "document/kpDocument.h" #include "kpThumbnail.h" #include "tools/kpTool.h" #include "widgets/toolbars/kpToolToolBar.h" #include "views/kpUnzoomedThumbnailView.h" #include "views/manager/kpViewManager.h" #include "kpViewScrollableContainer.h" #include "generic/kpWidgetMapper.h" #include "views/kpZoomedView.h" #include "views/kpZoomedThumbnailView.h" // private void kpMainWindow::setupViewMenuActions () { KActionCollection *ac = actionCollection (); /*d->actionFullScreen = KStandardAction::fullScreen (0, 0, ac); d->actionFullScreen->setEnabled (false);*/ setupViewMenuZoomActions (); d->actionShowGrid = ac->add ("view_show_grid"); d->actionShowGrid->setText (i18n ("Show &Grid")); ac->setDefaultShortcut (d->actionShowGrid, Qt::CTRL + Qt::Key_G); //d->actionShowGrid->setCheckedState (KGuiItem(i18n ("Hide &Grid"))); connect (d->actionShowGrid, &KToggleAction::triggered, this, &kpMainWindow::slotShowGridToggled); setupViewMenuThumbnailActions (); enableViewMenuDocumentActions (false); } //--------------------------------------------------------------------- // private bool kpMainWindow::viewMenuDocumentActionsEnabled () const { return d->viewMenuDocumentActionsEnabled; } //--------------------------------------------------------------------- // private void kpMainWindow::enableViewMenuDocumentActions (bool enable) { d->viewMenuDocumentActionsEnabled = enable; enableViewMenuZoomDocumentActions (enable); actionShowGridUpdate (); enableViewMenuThumbnailDocumentActions (enable); } //--------------------------------------------------------------------- // private void kpMainWindow::actionShowGridUpdate () { qCDebug(kpLogMainWindow) << "kpMainWindow::actionShowGridUpdate()"; const bool enable = (viewMenuDocumentActionsEnabled () && d->mainView && d->mainView->canShowGrid ()); d->actionShowGrid->setEnabled (enable); d->actionShowGrid->setChecked (enable && d->configShowGrid); } //--------------------------------------------------------------------- // private slot void kpMainWindow::slotShowGridToggled () { qCDebug(kpLogMainWindow) << "kpMainWindow::slotActionShowGridToggled()"; updateMainViewGrid (); KConfigGroup cfg (KSharedConfig::openConfig (), kpSettingsGroupGeneral); cfg.writeEntry (kpSettingShowGrid, d->configShowGrid = d->actionShowGrid->isChecked ()); cfg.sync (); } //--------------------------------------------------------------------- // private void kpMainWindow::updateMainViewGrid () { qCDebug(kpLogMainWindow) << "kpMainWindow::updateMainViewGrid ()"; - if (d->mainView) + if (d->mainView) { d->mainView->showGrid (d->actionShowGrid->isChecked ()); + } } //--------------------------------------------------------------------- // private QRect kpMainWindow::mapToGlobal (const QRect &rect) const { return kpWidgetMapper::toGlobal (this, rect); } //--------------------------------------------------------------------- // private QRect kpMainWindow::mapFromGlobal (const QRect &rect) const { return kpWidgetMapper::fromGlobal (this, rect); } //--------------------------------------------------------------------- diff --git a/mainWindow/kpMainWindow_View_Thumbnail.cpp b/mainWindow/kpMainWindow_View_Thumbnail.cpp index 5d85ebbc..535d13f4 100644 --- a/mainWindow/kpMainWindow_View_Thumbnail.cpp +++ b/mainWindow/kpMainWindow_View_Thumbnail.cpp @@ -1,417 +1,423 @@ /* Copyright (c) 2003-2007 Clarence Dang All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include "mainWindow/kpMainWindow.h" #include "kpMainWindowPrivate.h" #include "kpLogCategories.h" #include #include #include #include #include #include #include "kpDefs.h" #include "document/kpDocument.h" #include "kpThumbnail.h" #include "tools/kpTool.h" #include "widgets/toolbars/kpToolToolBar.h" #include "views/kpUnzoomedThumbnailView.h" #include "views/manager/kpViewManager.h" #include "kpViewScrollableContainer.h" #include "generic/kpWidgetMapper.h" #include "views/kpZoomedView.h" #include "views/kpZoomedThumbnailView.h" // private void kpMainWindow::setupViewMenuThumbnailActions () { d->thumbnailSaveConfigTimer = nullptr; KActionCollection *ac = actionCollection (); d->actionShowThumbnail = ac->add ("view_show_thumbnail"); d->actionShowThumbnail->setText (i18n ("Show T&humbnail")); // TODO: This doesn't work when the thumbnail has focus. // Testcase: Press CTRL+H twice on a fresh KolourPaint. // The second CTRL+H doesn't close the thumbnail. ac->setDefaultShortcut (d->actionShowThumbnail, Qt::CTRL + Qt::Key_H); //d->actionShowThumbnail->setCheckedState (KGuiItem(i18n ("Hide T&humbnail"))); connect (d->actionShowThumbnail, &KToggleAction::triggered, this, &kpMainWindow::slotShowThumbnailToggled); // Please do not use setCheckedState() here - it wouldn't make sense d->actionZoomedThumbnail = ac->add ("view_zoomed_thumbnail"); d->actionZoomedThumbnail->setText (i18n ("Zoo&med Thumbnail Mode")); connect (d->actionZoomedThumbnail, &KToggleAction::triggered, this, &kpMainWindow::slotZoomedThumbnailToggled); // For consistency with the above action, don't use setCheckedState() // // Also, don't use "Show Thumbnail Rectangle" because if entire doc // can be seen in scrollView, checking option won't "Show" anything // since rect _surrounds_ entire doc (hence, won't be rendered). d->actionShowThumbnailRectangle = ac->add ("view_show_thumbnail_rectangle"); d->actionShowThumbnailRectangle->setText (i18n ("Enable Thumbnail &Rectangle")); connect (d->actionShowThumbnailRectangle, &KToggleAction::triggered, this, &kpMainWindow::slotThumbnailShowRectangleToggled); } // private void kpMainWindow::enableViewMenuThumbnailDocumentActions (bool enable) { d->actionShowThumbnail->setEnabled (enable); enableThumbnailOptionActions (enable); } // private slot void kpMainWindow::slotDestroyThumbnail () { qCDebug(kpLogMainWindow) << "kpMainWindow::slotDestroyThumbnail()"; d->actionShowThumbnail->setChecked (false); enableThumbnailOptionActions (false); updateThumbnail (); } // private slot void kpMainWindow::slotDestroyThumbnailInitatedByUser () { qCDebug(kpLogMainWindow) << "kpMainWindow::slotDestroyThumbnailInitiatedByUser()"; d->actionShowThumbnail->setChecked (false); slotShowThumbnailToggled (); } // private slot void kpMainWindow::slotCreateThumbnail () { qCDebug(kpLogMainWindow) << "kpMainWindow::slotCreateThumbnail()"; d->actionShowThumbnail->setChecked (true); enableThumbnailOptionActions (true); updateThumbnail (); } // public void kpMainWindow::notifyThumbnailGeometryChanged () { qCDebug(kpLogMainWindow) << "kpMainWindow::notifyThumbnailGeometryChanged()"; if (!d->thumbnailSaveConfigTimer) { d->thumbnailSaveConfigTimer = new QTimer (this); d->thumbnailSaveConfigTimer->setSingleShot (true); connect (d->thumbnailSaveConfigTimer, &QTimer::timeout, this, &kpMainWindow::slotSaveThumbnailGeometry); } // (single shot) d->thumbnailSaveConfigTimer->start (500/*msec*/); } // private slot void kpMainWindow::slotSaveThumbnailGeometry () { qCDebug(kpLogMainWindow) << "kpMainWindow::saveThumbnailGeometry()"; - if (!d->thumbnail) + if (!d->thumbnail) { return; + } QRect rect (d->thumbnail->x (), d->thumbnail->y (), d->thumbnail->width (), d->thumbnail->height ()); qCDebug(kpLogMainWindow) << "\tthumbnail relative geometry=" << rect; d->configThumbnailGeometry = mapFromGlobal (rect); - qCDebug(kpLogMainWindow) << "\tCONFIG: saving thumbnail geometry " - << d->configThumbnailGeometry - << endl; + qCDebug(kpLogMainWindow) << "\tCONFIG: saving thumbnail geometry "; KConfigGroup cfg (KSharedConfig::openConfig (), kpSettingsGroupThumbnail); cfg.writeEntry (kpSettingThumbnailGeometry, d->configThumbnailGeometry); cfg.sync (); } // private slot void kpMainWindow::slotShowThumbnailToggled () { qCDebug(kpLogMainWindow) << "kpMainWindow::slotShowThumbnailToggled()"; d->configThumbnailShown = d->actionShowThumbnail->isChecked (); KConfigGroup cfg (KSharedConfig::openConfig (), kpSettingsGroupThumbnail); cfg.writeEntry (kpSettingThumbnailShown, d->configThumbnailShown); cfg.sync (); enableThumbnailOptionActions (d->actionShowThumbnail->isChecked ()); updateThumbnail (); } // private slot void kpMainWindow::updateThumbnailZoomed () { qCDebug(kpLogMainWindow) << "kpMainWindow::updateThumbnailZoomed() zoomed=" - << d->actionZoomedThumbnail->isChecked () << endl; + << d->actionZoomedThumbnail->isChecked (); - if (!d->thumbnailView) + if (!d->thumbnailView) { return; + } destroyThumbnailView (); createThumbnailView (); } // private slot void kpMainWindow::slotZoomedThumbnailToggled () { qCDebug(kpLogMainWindow) << "kpMainWindow::slotZoomedThumbnailToggled()"; d->configZoomedThumbnail = d->actionZoomedThumbnail->isChecked (); KConfigGroup cfg (KSharedConfig::openConfig (), kpSettingsGroupThumbnail); cfg.writeEntry (kpSettingThumbnailZoomed, d->configZoomedThumbnail); cfg.sync (); updateThumbnailZoomed (); } // private slot void kpMainWindow::slotThumbnailShowRectangleToggled () { qCDebug(kpLogMainWindow) << "kpMainWindow::slotThumbnailShowRectangleToggled()"; d->configThumbnailShowRectangle = d->actionShowThumbnailRectangle->isChecked (); KConfigGroup cfg (KSharedConfig::openConfig (), kpSettingsGroupThumbnail); cfg.writeEntry (kpSettingThumbnailShowRectangle, d->configThumbnailShowRectangle); cfg.sync (); if (d->thumbnailView) { d->thumbnailView->showBuddyViewScrollableContainerRectangle ( d->actionShowThumbnailRectangle->isChecked ()); } } // private void kpMainWindow::enableViewZoomedThumbnail (bool enable) { qCDebug(kpLogMainWindow) << "kpMainWindow::enableSettingsViewZoomedThumbnail()"; d->actionZoomedThumbnail->setEnabled (enable && d->actionShowThumbnail->isChecked ()); // Note: Don't uncheck if disabled - being able to see the zoomed state // before turning on the thumbnail can be useful. d->actionZoomedThumbnail->setChecked (d->configZoomedThumbnail); } // private void kpMainWindow::enableViewShowThumbnailRectangle (bool enable) { qCDebug(kpLogMainWindow) << "kpMainWindow::enableViewShowThumbnailRectangle()"; d->actionShowThumbnailRectangle->setEnabled (enable && d->actionShowThumbnail->isChecked ()); // Note: Don't uncheck if disabled for consistency with // enableViewZoomedThumbnail() d->actionShowThumbnailRectangle->setChecked ( d->configThumbnailShowRectangle); } // private void kpMainWindow::enableThumbnailOptionActions (bool enable) { enableViewZoomedThumbnail (enable); enableViewShowThumbnailRectangle (enable); } // private void kpMainWindow::createThumbnailView () { qCDebug(kpLogMainWindow) << "\t\tcreating new kpView:"; if (d->thumbnailView) { qCDebug(kpLogMainWindow) << "kpMainWindow::createThumbnailView() had to destroy view"; destroyThumbnailView (); } if (d->actionZoomedThumbnail->isChecked ()) { d->thumbnailView = new kpZoomedThumbnailView ( d->document, d->toolToolBar, d->viewManager, d->mainView, nullptr/*scrollableContainer*/, d->thumbnail); d->thumbnailView->setObjectName ( QLatin1String("thumbnailView" )); } else { d->thumbnailView = new kpUnzoomedThumbnailView ( d->document, d->toolToolBar, d->viewManager, d->mainView, nullptr/*scrollableContainer*/, d->thumbnail); d->thumbnailView->setObjectName ( QLatin1String("thumbnailView" )); } d->thumbnailView->showBuddyViewScrollableContainerRectangle ( d->actionShowThumbnailRectangle->isChecked ()); qCDebug(kpLogMainWindow) << "\t\tgive kpThumbnail the kpView:"; - if (d->thumbnail) + if (d->thumbnail) { d->thumbnail->setView (d->thumbnailView); - else - qCCritical(kpLogMainWindow) << "kpMainWindow::createThumbnailView() no thumbnail" << endl; + } + else { + qCCritical(kpLogMainWindow) << "kpMainWindow::createThumbnailView() no thumbnail"; + } qCDebug(kpLogMainWindow) << "\t\tregistering the kpView:"; - if (d->viewManager) + if (d->viewManager) { d->viewManager->registerView (d->thumbnailView); + } } // private void kpMainWindow::destroyThumbnailView () { - if (!d->thumbnailView) + if (!d->thumbnailView) { return; + } - if (d->viewManager) + if (d->viewManager) { d->viewManager->unregisterView (d->thumbnailView); + } - if (d->thumbnail) + if (d->thumbnail) { d->thumbnail->setView (nullptr); + } d->thumbnailView->deleteLater (); d->thumbnailView = nullptr; } // private void kpMainWindow::updateThumbnail () { qCDebug(kpLogMainWindow) << "kpMainWindow::updateThumbnail()"; bool enable = d->actionShowThumbnail->isChecked (); qCDebug(kpLogMainWindow) << "\tthumbnail=" << bool (d->thumbnail) << " action_isChecked=" - << enable - << endl; + << enable; - if (bool (d->thumbnail) == enable) + if (bool (d->thumbnail) == enable) { return; + } if (!d->thumbnail) { qCDebug(kpLogMainWindow) << "\tcreating thumbnail"; // Read last saved geometry before creating thumbnail & friends // in case they call notifyThumbnailGeometryChanged() QRect thumbnailGeometry = d->configThumbnailGeometry; qCDebug(kpLogMainWindow) << "\t\tlast used geometry=" << thumbnailGeometry; d->thumbnail = new kpThumbnail (this); createThumbnailView (); qCDebug(kpLogMainWindow) << "\t\tmoving thumbnail to right place"; if (!thumbnailGeometry.isEmpty () && QRect (0, 0, width (), height ()).intersects (thumbnailGeometry)) { const QRect geometry = mapToGlobal (thumbnailGeometry); d->thumbnail->resize (geometry.size ()); d->thumbnail->move (geometry.topLeft ()); } else { if (d->scrollView) { const int margin = 20; const int initialWidth = 160, initialHeight = 120; QRect geometryRect (width () - initialWidth - margin * 2, d->scrollView->y () + margin, initialWidth, initialHeight); qCDebug(kpLogMainWindow) << "\t\tcreating geometry=" << geometryRect; geometryRect = mapToGlobal (geometryRect); qCDebug(kpLogMainWindow) << "\t\tmap to global=" << geometryRect; d->thumbnail->resize (geometryRect.size ()); d->thumbnail->move (geometryRect.topLeft ()); } } qCDebug(kpLogMainWindow) << "\t\tshowing thumbnail"; d->thumbnail->show (); qCDebug(kpLogMainWindow) << "\t\tconnecting signal thumbnail::windowClosed to destroy slot"; connect (d->thumbnail, &kpThumbnail::windowClosed, this, &kpMainWindow::slotDestroyThumbnailInitatedByUser); qCDebug(kpLogMainWindow) << "\t\tDONE"; } else { qCDebug(kpLogMainWindow) << "\tdestroying thumbnail d->thumbnail=" - << d->thumbnail << endl; + << d->thumbnail; if (d->thumbnailSaveConfigTimer && d->thumbnailSaveConfigTimer->isActive ()) { d->thumbnailSaveConfigTimer->stop (); slotSaveThumbnailGeometry (); } // Must be done before hiding the thumbnail to avoid triggering // this signal - re-entering this code. disconnect (d->thumbnail, &kpThumbnail::windowClosed, this, &kpMainWindow::slotDestroyThumbnailInitatedByUser); // Avoid change/flicker of caption due to view delete // (destroyThumbnailView()) d->thumbnail->hide (); destroyThumbnailView (); d->thumbnail->deleteLater (); d->thumbnail = nullptr; } } diff --git a/mainWindow/kpMainWindow_View_Zoom.cpp b/mainWindow/kpMainWindow_View_Zoom.cpp index 5eb2b87b..bd86b3fc 100644 --- a/mainWindow/kpMainWindow_View_Zoom.cpp +++ b/mainWindow/kpMainWindow_View_Zoom.cpp @@ -1,639 +1,640 @@ // REFACTOR: Clean up bits of this file /* Copyright (c) 2003-2007 Clarence Dang All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include "mainWindow/kpMainWindow.h" #include "kpMainWindowPrivate.h" #include "kpLogCategories.h" #include #include #include #include #include #include #include "kpDefs.h" #include "document/kpDocument.h" #include "kpThumbnail.h" #include "tools/kpTool.h" #include "widgets/toolbars/kpToolToolBar.h" #include "views/kpUnzoomedThumbnailView.h" #include "views/manager/kpViewManager.h" #include "kpViewScrollableContainer.h" #include "generic/kpWidgetMapper.h" #include "views/kpZoomedView.h" #include "views/kpZoomedThumbnailView.h" static int ZoomLevelFromString (const QString &stringIn) { qCDebug(kpLogMainWindow) << "kpMainWindow_View.cpp:ZoomLevelFromString(" << stringIn << ")"; // Remove any non-digits kdelibs sometimes adds behind our back :( e.g.: // // 1. kdelibs adds accelerators to actions' text directly // 2. ',' is automatically added to change "1000%" to "1,000%" QString string = stringIn; string.remove (QRegExp ("[^0-9]")); qCDebug(kpLogMainWindow) << "\twithout non-digits='" << string << "'"; // Convert zoom level to number. bool ok = false; int zoomLevel = string.toInt (&ok); qCDebug(kpLogMainWindow) << "\tzoomLevel=" << zoomLevel; - if (!ok || zoomLevel < kpView::MinZoomLevel || zoomLevel > kpView::MaxZoomLevel) + if (!ok || zoomLevel < kpView::MinZoomLevel || zoomLevel > kpView::MaxZoomLevel) { return 0; // error - else - return zoomLevel; + } + + return zoomLevel; } //--------------------------------------------------------------------- static QString ZoomLevelToString (int zoomLevel) { return i18n ("%1%", zoomLevel); } //--------------------------------------------------------------------- // private void kpMainWindow::setupViewMenuZoomActions () { KActionCollection *ac = actionCollection (); d->actionActualSize = KStandardAction::actualSize (this, SLOT (slotActualSize()), ac); d->actionFitToPage = KStandardAction::fitToPage (this, SLOT (slotFitToPage()), ac); d->actionFitToWidth = KStandardAction::fitToWidth (this, SLOT (slotFitToWidth()), ac); d->actionFitToHeight = KStandardAction::fitToHeight (this, SLOT (slotFitToHeight()), ac); d->actionZoomIn = KStandardAction::zoomIn (this, SLOT (slotZoomIn()), ac); d->actionZoomOut = KStandardAction::zoomOut (this, SLOT (slotZoomOut()), ac); d->actionZoom = ac->add ("view_zoom_to"); d->actionZoom->setText (i18n ("&Zoom")); connect (d->actionZoom, static_cast(&KSelectAction::triggered), this, &kpMainWindow::slotZoom); d->actionZoom->setEditable (true); // create the zoom list for the 1st call to zoomTo() below d->zoomList.append (10); d->zoomList.append (25); d->zoomList.append (33); d->zoomList.append (50); d->zoomList.append (67); d->zoomList.append (75); d->zoomList.append (100); d->zoomList.append (200); d->zoomList.append (300); d->zoomList.append (400); d->zoomList.append (600); d->zoomList.append (800); d->zoomList.append (1000); d->zoomList.append (1200); d->zoomList.append (1600); } //--------------------------------------------------------------------- // private void kpMainWindow::enableViewMenuZoomDocumentActions (bool enable) { d->actionActualSize->setEnabled (enable); d->actionFitToPage->setEnabled (enable); d->actionFitToWidth->setEnabled (enable); d->actionFitToHeight->setEnabled (enable); d->actionZoomIn->setEnabled (enable); d->actionZoomOut->setEnabled (enable); d->actionZoom->setEnabled (enable); // TODO: for the time being, assume that we start at zoom 100% // with no grid // This function is only called when a new document is created // or an existing document is closed. So the following will // always be correct: zoomTo (100); } //--------------------------------------------------------------------- // private void kpMainWindow::sendZoomListToActionZoom () { QStringList items; const QList ::ConstIterator zoomListEnd (d->zoomList.end ()); for (QList ::ConstIterator it = d->zoomList.constBegin (); it != zoomListEnd; ++it) { items << ::ZoomLevelToString (*it); } // Work around a KDE bug - KSelectAction::setItems() enables the action. // David Faure said it won't be fixed because it's a feature used by // KRecentFilesAction. bool e = d->actionZoom->isEnabled (); d->actionZoom->setItems (items); - if (e != d->actionZoom->isEnabled ()) + if (e != d->actionZoom->isEnabled ()) { d->actionZoom->setEnabled (e); + } } //--------------------------------------------------------------------- // private void kpMainWindow::zoomToPre (int zoomLevel) { // We're called quite early in the init process and/or when there might // not be a document or a view so we have a lot of "if (ptr)" guards. qCDebug(kpLogMainWindow) << "kpMainWindow::zoomToPre(" << zoomLevel << ")"; zoomLevel = qBound (kpView::MinZoomLevel, zoomLevel, kpView::MaxZoomLevel); int index = 0; QList ::Iterator it = d->zoomList.begin (); while (index < d->zoomList.count () && zoomLevel > *it) { it++; index++; } - if (zoomLevel != *it) + if (zoomLevel != *it) { d->zoomList.insert (it, zoomLevel); + } // OPT: We get called twice on startup. sendZoomListToActionZoom() is very slow. sendZoomListToActionZoom (); qCDebug(kpLogMainWindow) << "\tsetCurrentItem(" << index << ")"; d->actionZoom->setCurrentItem (index); qCDebug(kpLogMainWindow) << "\tcurrentItem=" << d->actionZoom->currentItem () << " action=" << d->actionZoom->action (d->actionZoom->currentItem ()) << " checkedAction" - << d->actionZoom->selectableActionGroup ()->checkedAction () - << endl;; + << d->actionZoom->selectableActionGroup ()->checkedAction (); if (viewMenuDocumentActionsEnabled ()) { d->actionActualSize->setEnabled (zoomLevel != 100); d->actionZoomIn->setEnabled (d->actionZoom->currentItem () < d->zoomList.count () - 1); d->actionZoomOut->setEnabled (d->actionZoom->currentItem () > 0); } // TODO: Is this actually needed? - if (d->viewManager) + if (d->viewManager) { d->viewManager->setQueueUpdates (); + } if (d->scrollView) { d->scrollView->setUpdatesEnabled (false); } } //--------------------------------------------------------------------- // private void kpMainWindow::zoomToPost () { qCDebug(kpLogMainWindow) << "kpMainWindow::zoomToPost()"; if (d->mainView) { actionShowGridUpdate (); updateMainViewGrid (); // Since Zoom Level KSelectAction on ToolBar grabs focus after changing // Zoom, switch back to the Main View. // TODO: back to the last view d->mainView->setFocus (); } // The view magnified and moved beneath the cursor - if (tool ()) + if (tool ()) { tool ()->somethingBelowTheCursorChanged (); + } if (d->scrollView) { // TODO: setUpdatesEnabled() should really return to old value // - not necessarily "true" d->scrollView->setUpdatesEnabled (true); } - if (d->viewManager && d->viewManager->queueUpdates ()/*just in case*/) + if (d->viewManager && d->viewManager->queueUpdates ()/*just in case*/) { d->viewManager->restoreQueueUpdates (); + } setStatusBarZoom (d->mainView ? d->mainView->zoomLevelX () : 0); qCDebug(kpLogMainWindow) << "kpMainWindow::zoomToPost() done"; } //--------------------------------------------------------------------- // private void kpMainWindow::zoomTo (int zoomLevel, bool centerUnderCursor) { zoomToPre (zoomLevel); if (d->scrollView && d->mainView) { qCDebug(kpLogMainWindow) << "\tscrollView contentsX=" << d->scrollView->horizontalScrollBar()->value () << " contentsY=" << d->scrollView->verticalScrollBar()->value () << " contentsWidth=" << d->scrollView->widget()->width () << " contentsHeight=" << d->scrollView->widget()->height () << " visibleWidth=" << d->scrollView->viewport()->width () << " visibleHeight=" << d->scrollView->viewport()->height () << " oldZoomX=" << d->mainView->zoomLevelX () << " oldZoomY=" << d->mainView->zoomLevelY () - << " newZoom=" << zoomLevel - << endl; + << " newZoom=" << zoomLevel; // TODO: when changing from no scrollbars to scrollbars, Qt lies about // visibleWidth() & visibleHeight() (doesn't take into account the // space taken by the would-be scrollbars) until it updates the // scrollview; hence the centering is off by about 5-10 pixels. // TODO: Use visibleRect() for greater accuracy? // Or use kpAbstractScrollAreaUtils::EstimateUsableArea() // instead of ScrollView::visible{Width,Height}(), as // per zoomToRect()? int viewX, viewY; bool targetDocAvail = false; double targetDocX = -1, targetDocY = -1; if (centerUnderCursor && d->viewManager && d->viewManager->viewUnderCursor ()) { kpView *const vuc = d->viewManager->viewUnderCursor (); QPoint viewPoint = vuc->mouseViewPoint (); // vuc->transformViewToDoc() returns QPoint which only has int // accuracy so we do X and Y manually. targetDocX = vuc->transformViewToDocX (viewPoint.x ()); targetDocY = vuc->transformViewToDocY (viewPoint.y ()); targetDocAvail = true; - if (vuc != d->mainView) + if (vuc != d->mainView) { viewPoint = vuc->transformViewToOtherView (viewPoint, d->mainView); + } viewX = viewPoint.x (); viewY = viewPoint.y (); } else { viewX = d->scrollView->horizontalScrollBar()->value () + qMin (d->mainView->width (), d->scrollView->viewport()->width ()) / 2; viewY = d->scrollView->verticalScrollBar()->value () + qMin (d->mainView->height (), d->scrollView->viewport()->height ()) / 2; } int newCenterX = viewX * zoomLevel / d->mainView->zoomLevelX (); int newCenterY = viewY * zoomLevel / d->mainView->zoomLevelY (); // Do the zoom. d->mainView->setZoomLevel (zoomLevel, zoomLevel); qCDebug(kpLogMainWindow) << "\tvisibleWidth=" << d->scrollView->viewport()->width () - << " visibleHeight=" << d->scrollView->viewport()->height () - << endl; + << " visibleHeight=" << d->scrollView->viewport()->height (); qCDebug(kpLogMainWindow) << "\tnewCenterX=" << newCenterX - << " newCenterY=" << newCenterY << endl; + << " newCenterY=" << newCenterY; d->scrollView->horizontalScrollBar()->setValue(newCenterX - (d->scrollView->viewport()->width() / 2)); d->scrollView->verticalScrollBar()->setValue(newCenterY - (d->scrollView->viewport()->height() / 2)); if (centerUnderCursor && targetDocAvail && d->viewManager && d->viewManager->viewUnderCursor ()) { // Move the mouse cursor so that it is still above the same // document pixel as before the zoom. kpView *const vuc = d->viewManager->viewUnderCursor (); qCDebug(kpLogMainWindow) << "\tcenterUnderCursor: reposition cursor; viewUnderCursor=" - << vuc->objectName () << endl; + << vuc->objectName (); - const double viewX = vuc->transformDocToViewX (targetDocX); - const double viewY = vuc->transformDocToViewY (targetDocY); + const auto viewX = vuc->transformDocToViewX (targetDocX); + const auto viewY = vuc->transformDocToViewY (targetDocY); // Rounding error from zooming in and out :( // TODO: do everything in terms of tool doc points in type "double". const QPoint viewPoint (static_cast (viewX), static_cast (viewY)); qCDebug(kpLogMainWindow) << "\t\tdoc: (" << targetDocX << "," << targetDocY << ")" - << " viewUnderCursor: (" << viewX << "," << viewY << ")" - << endl; + << " viewUnderCursor: (" << viewX << "," << viewY << ")"; if (vuc->visibleRegion ().contains (viewPoint)) { const QPoint globalPoint = kpWidgetMapper::toGlobal (vuc, viewPoint); qCDebug(kpLogMainWindow) << "\t\tglobalPoint=" << globalPoint; // TODO: Determine some sane cursor flashing indication - // cursor movement is convenient but not conventional. // // Major problem: if using QApplication::setOverrideCursor() // and in some stage of flash and window quits. // // Or if using kpView::setCursor() and change tool. QCursor::setPos (globalPoint); } // e.g. Zoom to 200%, scroll mainView to bottom-right. // Unzoomed Thumbnail shows top-left portion of bottom-right of // mainView. // // Aim cursor at bottom-right of thumbnail and zoom out with // CTRL+Wheel. // // If mainView is now small enough to largely not need scrollbars, // Unzoomed Thumbnail scrolls to show _top-left_ portion // _of top-left_ of mainView. // // Unzoomed Thumbnail no longer contains the point we zoomed out // on top of. else { - qCDebug(kpLogMainWindow) << "\t\twon't move cursor - would get outside view" - << endl; + qCDebug(kpLogMainWindow) << "\t\twon't move cursor - would get outside view"; // TODO: Sane cursor flashing indication that indicates // that the normal cursor movement didn't happen. } } qCDebug(kpLogMainWindow) << "\t\tcheck (contentsX=" << d->scrollView->horizontalScrollBar()->value () << ",contentsY=" << d->scrollView->verticalScrollBar()->value () - << ")" << endl; + << ")"; } zoomToPost (); } //--------------------------------------------------------------------- // private void kpMainWindow::zoomToRect (const QRect &normalizedDocRect, bool accountForGrips, bool careAboutWidth, bool careAboutHeight) { qCDebug(kpLogMainWindow) << "kpMainWindow::zoomToRect(normalizedDocRect=" << normalizedDocRect << ",accountForGrips=" << accountForGrips << ",careAboutWidth=" << careAboutWidth << ",careAboutHeight=" << careAboutHeight << ")"; // You can't care about nothing. Q_ASSERT (careAboutWidth || careAboutHeight); // The size of the scroll view minus the current or future scrollbars. const QSize usableScrollArea (d->scrollView->maximumViewportSize().width() - d->scrollView->verticalScrollBar()->sizeHint().width(), d->scrollView->maximumViewportSize().height() - d->scrollView->horizontalScrollBar()->sizeHint().height()); qCDebug(kpLogMainWindow) << "size=" << d->scrollView->maximumViewportSize() << "scrollbar w=" << d->scrollView->verticalScrollBar()->sizeHint().width() << "usableSize=" << usableScrollArea; // Handle rounding error, mis-estimating the scroll view size and // cosmic rays. We do this because we really don't want unnecessary // scrollbars. This seems to need to be at least 2 for slotFitToWidth() // and friends. // least 2. // TODO: I might have fixed this but check later. const int slack = 0; // The grip and slack are in view coordinates but are never zoomed. const int viewWidth = usableScrollArea.width () - (accountForGrips ? kpGrip::Size : 0) - slack; const int viewHeight = usableScrollArea.height () - (accountForGrips ? kpGrip::Size : 0) - slack; // We want the selected document rectangle to fill the scroll view. // // The integer arithmetic rounds down, rather than to the nearest zoom // level, as rounding down guarantees that the view, at the zoom level, // will fit inside x . const int zoomX = careAboutWidth ? qMax (1, viewWidth * 100 / normalizedDocRect.width ()) : INT_MAX; const int zoomY = careAboutHeight ? qMax (1, viewHeight * 100 / normalizedDocRect.height ()) : INT_MAX; // Since kpView only supports identical horizontal and vertical zooms, // choose the one that will show the greatest amount of document // content. const int zoomLevel = qMin (zoomX, zoomY); qCDebug(kpLogMainWindow) << "\tzoomX=" << zoomX << " zoomY=" << zoomY - << " -> zoomLevel=" << zoomLevel << endl; + << " -> zoomLevel=" << zoomLevel; zoomToPre (zoomLevel); { d->mainView->setZoomLevel (zoomLevel, zoomLevel); const QPoint viewPoint = d->mainView->transformDocToView (normalizedDocRect.topLeft ()); d->scrollView->horizontalScrollBar()->setValue(viewPoint.x()); d->scrollView->verticalScrollBar()->setValue(viewPoint.y()); } zoomToPost (); } //--------------------------------------------------------------------- // public slot void kpMainWindow::slotActualSize () { zoomTo (100); } //--------------------------------------------------------------------- // public slot void kpMainWindow::slotFitToPage () { if ( d->document ) { zoomToRect ( d->document->rect (), true/*account for grips*/, true/*care about width*/, true/*care about height*/); } } //--------------------------------------------------------------------- // public slot void kpMainWindow::slotFitToWidth () { if ( d->document ) { const QRect docRect ( 0/*x*/, static_cast (d->mainView->transformViewToDocY (d->scrollView->verticalScrollBar()->value ()))/*maintain y*/, d->document->width (), 1/*don't care about height*/); zoomToRect ( docRect, true/*account for grips*/, true/*care about width*/, false/*don't care about height*/); } } //--------------------------------------------------------------------- // public slot void kpMainWindow::slotFitToHeight () { if ( d->document ) { const QRect docRect ( static_cast (d->mainView->transformViewToDocX (d->scrollView->horizontalScrollBar()->value ()))/*maintain x*/, 0/*y*/, 1/*don't care about width*/, d->document->height ()); zoomToRect ( docRect, true/*account for grips*/, false/*don't care about width*/, true/*care about height*/); } } //--------------------------------------------------------------------- // public void kpMainWindow::zoomIn (bool centerUnderCursor) { qCDebug(kpLogMainWindow) << "kpMainWindow::zoomIn(centerUnderCursor=" << centerUnderCursor << ") currentItem=" - << d->actionZoom->currentItem () - << endl; + << d->actionZoom->currentItem (); const int targetItem = d->actionZoom->currentItem () + 1; - if (targetItem >= static_cast (d->zoomList.count ())) + if (targetItem >= static_cast (d->zoomList.count ())) { return; + } d->actionZoom->setCurrentItem (targetItem); qCDebug(kpLogMainWindow) << "\tnew currentItem=" << d->actionZoom->currentItem (); zoomAccordingToZoomAction (centerUnderCursor); } //--------------------------------------------------------------------- // public void kpMainWindow::zoomOut (bool centerUnderCursor) { qCDebug(kpLogMainWindow) << "kpMainWindow::zoomOut(centerUnderCursor=" << centerUnderCursor << ") currentItem=" - << d->actionZoom->currentItem () - << endl; + << d->actionZoom->currentItem (); const int targetItem = d->actionZoom->currentItem () - 1; - if (targetItem < 0) + if (targetItem < 0) { return; + } d->actionZoom->setCurrentItem (targetItem); qCDebug(kpLogMainWindow) << "\tnew currentItem=" << d->actionZoom->currentItem (); zoomAccordingToZoomAction (centerUnderCursor); } //--------------------------------------------------------------------- // public slot void kpMainWindow::slotZoomIn () { qCDebug(kpLogMainWindow) << "kpMainWindow::slotZoomIn ()"; zoomIn (false/*don't center under cursor*/); } //--------------------------------------------------------------------- // public slot void kpMainWindow::slotZoomOut () { qCDebug(kpLogMainWindow) << "kpMainWindow::slotZoomOut ()"; zoomOut (false/*don't center under cursor*/); } //--------------------------------------------------------------------- // public void kpMainWindow::zoomAccordingToZoomAction (bool centerUnderCursor) { qCDebug(kpLogMainWindow) << "kpMainWindow::zoomAccordingToZoomAction(centerUnderCursor=" << centerUnderCursor << ") currentItem=" << d->actionZoom->currentItem () - << " currentText=" << d->actionZoom->currentText () - << endl; + << " currentText=" << d->actionZoom->currentText (); // This might be a new zoom level the user has typed in. zoomTo (::ZoomLevelFromString (d->actionZoom->currentText ()), centerUnderCursor); } //--------------------------------------------------------------------- // private slot void kpMainWindow::slotZoom () { qCDebug(kpLogMainWindow) << "kpMainWindow::slotZoom () index=" << d->actionZoom->currentItem () - << " text='" << d->actionZoom->currentText () << "'" << endl; + << " text='" << d->actionZoom->currentText () << "'"; zoomAccordingToZoomAction (false/*don't center under cursor*/); } //--------------------------------------------------------------------- diff --git a/pixmapfx/kpPixmapFX_DrawShapes.cpp b/pixmapfx/kpPixmapFX_DrawShapes.cpp index b13561b9..07e6c6f8 100644 --- a/pixmapfx/kpPixmapFX_DrawShapes.cpp +++ b/pixmapfx/kpPixmapFX_DrawShapes.cpp @@ -1,273 +1,281 @@ /* Copyright (c) 2003-2007 Clarence Dang All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #define DEBUG_KP_PIXMAP_FX 0 #include "kpPixmapFX.h" #include #include #include #include #include #include "kpLogCategories.h" #include "layers/selections/kpAbstractSelection.h" #include "imagelib/kpColor.h" #include "kpDefs.h" //--------------------------------------------------------------------- // Returns whether there is only 1 distinct point in . bool kpPixmapFX::Only1PixelInPointArray (const QPolygon &points) { - if (points.count () == 0) + if (points.count () == 0) { return false; + } for (int i = 1; i < static_cast (points.count ()); i++) { - if (points [i] != points [0]) + if (points [i] != points [0]) { return false; + } } return true; } //--------------------------------------------------------------------- // Warp the given from 1 to 0. // This is not always done (specifically if ) because // width 0 sometimes looks worse. // // Qt lines of width 1 look like they have a width between 1-2 i.e.: // // # // ## // # // # // // compared to Qt's special "width 0" which just means a "proper" width 1: // // # // # // # // # // static int WidthToQPenWidth (int width, bool drawingEllipse = false) { if (width == 1) { // 3x10 ellipse with Qt width 0 looks like rectangle. // Therefore, do not apply this 1 -> 0 transformations for ellipses. if (!drawingEllipse) { // Closer to looking width 1, for lines at least. return 0; } } return width; } //--------------------------------------------------------------------- static void QPainterSetPenWithStipple (QPainter *p, const kpColor &fColor, int penWidth, const kpColor &fStippleColor = kpColor::Invalid, bool isEllipseLike = false) { if (!fStippleColor.isValid ()) { p->setPen ( kpPixmapFX::QPainterDrawLinePen ( fColor.toQColor(), ::WidthToQPenWidth (penWidth, isEllipseLike))); } else { QPen usePen = kpPixmapFX::QPainterDrawLinePen ( fColor.toQColor(), ::WidthToQPenWidth (penWidth, isEllipseLike)); usePen.setStyle (Qt::DashLine); p->setPen (usePen); p->setBackground (fStippleColor.toQColor()); p->setBackgroundMode (Qt::OpaqueMode); } } //--------------------------------------------------------------------- // public static QPen kpPixmapFX::QPainterDrawRectPen (const QColor &color, int qtWidth) { return QPen (color, qtWidth, Qt::SolidLine, Qt::SquareCap, Qt::MiterJoin); } //--------------------------------------------------------------------- // public static QPen kpPixmapFX::QPainterDrawLinePen (const QColor &color, int qtWidth) { return QPen (color, qtWidth, Qt::SolidLine, Qt::RoundCap, Qt::RoundJoin); } //--------------------------------------------------------------------- // // drawPolyline() / drawLine() // // public static void kpPixmapFX::drawPolyline (QImage *image, const QPolygon &points, const kpColor &color, int penWidth, const kpColor &stippleColor) { QPainter painter(image); ::QPainterSetPenWithStipple(&painter, color, penWidth, stippleColor); // Qt bug: single point doesn't show up depending on penWidth. if (Only1PixelInPointArray(points)) { qCDebug(kpLogPixmapfx) << "\tinvoking single point hack"; painter.drawPoint(points[0]); return; } painter.drawPolyline(points); } //--------------------------------------------------------------------- // // drawPolygon() // // public static void kpPixmapFX::drawPolygon (QImage *image, const QPolygon &points, const kpColor &fcolor, int penWidth, const kpColor &bcolor, bool isFinal, const kpColor &fStippleColor) { QPainter p(image); ::QPainterSetPenWithStipple (&p, fcolor, penWidth, fStippleColor); - if (bcolor.isValid ()) + if (bcolor.isValid ()) { p.setBrush (QBrush (bcolor.toQColor())); + } // HACK: seems to be needed if set_Pen_(Qt::color0) else fills with Qt::color0. - else + else { p.setBrush (Qt::NoBrush); + } // Qt bug: single point doesn't show up depending on penWidth. if (Only1PixelInPointArray (points)) { qCDebug(kpLogPixmapfx) << "\tinvoking single point hack"; p.drawPoint(points [0]); return; } // TODO: why aren't the ends rounded? p.drawPolygon(points, Qt::OddEvenFill); - if ( isFinal ) + if ( isFinal ) { return; + } - if ( points.count() <= 2 ) + if ( points.count() <= 2 ) { return; + } p.setCompositionMode(QPainter::RasterOp_SourceXorDestination); p.setPen(QPen(Qt::white)); p.drawLine(points[0], points[points.count() - 1]); } //--------------------------------------------------------------------- // public static void kpPixmapFX::fillRect (QImage *image, int x, int y, int width, int height, const kpColor &color, const kpColor &stippleColor) { QPainter painter(image); if (!stippleColor.isValid ()) { painter.fillRect (x, y, width, height, color.toQColor()); } else { const int StippleSize = 4; painter.setClipRect (x, y, width, height); for (int dy = 0; dy < height; dy += StippleSize) { for (int dx = 0; dx < width; dx += StippleSize) { const bool parity = ((dy + dx) / StippleSize) % 2; kpColor useColor; - if (!parity) + if (!parity) { useColor = color; - else + } + else { useColor = stippleColor; + } painter.fillRect (x + dx, y + dy, StippleSize, StippleSize, useColor.toQColor()); } } } } //--------------------------------------------------------------------- void kpPixmapFX::drawStippleRect(QImage *image, int x, int y, int width, int height, const kpColor &fColor, const kpColor &fStippleColor) { QPainter painter(image); painter.setPen(QPen(fColor.toQColor(), 1, Qt::DashLine)); painter.setBackground(fStippleColor.toQColor()); painter.setBackgroundMode(Qt::OpaqueMode); painter.drawRect(x, y, width - 1, height - 1); } //--------------------------------------------------------------------- diff --git a/pixmapfx/kpPixmapFX_GetSetPixmapParts.cpp b/pixmapfx/kpPixmapFX_GetSetPixmapParts.cpp index 08f91af9..a0203275 100644 --- a/pixmapfx/kpPixmapFX_GetSetPixmapParts.cpp +++ b/pixmapfx/kpPixmapFX_GetSetPixmapParts.cpp @@ -1,140 +1,140 @@ /* Copyright (c) 2003-2007 Clarence Dang All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #define DEBUG_KP_PIXMAP_FX 0 #include "kpPixmapFX.h" #include #include #include #include #include "kpLogCategories.h" #include "imagelib/kpColor.h" //--------------------------------------------------------------------- // public static QImage kpPixmapFX::getPixmapAt (const QImage &image, const QRect &rect) { return image.copy(rect); } //--------------------------------------------------------------------- // public static void kpPixmapFX::setPixmapAt(QImage *destPtr, const QRect &destRect, const QImage &src) { qCDebug(kpLogPixmapfx) << "kpPixmapFX::setPixmapAt(destPixmap->rect=" << destPtr->rect () << ",destRect=" << destRect << ",src.rect=" << src.rect () - << ")" - << endl; + << ")"; Q_ASSERT (destPtr); // You cannot copy more than what you have. Q_ASSERT (destRect.width () <= src.width () && destRect.height () <= src.height ()); QPainter painter(destPtr); // destination shall be source only painter.setCompositionMode(QPainter::CompositionMode_Source); painter.drawImage(destRect.topLeft(), src, QRect(0, 0, destRect.width(), destRect.height())); } //--------------------------------------------------------------------- // public static void kpPixmapFX::setPixmapAt (QImage *destPtr, const QPoint &destAt, const QImage &src) { kpPixmapFX::setPixmapAt (destPtr, QRect (destAt.x (), destAt.y (), src.width (), src.height ()), src); } //--------------------------------------------------------------------- // public static void kpPixmapFX::setPixmapAt (QImage *destPtr, int destX, int destY, const QImage &src) { kpPixmapFX::setPixmapAt (destPtr, QPoint (destX, destY), src); } //--------------------------------------------------------------------- // public static void kpPixmapFX::paintPixmapAt (QImage *destPtr, const QPoint &destAt, const QImage &src) { // draw image with SourceOver composition mode QPainter painter(destPtr); painter.drawImage(destAt, src); } //--------------------------------------------------------------------- // public static void kpPixmapFX::paintPixmapAt (QImage *destPtr, int destX, int destY, const QImage &src) { kpPixmapFX::paintPixmapAt(destPtr, QPoint (destX, destY), src); } //--------------------------------------------------------------------- // public static kpColor kpPixmapFX::getColorAtPixel (const QImage &img, const QPoint &at) { - if (!img.valid (at.x (), at.y ())) + if (!img.valid (at.x (), at.y ())) { return kpColor::Invalid; + } QRgb rgba = img.pixel(at); return kpColor (rgba); } //--------------------------------------------------------------------- // public static kpColor kpPixmapFX::getColorAtPixel (const QImage &img, int x, int y) { return kpPixmapFX::getColorAtPixel (img, QPoint (x, y)); } //--------------------------------------------------------------------- diff --git a/pixmapfx/kpPixmapFX_Transforms.cpp b/pixmapfx/kpPixmapFX_Transforms.cpp index e4beb91b..3d1260ae 100644 --- a/pixmapfx/kpPixmapFX_Transforms.cpp +++ b/pixmapfx/kpPixmapFX_Transforms.cpp @@ -1,605 +1,612 @@ /* Copyright (c) 2003-2007 Clarence Dang All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #define DEBUG_KP_PIXMAP_FX 0 #include "kpPixmapFX.h" #include #include #include #include #include #include "kpLogCategories.h" #include "layers/selections/kpAbstractSelection.h" #include "imagelib/kpColor.h" #include "kpDefs.h" //--------------------------------------------------------------------- // public static void kpPixmapFX::resize (QImage *destPtr, int w, int h, const kpColor &backgroundColor) { qCDebug(kpLogPixmapfx) << "kpPixmapFX::resize()"; - if (!destPtr) + if (!destPtr) { return; + } const int oldWidth = destPtr->width (); const int oldHeight = destPtr->height (); - if (w == oldWidth && h == oldHeight) + if (w == oldWidth && h == oldHeight) { return; + } QImage newImage (w, h, QImage::Format_ARGB32_Premultiplied); // Would have new undefined areas? - if (w > oldWidth || h > oldHeight) + if (w > oldWidth || h > oldHeight) { newImage.fill (backgroundColor.toQRgb ()); + } // Copy over old pixmap. QPainter painter(&newImage); painter.setCompositionMode(QPainter::CompositionMode_Source); painter.drawImage(0, 0, *destPtr); painter.end(); // Replace pixmap with new one. *destPtr = newImage; } //--------------------------------------------------------------------- // public static QImage kpPixmapFX::resize (const QImage &image, int w, int h, const kpColor &backgroundColor) { QImage ret = image; kpPixmapFX::resize (&ret, w, h, backgroundColor); return ret; } //--------------------------------------------------------------------- // public static void kpPixmapFX::scale (QImage *destPtr, int w, int h, bool pretty) { - if (!destPtr) + if (!destPtr) { return; + } *destPtr = kpPixmapFX::scale (*destPtr, w, h, pretty); } //--------------------------------------------------------------------- // public static QImage kpPixmapFX::scale (const QImage &image, int w, int h, bool pretty) { qCDebug(kpLogPixmapfx) << "kpPixmapFX::scale(oldRect=" << image.rect () << ",w=" << w << ",h=" << h << ",pretty=" << pretty - << ")" - << endl; + << ")"; - if (w == image.width () && h == image.height ()) + if (w == image.width () && h == image.height ()) { return image; + } return image.scaled(w, h, Qt::IgnoreAspectRatio, pretty ? Qt::SmoothTransformation : Qt::FastTransformation); } //--------------------------------------------------------------------- // public static const double kpPixmapFX::AngleInDegreesEpsilon = qRadiansToDegrees (std::tan (1.0 / 10000.0)) / (2.0/*max error allowed*/ * 2.0/*for good measure*/); -static void MatrixDebug (const QString matrixName, const QTransform &matrix, +static void MatrixDebug (const QString& matrixName, const QTransform &matrix, int srcPixmapWidth = -1, int srcPixmapHeight = -1) { const int w = srcPixmapWidth, h = srcPixmapHeight; qCDebug(kpLogPixmapfx) << matrixName << "=" << matrix; // Sometimes this precision lets us see unexpected rounding errors. fprintf (stderr, "m11=%.24f m12=%.24f m21=%.24f m22=%.24f dx=%.24f dy=%.24f\n", matrix.m11 (), matrix.m12 (), matrix.m21 (), matrix.m22 (), matrix.dx (), matrix.dy ()); if (w > 0 && h > 0) { qCDebug(kpLogPixmapfx) << "(0,0) ->" << matrix.map (QPoint (0, 0)); qCDebug(kpLogPixmapfx) << "(w-1,0) ->" << matrix.map (QPoint (w - 1, 0)); qCDebug(kpLogPixmapfx) << "(0,h-1) ->" << matrix.map (QPoint (0, h - 1)); qCDebug(kpLogPixmapfx) << "(w-1,h-1) ->" << matrix.map (QPoint (w - 1, h - 1)); } } //--------------------------------------------------------------------- // Theoretically, this should act the same as QPixmap::trueMatrix() but // it doesn't. As an example, if you rotate tests/transforms.png by 90 // degrees clockwise, this returns the correct of 26 but // QPixmap::trueMatrix() returns 27. // // You should use the returned matrix to map points accurately (e.g. selection // borders). For QPainter::drawPixmap()/drawImage() + setWorldMatrix() // rendering accuracy, pass the returned matrix through QPixmap::trueMatrix() // and use that. // // TODO: If you put the flipMatrix() of tests/transforms.png through this, // the output is the same as QPixmap::trueMatrix(): is one off // (dy=27 instead of 26). // SYNC: I bet this is a Qt4 bug. static QTransform MatrixWithZeroOrigin (const QTransform &matrix, int width, int height) { qCDebug(kpLogPixmapfx) << "matrixWithZeroOrigin(w=" << width << ",h=" << height << ")"; qCDebug(kpLogPixmapfx) << "\tmatrix: m11=" << matrix.m11 () << "m12=" << matrix.m12 () << "m21=" << matrix.m21 () << "m22=" << matrix.m22 () << "dx=" << matrix.dx () << "dy=" << matrix.dy (); QRect mappedRect = matrix.mapRect (QRect (0, 0, width, height)); qCDebug(kpLogPixmapfx) << "\tmappedRect=" << mappedRect; QTransform translatedMatrix ( matrix.m11 (), matrix.m12 (), matrix.m21 (), matrix.m22 (), matrix.dx () - mappedRect.left (), matrix.dy () - mappedRect.top ()); qCDebug(kpLogPixmapfx) << "\treturning" << translatedMatrix; qCDebug(kpLogPixmapfx) << "(0,0) ->" << translatedMatrix.map (QPoint (0, 0)); qCDebug(kpLogPixmapfx) << "(w-1,0) ->" << translatedMatrix.map (QPoint (width - 1, 0)); qCDebug(kpLogPixmapfx) << "(0,h-1) ->" << translatedMatrix.map (QPoint (0, height - 1)); qCDebug(kpLogPixmapfx) << "(w-1,h-1) ->" << translatedMatrix.map (QPoint (width - 1, height - 1)); return translatedMatrix; } //--------------------------------------------------------------------- static double TrueMatrixEpsilon = 0.000001; // An attempt to reverse tiny rounding errors introduced by QPixmap::trueMatrix() // when skewing tests/transforms.png by 45% horizontally (with TransformPixmap() // using a QPixmap painter, prior to the 2007-10-09 change -- did not test after // the change). // Unfortunately, this does not work enough to stop the rendering errors // that follow. But it was worth a try and might still help us given the // sometimes excessive aliasing QPainter::draw{Pixmap,Image}() gives us, when // QPainter::SmoothPixmapTransform is disabled. static double TrueMatrixFixInts (double x) { - if (std::fabs (x - qRound (x)) < TrueMatrixEpsilon) + if (std::fabs (x - qRound (x)) < TrueMatrixEpsilon) { return qRound (x); - else - return x; + } + + return x; } //--------------------------------------------------------------------- static QTransform TrueMatrix (const QTransform &matrix, int srcPixmapWidth, int srcPixmapHeight) { ::MatrixDebug ("TrueMatrix(): org", matrix); const QTransform truMat = QPixmap::trueMatrix (matrix, srcPixmapWidth, srcPixmapHeight); ::MatrixDebug ("TrueMatrix(): passed through QPixmap::trueMatrix()", truMat); const QTransform retMat ( ::TrueMatrixFixInts (truMat.m11 ()), ::TrueMatrixFixInts (truMat.m12 ()), ::TrueMatrixFixInts (truMat.m21 ()), ::TrueMatrixFixInts (truMat.m22 ()), ::TrueMatrixFixInts (truMat.dx ()), ::TrueMatrixFixInts (truMat.dy ())); ::MatrixDebug ("TrueMatrix(): fixed ints", retMat); return retMat; } //--------------------------------------------------------------------- // Like QPixmap::transformed() but fills new areas with // (unless is invalid) and works around internal QTransform // floating point -> integer oddities, that would otherwise give fatally // incorrect results. If you don't believe me on this latter point, compare // QPixmap::transformed() to us using a flip matrix or a rotate-by-multiple-of-90 // matrix on tests/transforms.png -- QPixmap::transformed()'s output is 1 // pixel too high or low depending on whether the matrix is passed through // QPixmap::trueMatrix(). // // Use and to specify the intended output size // of the pixmap. -1 if don't care. static QImage TransformPixmap (const QImage &pm, const QTransform &transformMatrix_, const kpColor &backgroundColor, int targetWidth, int targetHeight) { QTransform transformMatrix = transformMatrix_; qCDebug(kpLogPixmapfx) << "kppixmapfx.cpp: TransformPixmap(pm.size=" << pm.size () << ",targetWidth=" << targetWidth << ",targetHeight=" << targetHeight - << ")" - << endl; + << ")"; QRect newRect = transformMatrix.mapRect (pm.rect ()); qCDebug(kpLogPixmapfx) << "\tmappedRect=" << newRect; QTransform scaleMatrix; if (targetWidth > 0 && targetWidth != newRect.width ()) { qCDebug(kpLogPixmapfx) << "\tadjusting for targetWidth"; scaleMatrix.scale (double (targetWidth) / double (newRect.width ()), 1); } if (targetHeight > 0 && targetHeight != newRect.height ()) { qCDebug(kpLogPixmapfx) << "\tadjusting for targetHeight"; scaleMatrix.scale (1, double (targetHeight) / double (newRect.height ())); } if (!scaleMatrix.isIdentity ()) { // TODO: What is going on here??? Why isn't matrix * working properly? QTransform wrongMatrix = transformMatrix * scaleMatrix; QTransform oldHat = transformMatrix; - if (targetWidth > 0 && targetWidth != newRect.width ()) + + if (targetWidth > 0 && targetWidth != newRect.width ()) { oldHat.scale (double (targetWidth) / double (newRect.width ()), 1); - if (targetHeight > 0 && targetHeight != newRect.height ()) + } + if (targetHeight > 0 && targetHeight != newRect.height ()) { oldHat.scale (1, double (targetHeight) / double (newRect.height ())); + } + QTransform altHat = transformMatrix; + altHat.scale ((targetWidth > 0 && targetWidth != newRect.width ()) ? double (targetWidth) / double (newRect.width ()) : 1, (targetHeight > 0 && targetHeight != newRect.height ()) ? double (targetHeight) / double (newRect.height ()) : 1); QTransform correctMatrix = scaleMatrix * transformMatrix; qCDebug(kpLogPixmapfx) << "\tsupposedlyWrongMatrix: m11=" << wrongMatrix.m11 () // <<<---- this is the correct matrix??? << " m12=" << wrongMatrix.m12 () << " m21=" << wrongMatrix.m21 () << " m22=" << wrongMatrix.m22 () << " dx=" << wrongMatrix.dx () << " dy=" << wrongMatrix.dy () << " rect=" << wrongMatrix.mapRect (pm.rect ()) - << endl + << "\n" << "\ti_used_to_use_thisMatrix: m11=" << oldHat.m11 () << " m12=" << oldHat.m12 () << " m21=" << oldHat.m21 () << " m22=" << oldHat.m22 () << " dx=" << oldHat.dx () << " dy=" << oldHat.dy () << " rect=" << oldHat.mapRect (pm.rect ()) - << endl + << "\n" << "\tabove but scaled at the same time: m11=" << altHat.m11 () << " m12=" << altHat.m12 () << " m21=" << altHat.m21 () << " m22=" << altHat.m22 () << " dx=" << altHat.dx () << " dy=" << altHat.dy () << " rect=" << altHat.mapRect (pm.rect ()) - << endl + << "\n" << "\tsupposedlyCorrectMatrix: m11=" << correctMatrix.m11 () << " m12=" << correctMatrix.m12 () << " m21=" << correctMatrix.m21 () << " m22=" << correctMatrix.m22 () << " dx=" << correctMatrix.dx () << " dy=" << correctMatrix.dy () - << " rect=" << correctMatrix.mapRect (pm.rect ()) - << endl; + << " rect=" << correctMatrix.mapRect (pm.rect ()); transformMatrix = transformMatrix * scaleMatrix; newRect = transformMatrix.mapRect (pm.rect ()); qCDebug(kpLogPixmapfx) << "\tnewRect after targetWidth,targetHeight adjust=" << newRect; } ::MatrixDebug ("TransformPixmap(): before trueMatrix", transformMatrix, pm.width (), pm.height ()); QTransform oldMatrix = transformMatrix; // Translate the matrix to account for Qt rounding errors, // so that flipping (if it used this method) and rotating by a multiple // of 90 degrees actually work as expected (try tests/transforms.png). // // SYNC: This was not required with Qt3 so we are actually working // around a Qt4 bug/feature. // // COMPAT: Qt4's rendering with a matrix enabled is low quality anyway // but does this reduce quality even further? // // With or without it, skews by 45 degrees with the QImage // painter below look bad (with it, you get an extra transparent // line on the right; without, you get only about 1/4 of a source // line on the left). In Qt3, with TrueMatrix(), the source // image is translated 1 pixel off the destination image. // // Also, if you skew a rectangular selection, the skewed selection // border does not line up with the skewed image data. // TODO: do we need to pass through this new matrix? transformMatrix = ::TrueMatrix (transformMatrix, pm.width (), pm.height ()); qCDebug(kpLogPixmapfx) << "trueMatrix changed matrix?" << (oldMatrix == transformMatrix); ::MatrixDebug ("TransformPixmap(): after trueMatrix", transformMatrix, pm.width (), pm.height ()); QImage newQImage (targetWidth > 0 ? targetWidth : newRect.width (), targetHeight > 0 ? targetHeight : newRect.height (), QImage::Format_ARGB32_Premultiplied); if ((targetWidth > 0 && targetWidth != newRect.width ()) || (targetHeight > 0 && targetHeight != newRect.height ())) { qCDebug(kpLogPixmapfx) << "kppixmapfx.cpp: TransformPixmap(pm.size=" << pm.size () << ",targetWidth=" << targetWidth << ",targetHeight=" << targetHeight << ") newRect=" << newRect - << " (you are a victim of rounding error)" - << endl; + << " (you are a victim of rounding error)"; } // Note: Do _not_ use "p.setRenderHints (QPainter::SmoothPixmapTransform);" // as the user does not want their image to get blurier every // time they e.g. rotate it (especially important for multiples // of 90 degrees but also true for every other angle). Being a // pixel-based program, we generally like to preserve RGB values // and avoid unnecessary blurs -- in the worst case, we'd rather // drop pixels, than blur. QPainter p (&newQImage); { // Make sure transparent pixels are drawn into the destination image. p.setCompositionMode (QPainter::CompositionMode_Source); // Fill the entire new image with the background color. if (backgroundColor.isValid ()) { p.fillRect (newQImage.rect (), backgroundColor.toQColor ()); } p.setWorldTransform (transformMatrix); p.drawImage (QPoint (0, 0), pm); } p.end (); - qCDebug(kpLogPixmapfx) << "Done" << endl << endl; + qCDebug(kpLogPixmapfx) << "Done"; return newQImage; } //--------------------------------------------------------------------- // public static QTransform kpPixmapFX::skewMatrix (int width, int height, double hangle, double vangle) { if (std::fabs (hangle - 0) < kpPixmapFX::AngleInDegreesEpsilon && std::fabs (vangle - 0) < kpPixmapFX::AngleInDegreesEpsilon) { - return QTransform (); + return {}; } /* Diagram for completeness :) * * |---------- w ----------| * (0,0) * _ _______________________ (w,0) * | |\~_ va | * | | \ ~_ | * | |ha\ ~__ | * | \ ~__ | dy * h | \ ~___ | * | \ ~___ | * | | \ ~___| (w,w*tan(va)=dy) * | | \ * \ * _ |________\________|_____|\ vertical shear factor * (0,h) dx ^~_ | \ | * | ~_ \________\________ General Point (x,y) V * | ~__ \ Skewed Point (x + y*tan(ha),y + x*tan(va)) * (h*tan(ha)=dx,h) ~__ \ ^ * ~___ \ | * ~___ \ horizontal shear factor * Key: ~___\ * ha = hangle (w + h*tan(ha)=w+dx,h + w*tan(va)=w+dy) * va = vangle * * Skewing really just twists a rectangle into a parallelogram. * */ //QTransform matrix (1, tan (KP_DEGREES_TO_RADIANS (vangle)), tan (KP_DEGREES_TO_RADIANS (hangle)), 1, 0, 0); // I think this is clearer than above :) QTransform matrix; matrix.shear (std::tan (qDegreesToRadians (hangle)), std::tan (qDegreesToRadians (vangle))); return ::MatrixWithZeroOrigin (matrix, width, height); } //--------------------------------------------------------------------- // public static QTransform kpPixmapFX::skewMatrix (const QImage &pixmap, double hangle, double vangle) { return kpPixmapFX::skewMatrix (pixmap.width (), pixmap.height (), hangle, vangle); } //--------------------------------------------------------------------- // public static void kpPixmapFX::skew (QImage *destPtr, double hangle, double vangle, const kpColor &backgroundColor, int targetWidth, int targetHeight) { - if (!destPtr) + if (!destPtr) { return; + } *destPtr = kpPixmapFX::skew (*destPtr, hangle, vangle, backgroundColor, targetWidth, targetHeight); } //--------------------------------------------------------------------- // public static QImage kpPixmapFX::skew (const QImage &pm, double hangle, double vangle, const kpColor &backgroundColor, int targetWidth, int targetHeight) { qCDebug(kpLogPixmapfx) << "kpPixmapFX::skew() pm.width=" << pm.width () << " pm.height=" << pm.height () << " hangle=" << hangle << " vangle=" << vangle << " targetWidth=" << targetWidth - << " targetHeight=" << targetHeight - << endl; + << " targetHeight=" << targetHeight; if (std::fabs (hangle - 0) < kpPixmapFX::AngleInDegreesEpsilon && std::fabs (vangle - 0) < kpPixmapFX::AngleInDegreesEpsilon && (targetWidth <= 0 && targetHeight <= 0)/*don't want to scale?*/) { return pm; } if (std::fabs (hangle) > 90 - kpPixmapFX::AngleInDegreesEpsilon || std::fabs (vangle) > 90 - kpPixmapFX::AngleInDegreesEpsilon) { - qCCritical(kpLogPixmapfx) << "kpPixmapFX::skew() passed hangle and/or vangle out of range (-90 < x < 90)" << endl; + qCCritical(kpLogPixmapfx) << "kpPixmapFX::skew() passed hangle and/or vangle out of range (-90 < x < 90)"; return pm; } QTransform matrix = skewMatrix (pm, hangle, vangle); return ::TransformPixmap (pm, matrix, backgroundColor, targetWidth, targetHeight); } //--------------------------------------------------------------------- // public static QTransform kpPixmapFX::rotateMatrix (int width, int height, double angle) { if (std::fabs (angle - 0) < kpPixmapFX::AngleInDegreesEpsilon) { - return QTransform (); + return {}; } QTransform matrix; matrix.translate (width / 2, height / 2); matrix.rotate (angle); return ::MatrixWithZeroOrigin (matrix, width, height); } //--------------------------------------------------------------------- // public static QTransform kpPixmapFX::rotateMatrix (const QImage &pixmap, double angle) { return kpPixmapFX::rotateMatrix (pixmap.width (), pixmap.height (), angle); } //--------------------------------------------------------------------- // public static bool kpPixmapFX::isLosslessRotation (double angle) { const double angleIn = angle; // Reflect angle into positive if negative - if (angle < 0) + if (angle < 0) { angle = -angle; + } // Remove multiples of 90 to make sure 0 <= angle <= 90 angle -= (static_cast (angle)) / 90 * 90; // "Impossible" situation? if (angle < 0 || angle > 90) { qCCritical(kpLogPixmapfx) << "kpPixmapFX::isLosslessRotation(" << angleIn - << ") result=" << angle - << endl; + << ") result=" << angle; return false; // better safe than sorry } const bool ret = (angle < kpPixmapFX::AngleInDegreesEpsilon || 90 - angle < kpPixmapFX::AngleInDegreesEpsilon); qCDebug(kpLogPixmapfx) << "kpPixmapFX::isLosslessRotation(" << angleIn << ")" << " residual angle=" << angle - << " returning " << ret - << endl; + << " returning " << ret; return ret; } //--------------------------------------------------------------------- // public static void kpPixmapFX::rotate (QImage *destPtr, double angle, const kpColor &backgroundColor, int targetWidth, int targetHeight) { - if (!destPtr) + if (!destPtr) { return; + } *destPtr = kpPixmapFX::rotate (*destPtr, angle, backgroundColor, targetWidth, targetHeight); } //--------------------------------------------------------------------- // public static QImage kpPixmapFX::rotate (const QImage &pm, double angle, const kpColor &backgroundColor, int targetWidth, int targetHeight) { if (std::fabs (angle - 0) < kpPixmapFX::AngleInDegreesEpsilon && (targetWidth <= 0 && targetHeight <= 0)/*don't want to scale?*/) { return pm; } QTransform matrix = rotateMatrix (pm, angle); return ::TransformPixmap (pm, matrix, backgroundColor, targetWidth, targetHeight); } //--------------------------------------------------------------------- diff --git a/scan/sanedialog.cpp b/scan/sanedialog.cpp index 058a2541..8614fd87 100644 --- a/scan/sanedialog.cpp +++ b/scan/sanedialog.cpp @@ -1,118 +1,120 @@ /* ============================================================ * * Date : 2008-04-17 * Description : Sane plugin interface for KDE * * Copyright (C) 2008 by Kare Sars * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) version 3, or any * later version accepted by the membership of KDE e.V. (or its * successor approved by the membership of KDE e.V.), which shall * act as a proxy defined in Section 6 of version 3 of the license. * * This library 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 * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this program. If not, see . * * ============================================================ */ #include "sanedialog.h" #include #include "kpLogCategories.h" #include #include #include #include #include SaneDialog::SaneDialog(QWidget *parent) : KPageDialog(parent) { setFaceType(static_cast (Plain)); setWindowTitle(i18nc("@title:window", "Acquire Image")); buttonBox()->setStandardButtons(QDialogButtonBox::Close); buttonBox()->button(QDialogButtonBox::Close)->setDefault(true); m_ksanew = new KSaneIface::KSaneWidget(this); addPage(m_ksanew, QString()); connect (m_ksanew, &KSaneIface::KSaneWidget::imageReady, this, &SaneDialog::imageReady); m_openDev = QString(); } bool SaneDialog::setup() { if(!m_ksanew) { // new failed return false; } if (!m_openDev.isEmpty()) { return true; } // need to select a scanner m_openDev = m_ksanew->selectDevice(nullptr); if (m_openDev.isEmpty()) { // either no scanner was found or then cancel was pressed. return false; } - if (m_ksanew->openDevice(m_openDev) == false) { + if (!m_ksanew->openDevice(m_openDev)) { // could not open the scanner KMessageBox::sorry(nullptr, i18n("Opening the selected scanner failed.")); m_openDev = QString(); return false; } // restore scan dialog size and all options for the selected device if available KSharedConfigPtr configPtr = KSharedConfig::openConfig("scannersettings"); KWindowConfig::restoreWindowSize(windowHandle(), KConfigGroup(configPtr, "ScanDialog")); QString groupName = m_openDev; if (configPtr->hasGroup(groupName)) { KConfigGroup group(configPtr, groupName); QStringList keys = group.keyList(); - for (int i = 0; i < keys.count(); i++) + for (int i = 0; i < keys.count(); i++) { m_ksanew->setOptVal(keys[i], group.readEntry(keys[i])); + } } return true; } SaneDialog::~SaneDialog() { if (m_ksanew && !m_openDev.isEmpty()) { // save scan dialog size and all options for the selected device if available KSharedConfigPtr configPtr = KSharedConfig::openConfig("scannersettings"); KConfigGroup group(configPtr, "ScanDialog"); KWindowConfig::saveWindowSize(windowHandle(), group, KConfigGroup::Persistent); group = configPtr->group(m_openDev); QMap opts; m_ksanew->getOptVals(opts); QMap::const_iterator i = opts.constBegin(); - for (; i != opts.constEnd(); ++i) + for (; i != opts.constEnd(); ++i) { group.writeEntry(i.key(), i.value(), KConfigGroup::Persistent); + } } } void SaneDialog::imageReady(QByteArray &data, int w, int h, int bpl, int f) { /* copy the image data into img */ QImage img = m_ksanew->toQImage(data, w, h, bpl, static_cast (f)); emit finalImage(img, nextId()); } int SaneDialog::nextId() { return ++m_currentId; } diff --git a/tools/flow/kpToolColorEraser.cpp b/tools/flow/kpToolColorEraser.cpp index 9ac5ee69..aff0f955 100644 --- a/tools/flow/kpToolColorEraser.cpp +++ b/tools/flow/kpToolColorEraser.cpp @@ -1,158 +1,152 @@ /* Copyright (c) 2003-2007 Clarence Dang All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #define DEBUG_KP_TOOL_COLOR_ERASER 0 #include "kpToolColorEraser.h" #include #include "kpLogCategories.h" #include #include "imagelib/kpColor.h" #include "commands/kpCommandHistory.h" #include "document/kpDocument.h" #include "commands/kpMacroCommand.h" #include "imagelib/kpPainter.h" #include "pixmapfx/kpPixmapFX.h" #include "commands/tools/flow/kpToolFlowCommand.h" #include "environments/tools/kpToolEnvironment.h" //-------------------------------------------------------------------------------- kpToolColorEraser::kpToolColorEraser (kpToolEnvironment *environ, QObject *parent) : kpToolFlowBase (i18n ("Color Eraser"), i18n ("Replaces pixels of the foreground color with the background color"), Qt::Key_O, environ, parent, "tool_color_eraser") { } //-------------------------------------------------------------------------------- -kpToolColorEraser::~kpToolColorEraser () -{ -} +kpToolColorEraser::~kpToolColorEraser () = default; //-------------------------------------------------------------------------------- // public virtual [base kpTool] void kpToolColorEraser::globalDraw () { qCDebug(kpLogTools) << "kpToolColorEraser::globalDraw()"; - if (!drawShouldProceed (QPoint ()/*unused*/, QPoint ()/*unused*/, QRect ()/*unused*/)) + if (!drawShouldProceed (QPoint ()/*unused*/, QPoint ()/*unused*/, QRect ()/*unused*/)) { return; + } QApplication::setOverrideCursor (Qt::WaitCursor); environ ()->flashColorSimilarityToolBarItem (); kpToolFlowCommand *cmd = new kpToolFlowCommand ( i18n ("Color Eraser"), environ ()->commandEnvironment ()); const QRect dirtyRect = kpPainter::washRect (document ()->imagePointer (), 0, 0, document ()->width (), document ()->height (), backgroundColor ()/*color to draw in*/, foregroundColor ()/*color to replace*/, processedColorSimilarity ()); if (!dirtyRect.isEmpty ()) { document ()->slotContentsChanged (dirtyRect); cmd->updateBoundingRect (dirtyRect); cmd->finalize (); commandHistory ()->addCommand (cmd, false /* don't exec */); // don't delete - it's up to the commandHistory cmd = nullptr; } else { qCDebug(kpLogTools) << "\tisNOP"; delete cmd; cmd = nullptr; } QApplication::restoreOverrideCursor (); } //-------------------------------------------------------------------------------- QString kpToolColorEraser::haventBegunDrawUserMessage () const { return i18n ("Click or drag to erase pixels of the foreground color."); } //-------------------------------------------------------------------------------- bool kpToolColorEraser::drawShouldProceed (const QPoint & /*thisPoint*/, const QPoint & /*lastPoint*/, const QRect & /*normalizedRect*/) { - if (foregroundColor () == backgroundColor () && - processedColorSimilarity () == 0) - { - return false; - } - - return true; + return !(foregroundColor () == backgroundColor () && + processedColorSimilarity () == 0); } //-------------------------------------------------------------------------------- QRect kpToolColorEraser::drawLine (const QPoint &thisPoint, const QPoint &lastPoint) { qCDebug(kpLogTools) << "kpToolColorEraser::drawLine(thisPoint=" << thisPoint - << ",lastPoint=" << lastPoint << ")" << endl; + << ",lastPoint=" << lastPoint << ")"; environ ()->flashColorSimilarityToolBarItem (); const QRect dirtyRect = kpPainter::washLine (document ()->imagePointer (), lastPoint.x (), lastPoint.y (), thisPoint.x (), thisPoint.y (), color (mouseButton ())/*color to draw in*/, brushWidth (), brushHeight (), color (1 - mouseButton ())/*color to replace*/, processedColorSimilarity ()); qCDebug(kpLogTools) << "\tdirtyRect=" << dirtyRect; if (!dirtyRect.isEmpty ()) { document ()->slotContentsChanged (dirtyRect); return dirtyRect; } - return QRect (); + return {}; } //-------------------------------------------------------------------------------- diff --git a/tools/flow/kpToolFlowBase.cpp b/tools/flow/kpToolFlowBase.cpp index 35b02131..4677a78d 100644 --- a/tools/flow/kpToolFlowBase.cpp +++ b/tools/flow/kpToolFlowBase.cpp @@ -1,474 +1,476 @@ /* Copyright (c) 2003-2007 Clarence Dang All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #define DEBUG_KP_TOOL_FLOW_BASE 0 #include "kpToolFlowBase.h" #include #include #include #include "kpLogCategories.h" #include #include "imagelib/kpColor.h" #include "commands/kpCommandHistory.h" #include "cursors/kpCursorProvider.h" #include "kpDefs.h" #include "document/kpDocument.h" #include "imagelib/kpImage.h" #include "imagelib/kpPainter.h" #include "pixmapfx/kpPixmapFX.h" #include "layers/tempImage/kpTempImage.h" #include "environments/tools/kpToolEnvironment.h" #include "commands/tools/flow/kpToolFlowCommand.h" #include "widgets/toolbars/kpToolToolBar.h" #include "widgets/toolbars/options/kpToolWidgetBrush.h" #include "widgets/toolbars/options/kpToolWidgetEraserSize.h" #include "views/manager/kpViewManager.h" //--------------------------------------------------------------------- struct kpToolFlowBasePrivate { - kpToolWidgetBrush *toolWidgetBrush; - kpToolWidgetEraserSize *toolWidgetEraserSize; + kpToolWidgetBrush *toolWidgetBrush{}; + kpToolWidgetEraserSize *toolWidgetEraserSize{}; // // Cursor and Brush Data // (must be zero if unused) // - kpTempImage::UserFunctionType brushDrawFunc, cursorDrawFunc; + kpTempImage::UserFunctionType brushDrawFunc{}, cursorDrawFunc{}; // Can't use union since package types contain fields requiring // constructors. kpToolWidgetBrush::DrawPackage brushDrawPackageForMouseButton [2]; kpToolWidgetEraserSize::DrawPackage eraserDrawPackageForMouseButton [2]; // Each element points to one of the above (both elements from the same // array). - void *drawPackageForMouseButton [2]; + void *drawPackageForMouseButton [2]{}; - int brushWidth, brushHeight; - int cursorWidth, cursorHeight; + int brushWidth{}, brushHeight{}; + int cursorWidth{}, cursorHeight{}; - bool brushIsDiagonalLine; + bool brushIsDiagonalLine{}; - kpToolFlowCommand *currentCommand; + kpToolFlowCommand *currentCommand{}; }; //--------------------------------------------------------------------- kpToolFlowBase::kpToolFlowBase (const QString &text, const QString &description, int key, kpToolEnvironment *environ, QObject *parent, const QString &name) : kpTool (text, description, key, environ, parent, name), d (new kpToolFlowBasePrivate ()) { d->toolWidgetBrush = nullptr; d->toolWidgetEraserSize = nullptr; clearBrushCursorData (); d->currentCommand = nullptr; } //--------------------------------------------------------------------- kpToolFlowBase::~kpToolFlowBase () { delete d; } //--------------------------------------------------------------------- // private void kpToolFlowBase::clearBrushCursorData () { d->brushDrawFunc = d->cursorDrawFunc = nullptr; memset (&d->brushDrawPackageForMouseButton, 0, sizeof (d->brushDrawPackageForMouseButton)); memset (&d->eraserDrawPackageForMouseButton, 0, sizeof (d->eraserDrawPackageForMouseButton)); memset (&d->drawPackageForMouseButton, 0, sizeof (d->drawPackageForMouseButton)); d->brushWidth = d->brushHeight = 0; d->cursorWidth = d->cursorHeight = 0; d->brushIsDiagonalLine = false; } //--------------------------------------------------------------------- // virtual void kpToolFlowBase::begin () { kpToolToolBar *tb = toolToolBar (); Q_ASSERT (tb); // TODO: Bad smell. Mutually exclusive. Use inheritance. if (haveSquareBrushes ()) { d->toolWidgetEraserSize = tb->toolWidgetEraserSize (); connect (d->toolWidgetEraserSize, &kpToolWidgetEraserSize::eraserSizeChanged, this, &kpToolFlowBase::updateBrushAndCursor); d->toolWidgetEraserSize->show (); updateBrushAndCursor (); viewManager ()->setCursor (kpCursorProvider::lightCross ()); } else if (haveDiverseBrushes ()) { d->toolWidgetBrush = tb->toolWidgetBrush (); connect (d->toolWidgetBrush, &kpToolWidgetBrush::brushChanged, this, &kpToolFlowBase::updateBrushAndCursor); d->toolWidgetBrush->show (); updateBrushAndCursor (); viewManager ()->setCursor (kpCursorProvider::lightCross ()); } setUserMessage (haventBegunDrawUserMessage ()); } //--------------------------------------------------------------------- // virtual void kpToolFlowBase::end () { if (d->toolWidgetEraserSize) { disconnect (d->toolWidgetEraserSize, &kpToolWidgetEraserSize::eraserSizeChanged, this, &kpToolFlowBase::updateBrushAndCursor); d->toolWidgetEraserSize = nullptr; } else if (d->toolWidgetBrush) { disconnect (d->toolWidgetBrush, &kpToolWidgetBrush::brushChanged, this, &kpToolFlowBase::updateBrushAndCursor); d->toolWidgetBrush = nullptr; } kpViewManager *vm = viewManager (); Q_ASSERT (vm); - if (vm->tempImage () && vm->tempImage ()->isBrush ()) + if (vm->tempImage () && vm->tempImage ()->isBrush ()) { vm->invalidateTempImage (); + } - if (haveAnyBrushes ()) + if (haveAnyBrushes ()) { vm->unsetCursor (); + } clearBrushCursorData (); } //--------------------------------------------------------------------- // virtual void kpToolFlowBase::beginDraw () { d->currentCommand = new kpToolFlowCommand (text (), environ ()->commandEnvironment ()); // We normally show the brush cursor in the foreground colour but if the // user starts drawing in the background color, we don't want to leave // the brush cursor in the foreground colour -- just hide it in all cases // to avoid confusion. viewManager ()->invalidateTempImage (); setUserMessage (cancelUserMessage ()); } //--------------------------------------------------------------------- // virtual void kpToolFlowBase::hover (const QPoint &point) { if (point != KP_INVALID_POINT && d->cursorDrawFunc) { viewManager ()->setFastUpdates (); viewManager ()->setTempImage ( kpTempImage (true/*brush*/, hotRect ().topLeft (), d->cursorDrawFunc, d->drawPackageForMouseButton [0/*left button*/], d->cursorWidth, d->cursorHeight)); viewManager ()->restoreFastUpdates (); } setUserShapePoints (point); } //--------------------------------------------------------------------- // virtual QRect kpToolFlowBase::drawPoint (const QPoint &point) { return drawLine (point, point); } //--------------------------------------------------------------------- // virtual void kpToolFlowBase::draw (const QPoint &thisPoint, const QPoint &lastPoint, const QRect &normalizedRect) { - if (!/*virtual*/drawShouldProceed (thisPoint, lastPoint, normalizedRect)) + if (!/*virtual*/drawShouldProceed (thisPoint, lastPoint, normalizedRect)) { return; + } // sync: remember to restoreFastUpdates() in all exit paths viewManager ()->setFastUpdates (); QRect dirtyRect; // TODO: I'm beginning to wonder this drawPoint() "optimization" actually // optimises. Is it worth the complexity? Hence drawPoint() impl above. if (d->brushIsDiagonalLine ? currentPointCardinallyNextToLast () : currentPointNextToLast ()) { dirtyRect = drawPoint (thisPoint); } // in reality, the system is too slow to give us all the MouseMove events // so we "interpolate" the missing points :) else { dirtyRect = drawLine (thisPoint, lastPoint); } d->currentCommand->updateBoundingRect (dirtyRect); viewManager ()->restoreFastUpdates (); setUserShapePoints (thisPoint); } //--------------------------------------------------------------------- // virtual void kpToolFlowBase::cancelShape () { d->currentCommand->finalize (); d->currentCommand->cancel (); delete d->currentCommand; d->currentCommand = nullptr; updateBrushAndCursor (); setUserMessage (i18n ("Let go of all the mouse buttons.")); } //--------------------------------------------------------------------- void kpToolFlowBase::releasedAllButtons () { setUserMessage (haventBegunDrawUserMessage ()); } //--------------------------------------------------------------------- // virtual void kpToolFlowBase::endDraw (const QPoint &, const QRect &) { d->currentCommand->finalize (); environ ()->commandHistory ()->addCommand (d->currentCommand, false/*don't exec*/); // don't delete - it's up to the commandHistory d->currentCommand = nullptr; updateBrushAndCursor (); setUserMessage (haventBegunDrawUserMessage ()); } //--------------------------------------------------------------------- // TODO: maybe the base should be virtual? kpColor kpToolFlowBase::color (int which) { qCDebug(kpLogTools) << "kpToolFlowBase::color (" << which << ")"; // Pen & Brush - if (!colorsAreSwapped ()) + if (!colorsAreSwapped ()) { return kpTool::color (which); + } // only the (Color) Eraser uses the opposite color - else - return kpTool::color (which ? 0 : 1); // don't trust !0 == 1 + return kpTool::color (which ? 0 : 1); // don't trust !0 == 1 } //--------------------------------------------------------------------- // protected kpTempImage::UserFunctionType kpToolFlowBase::brushDrawFunction () const { return d->brushDrawFunc; } //--------------------------------------------------------------------- // protected void *kpToolFlowBase::brushDrawFunctionData () const { return d->drawPackageForMouseButton [mouseButton ()]; } // protected int kpToolFlowBase::brushWidth () const { return d->brushWidth; } // protected int kpToolFlowBase::brushHeight () const { return d->brushHeight; } // protected bool kpToolFlowBase::brushIsDiagonalLine () const { return d->brushIsDiagonalLine; } // protected kpToolFlowCommand *kpToolFlowBase::currentCommand () const { return d->currentCommand; } //--------------------------------------------------------------------- // protected slot void kpToolFlowBase::updateBrushAndCursor () { qCDebug(kpLogTools) << "kpToolFlowBase::updateBrushAndCursor()"; if (haveSquareBrushes ()) { d->brushDrawFunc = d->toolWidgetEraserSize->drawFunction (); d->cursorDrawFunc = d->toolWidgetEraserSize->drawCursorFunction (); for (int i = 0; i < 2; i++) { d->drawPackageForMouseButton [i] = &(d->eraserDrawPackageForMouseButton [i] = d->toolWidgetEraserSize->drawFunctionData (color (i))); } d->brushWidth = d->brushHeight = d->cursorWidth = d->cursorHeight = d->toolWidgetEraserSize->eraserSize (); d->brushIsDiagonalLine = false; } else if (haveDiverseBrushes ()) { d->brushDrawFunc = d->cursorDrawFunc = d->toolWidgetBrush->drawFunction (); for (int i = 0; i < 2; i++) { d->drawPackageForMouseButton [i] = &(d->brushDrawPackageForMouseButton [i] = d->toolWidgetBrush->drawFunctionData (color (i))); } d->brushWidth = d->brushHeight = d->cursorWidth = d->cursorHeight = d->toolWidgetBrush->brushSize (); d->brushIsDiagonalLine = d->toolWidgetBrush->brushIsDiagonalLine (); } hover (hasBegun () ? currentPoint () : calculateCurrentPoint ()); } //--------------------------------------------------------------------- // virtual private slot void kpToolFlowBase::slotForegroundColorChanged (const kpColor & /*col*/) { qCDebug(kpLogTools) << "kpToolFlowBase::slotForegroundColorChanged()"; updateBrushAndCursor (); } //--------------------------------------------------------------------- // virtual private slot void kpToolFlowBase::slotBackgroundColorChanged (const kpColor & /*col*/) { qCDebug(kpLogTools) << "kpToolFlowBase::slotBackgroundColorChanged()"; updateBrushAndCursor (); } //--------------------------------------------------------------------- // public static QRect kpToolFlowBase::hotRectForMousePointAndBrushWidthHeight ( const QPoint &mousePoint, int brushWidth, int brushHeight) { /* * e.g. * Width 5: * 0 1 2 3 4 * ^ * | * Center */ - return QRect (mousePoint.x () - brushWidth / 2, - mousePoint.y () - brushHeight / 2, - brushWidth, - brushHeight); + return {mousePoint.x () - brushWidth / 2, + mousePoint.y () - brushHeight / 2, + brushWidth, brushHeight}; } //--------------------------------------------------------------------- // protected QRect kpToolFlowBase::hotRect () const { return hotRectForMousePointAndBrushWidthHeight (currentPoint (), d->brushWidth, d->brushHeight); } //--------------------------------------------------------------------- diff --git a/tools/flow/kpToolSpraycan.cpp b/tools/flow/kpToolSpraycan.cpp index 937ea04c..c2bb8145 100644 --- a/tools/flow/kpToolSpraycan.cpp +++ b/tools/flow/kpToolSpraycan.cpp @@ -1,241 +1,241 @@ /* Copyright (c) 2003-2007 Clarence Dang All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #define DEBUG_KP_TOOL_SPRAYCAN 0 #include "kpToolSpraycan.h" #include "kpDefs.h" #include "document/kpDocument.h" #include "imagelib/kpPainter.h" #include "pixmapfx/kpPixmapFX.h" #include "environments/tools/kpToolEnvironment.h" #include "commands/tools/flow/kpToolFlowCommand.h" #include "widgets/toolbars/kpToolToolBar.h" #include "widgets/toolbars/options/kpToolWidgetSpraycanSize.h" #include "views/kpView.h" #include "views/manager/kpViewManager.h" #include #include "kpLogCategories.h" #include #include #include #include //--------------------------------------------------------------------- kpToolSpraycan::kpToolSpraycan (kpToolEnvironment *environ, QObject *parent) : kpToolFlowBase (i18n ("Spraycan"), i18n ("Sprays graffiti"), Qt::Key_Y, environ, parent, "tool_spraycan"), m_toolWidgetSpraycanSize(nullptr) { m_timer = new QTimer (this); m_timer->setInterval (25/*ms*/); connect (m_timer, &QTimer::timeout, this, &kpToolSpraycan::timeoutDraw); } //--------------------------------------------------------------------- // protected virtual [base kpToolFlowBase] QString kpToolSpraycan::haventBegunDrawUserMessage () const { return i18n ("Click or drag to spray graffiti."); } //--------------------------------------------------------------------- // public virtual [base kpToolFlowBase] void kpToolSpraycan::begin () { kpToolToolBar *tb = toolToolBar (); Q_ASSERT (tb); m_toolWidgetSpraycanSize = tb->toolWidgetSpraycanSize (); connect (m_toolWidgetSpraycanSize, &kpToolWidgetSpraycanSize::spraycanSizeChanged, this, &kpToolSpraycan::slotSpraycanSizeChanged); m_toolWidgetSpraycanSize->show (); kpToolFlowBase::begin (); } // public virtual [base kpToolFlowBase] void kpToolSpraycan::end () { kpToolFlowBase::end (); disconnect (m_toolWidgetSpraycanSize, &kpToolWidgetSpraycanSize::spraycanSizeChanged, this, &kpToolSpraycan::slotSpraycanSizeChanged); m_toolWidgetSpraycanSize = nullptr; } // public virtual [base kpToolFlowBase] void kpToolSpraycan::beginDraw () { qCDebug(kpLogTools) << "kpToolSpraycan::beginDraw()"; kpToolFlowBase::beginDraw (); // We draw even if the user doesn't move the mouse. // We still timeout-draw even if the user _does_ move the mouse. m_timer->start (); } // protected QRect kpToolSpraycan::drawLineWithProbability (const QPoint &thisPoint, const QPoint &lastPoint, double probability) { qCDebug(kpLogTools) << "CALL(thisPoint=" << thisPoint << ",lastPoint=" << lastPoint - << ")" << endl; + << ")"; QList docPoints = kpPainter::interpolatePoints (lastPoint, thisPoint, false/*no need for cardinally adjacency points*/, probability); qCDebug(kpLogTools) << "\tdocPoints=" << docPoints; // By chance no points to draw? - if (docPoints.empty ()) - return QRect (); + if (docPoints.empty ()) { + return {}; + } // For efficiency, only get image after NOP check above. QRect docRect = kpPainter::normalizedRect(thisPoint, lastPoint); docRect = neededRect (docRect, spraycanSize ()); kpImage image = document ()->getImageAt (docRect); // Spray at each point, onto the image. // // Note in passing: Unlike other tools such as the Brush, drawing // over the same point does result in a different // appearance. QList imagePoints; - foreach (const QPoint &dp, docPoints) + for (const auto &dp : docPoints) imagePoints.append (dp - docRect.topLeft ()); kpPainter::sprayPoints (&image, imagePoints, color (mouseButton ()), spraycanSize ()); viewManager ()->setFastUpdates (); document ()->setImageAt (image, docRect.topLeft ()); viewManager ()->restoreFastUpdates (); return docRect; } // public virtual [base kpToolFlowBase] QRect kpToolSpraycan::drawPoint (const QPoint &point) { qCDebug(kpLogTools) << "kpToolSpraycan::drawPoint" << point - << " lastPoint=" << lastPoint () - << endl; + << " lastPoint=" << lastPoint (); // If this is the first in the flow or if the user is moving the spray, // make the spray line continuous. if (point != lastPoint ()) { // Draw at this single point without delay. return drawLineWithProbability (point, point, 1.0/*100% chance of drawing*/); } - return QRect (); + return {}; } // public virtual [base kpToolFlowBase] QRect kpToolSpraycan::drawLine (const QPoint &thisPoint, const QPoint &lastPoint) { qCDebug(kpLogTools) << "CALL(thisPoint=" << thisPoint << ",lastPoint=" << lastPoint; // Draw only every so often in response to movement. return drawLineWithProbability (thisPoint, lastPoint, 0.05/*less dense: select 5% of adjacent pixels - not all*/); } // protected slot void kpToolSpraycan::timeoutDraw () { qCDebug(kpLogTools) << "kpToolSpraycan::timeoutDraw()"; // Draw at this single point without delay. const QRect drawnRect = drawLineWithProbability (currentPoint (), currentPoint (), 1.0/*100% chance of drawing*/); // kpToolFlowBase() does this after calling drawPoint() and drawLine() so // we need to do it too. currentCommand ()->updateBoundingRect (drawnRect); } // public virtual [base kpToolFlowBase] void kpToolSpraycan::cancelShape () { qCDebug(kpLogTools) << "kpToolSpraycan::cancelShape()"; m_timer->stop (); kpToolFlowBase::cancelShape (); } // public virtual [base kpToolFlowBase] void kpToolSpraycan::endDraw (const QPoint &thisPoint, const QRect &normalizedRect) { qCDebug(kpLogTools) << "kpToolSpraycan::endDraw(thisPoint=" << thisPoint - << ")" << endl; + << ")"; m_timer->stop (); kpToolFlowBase::endDraw (thisPoint, normalizedRect); } // protected int kpToolSpraycan::spraycanSize () const { return m_toolWidgetSpraycanSize->spraycanSize (); } // protected slot void kpToolSpraycan::slotSpraycanSizeChanged (int size) { (void) size; } diff --git a/tools/kpTool.cpp b/tools/kpTool.cpp index 72cdbe10..345c891e 100644 --- a/tools/kpTool.cpp +++ b/tools/kpTool.cpp @@ -1,262 +1,263 @@ /* Copyright (c) 2003-2007 Clarence Dang All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ // // Tool initialisation and basic accessors. // #define DEBUG_KP_TOOL 0 #include "kpTool.h" #include "kpToolPrivate.h" #include #include #include "kpLogCategories.h" #include #include "imagelib/kpColor.h" #include "widgets/toolbars/kpColorToolBar.h" #include "kpDefs.h" #include "tools/kpToolAction.h" #include "environments/tools/kpToolEnvironment.h" #include "widgets/toolbars/kpToolToolBar.h" #include "views/kpView.h" #include "views/manager/kpViewManager.h" #undef environ // macro on win32 //--------------------------------------------------------------------- kpTool::kpTool(const QString &text, const QString &description, int key, kpToolEnvironment *environ, QObject *parent, const QString &name) : QObject(parent), d(new kpToolPrivate()) { d->key = key; d->action = nullptr; d->ignoreColorSignals = 0; d->shiftPressed = false; d->controlPressed = false; d->altPressed = false; // set in beginInternal() d->beganDraw = false; d->text = text; d->description = description; d->began = false; d->viewUnderStartPoint = nullptr; d->userShapeStartPoint = KP_INVALID_POINT; d->userShapeEndPoint = KP_INVALID_POINT; d->userShapeSize = KP_INVALID_SIZE; d->environ = environ; setObjectName(name); initAction(); } //--------------------------------------------------------------------- kpTool::~kpTool () { // before destructing, stop using the tool - if (d->began) + if (d->began) { endInternal (); + } delete d->action; delete d; } //--------------------------------------------------------------------- // private void kpTool::initAction () { KActionCollection *ac = d->environ->actionCollection (); Q_ASSERT (ac); d->action = new kpToolAction(text(), objectName(), shortcutForKey(d->key), this, SIGNAL(actionActivated()), ac, objectName()); // Make tools mutually exclusive by placing them in the same group. d->action->setActionGroup(d->environ->toolsActionGroup ()); d->action->setWhatsThis(d->description); connect (d->action, &kpToolAction::changed, this, &kpTool::actionToolTipChanged); } //--------------------------------------------------------------------- // public QString kpTool::text () const { return d->text; } //--------------------------------------------------------------------- static bool KeyIsText (int key) { // TODO: should work like !QKeyEvent::text().isEmpty() return !(static_cast (key) & (Qt::KeyboardModifierMask ^ Qt::ShiftModifier)); } //--------------------------------------------------------------------- // public static QString kpTool::toolTipForTextAndShortcut (const QString &text, const QList &shortcut) { - foreach(const QKeySequence &seq, shortcut) + for(const auto &seq : shortcut) { - if (seq.count () == 1 && ::KeyIsText (seq [0])) - return i18nc (" ()", - "%1 (%2)", text, seq.toString ().toUpper ()); + if (seq.count () == 1 && ::KeyIsText (seq [0])) { + return i18nc (" ()", "%1 (%2)", text, seq.toString ().toUpper ()); + } } return text; } //--------------------------------------------------------------------- QString kpTool::toolTip () const { return toolTipForTextAndShortcut(d->text, d->action->shortcuts()); } //--------------------------------------------------------------------- // public static QList kpTool::shortcutForKey (int key) { QList shortcut; if (key) { shortcut.append (QKeySequence (key)); // (CTRL+, ALT+, CTRL+ALT+, CTRL+SHIFT+ // all clash with global KDE shortcuts) shortcut.append (QKeySequence (static_cast(Qt::ALT) + static_cast(Qt::SHIFT) + key)); } return shortcut; } //--------------------------------------------------------------------- // public kpToolAction *kpTool::action () const { return d->action; } //--------------------------------------------------------------------- kpDocument *kpTool::document () const { return d->environ->document (); } //--------------------------------------------------------------------- kpViewManager *kpTool::viewManager () const { return d->environ->viewManager (); } //--------------------------------------------------------------------- kpToolToolBar *kpTool::toolToolBar () const { return d->environ->toolToolBar (); } //--------------------------------------------------------------------- kpColor kpTool::color (int which) const { return d->environ->color (which); } //--------------------------------------------------------------------- kpColor kpTool::foregroundColor () const { return color (0); } //--------------------------------------------------------------------- kpColor kpTool::backgroundColor () const { return color (1); } //--------------------------------------------------------------------- // TODO: Some of these might not be common enough. // Just put in kpToolEnvironment? double kpTool::colorSimilarity () const { return d->environ->colorSimilarity (); } int kpTool::processedColorSimilarity () const { return d->environ->processedColorSimilarity (); } kpColor kpTool::oldForegroundColor () const { return d->environ->oldForegroundColor (); } kpColor kpTool::oldBackgroundColor () const { return d->environ->oldBackgroundColor (); } double kpTool::oldColorSimilarity () const { return d->environ->oldColorSimilarity (); } kpCommandHistory *kpTool::commandHistory () const { return d->environ->commandHistory (); } kpToolEnvironment *kpTool::environ () const { return d->environ; } diff --git a/tools/kpToolAction.cpp b/tools/kpToolAction.cpp index ed80bdf5..de1b0d27 100644 --- a/tools/kpToolAction.cpp +++ b/tools/kpToolAction.cpp @@ -1,69 +1,71 @@ /* Copyright(c) 2003-2007 Clarence Dang Copyright(c) 2011 Martin Koller All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include "tools/kpToolAction.h" #include #include "tools/kpTool.h" #include //--------------------------------------------------------------------- kpToolAction::kpToolAction(const QString &text, const QString &pic, const QList &shortcut, const QObject *receiver, const char *slot, KActionCollection *ac, const QString &name) : KToggleAction(KDE::icon(pic), text, ac) { ac->setDefaultShortcuts(this, shortcut); - if ( receiver && slot ) + if ( receiver && slot ) { connect (this, SIGNAL(triggered(bool)), receiver, slot); + } updateToolTip(); connect (this, &kpToolAction::changed, this, &kpToolAction::updateToolTip); ac->addAction(name, this); } //--------------------------------------------------------------------- // protected void kpToolAction::updateToolTip() { const QString newToolTip = kpTool::toolTipForTextAndShortcut(text(), shortcuts()).remove(QLatin1Char('&')); - if ( newToolTip == toolTip() ) + if ( newToolTip == toolTip() ) { return; + } setToolTip(newToolTip); } //--------------------------------------------------------------------- diff --git a/tools/kpToolColorPicker.cpp b/tools/kpToolColorPicker.cpp index 691e58e8..484f9c44 100644 --- a/tools/kpToolColorPicker.cpp +++ b/tools/kpToolColorPicker.cpp @@ -1,140 +1,135 @@ /* Copyright (c) 2003-2007 Clarence Dang All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #define DEBUG_KP_TOOL_COLOR_PICKER 0 #include "kpToolColorPicker.h" #include "kpLogCategories.h" #include "widgets/toolbars/kpColorToolBar.h" #include "commands/kpCommandHistory.h" #include "kpDefs.h" #include "document/kpDocument.h" #include "pixmapfx/kpPixmapFX.h" #include "commands/tools/kpToolColorPickerCommand.h" #include "environments/tools/kpToolEnvironment.h" #include kpToolColorPicker::kpToolColorPicker (kpToolEnvironment *environ, QObject *parent) : kpTool (i18n ("Color Picker"), i18n ("Lets you select a color from the image"), Qt::Key_C, environ, parent, "tool_color_picker") { } -kpToolColorPicker::~kpToolColorPicker () -{ -} +kpToolColorPicker::~kpToolColorPicker () = default; // private kpColor kpToolColorPicker::colorAtPixel (const QPoint &p) { qCDebug(kpLogTools) << "kpToolColorPicker::colorAtPixel" << p; return kpPixmapFX::getColorAtPixel (document ()->image (), p); } // private QString kpToolColorPicker::haventBegunDrawUserMessage () const { return i18n ("Click to select a color."); } // public virtual [base kpTool] void kpToolColorPicker::begin () { setUserMessage (haventBegunDrawUserMessage ()); } // public virtual [base kpTool] void kpToolColorPicker::beginDraw () { m_oldColor = color (mouseButton ()); setUserMessage (cancelUserMessage ()); } // public virtual [base kpTool] void kpToolColorPicker::draw (const QPoint &thisPoint, const QPoint &, const QRect &) { const kpColor color = colorAtPixel (thisPoint); if (color.isValid ()) { environ ()->setColor (mouseButton (), color); setUserShapePoints (thisPoint); } else { environ ()->setColor (mouseButton (), m_oldColor); setUserShapePoints (); } } // public virtual [base kpTool] void kpToolColorPicker::cancelShape () { environ ()->setColor (mouseButton (), m_oldColor); setUserMessage (i18n ("Let go of all the mouse buttons.")); } // public virtual [base kpTool] void kpToolColorPicker::releasedAllButtons () { setUserMessage (haventBegunDrawUserMessage ()); } // public virtual [base kpTool] void kpToolColorPicker::endDraw (const QPoint &thisPoint, const QRect &) { const kpColor color = colorAtPixel (thisPoint); if (color.isValid ()) { - kpToolColorPickerCommand *cmd = - new kpToolColorPickerCommand ( - mouseButton (), - color, m_oldColor, - environ ()->commandEnvironment ()); + auto *cmd = new kpToolColorPickerCommand ( mouseButton (), color, m_oldColor, + environ ()->commandEnvironment ()); environ ()->commandHistory ()->addCommand (cmd, false/*no exec*/); setUserMessage (haventBegunDrawUserMessage ()); } else { cancelShape (); } } diff --git a/tools/kpToolZoom.cpp b/tools/kpToolZoom.cpp index 5dd0cb9f..8f1096b8 100644 --- a/tools/kpToolZoom.cpp +++ b/tools/kpToolZoom.cpp @@ -1,244 +1,248 @@ /* Copyright (c) 2003-2007 Clarence Dang All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #define DEBUG_KP_TOOL_ZOOM 0 #include "kpToolZoom.h" #include "kpDefs.h" #include "document/kpDocument.h" #include "pixmapfx/kpPixmapFX.h" #include "generic/kpSetOverrideCursorSaver.h" #include "layers/tempImage/kpTempImage.h" #include "environments/tools/kpToolEnvironment.h" #include "tools/kpToolAction.h" #include "views/manager/kpViewManager.h" #include "kpLogCategories.h" #include #include #include //--------------------------------------------------------------------- struct DrawZoomRectPackage { QRect normalizedRect; }; static void DrawZoomRect (kpImage *destImage, const QPoint &topLeft, void *userData) { - DrawZoomRectPackage *pack = static_cast (userData); + auto *pack = static_cast (userData); kpPixmapFX::drawStippleRect(destImage, topLeft.x (), topLeft.y (), pack->normalizedRect.width (), pack->normalizedRect.height (), kpColor::Yellow, kpColor::Green); } struct kpToolZoomPrivate { - bool dragHasBegun, dragCompleted; + bool dragHasBegun{}, dragCompleted{}; DrawZoomRectPackage drawPackage; }; kpToolZoom::kpToolZoom (kpToolEnvironment *environ, QWidget *parent) : kpTool (i18n ("Zoom"), i18n ("Zooms in and out of the image"), Qt::Key_Z, environ, parent, "tool_zoom"), d (new kpToolZoomPrivate ()) { // different from objectName() action()->setIcon(KDE::icon("zoom-original")); } //--------------------------------------------------------------------- kpToolZoom::~kpToolZoom () { delete d; } //--------------------------------------------------------------------- // public virtual [base kpTool] bool kpToolZoom::returnToPreviousToolAfterEndDraw () const { // If the user clicks to zoom in or out, s/he generally wants to click // some more to get the exact zoom level wanted. // // However, if they drag out a rectangle to zoom into a particular area, // they probably don't need to do any further zooming so we can return // them to their previous tool. // // Note that if they cancel a drag (cancelShape()), we do _not_ return // them to their previous tool, unlike the Color Picker. This is because // cancelling a drag generally means that the user got the top-left of // the drag wrong and wants to try a different top-left. In contrast, // with the Color Picket, if you've made a mistake while pressing the // mouse, you can just keep holding down the mouse and drag to the intended // color -- a cancel with a Color Picker really means "I've decided not // to pick another color after all", not "I got the start of the drag wrong" // because you can correct that drag. return d->dragCompleted; } // private QString kpToolZoom::haventBegunDrawUserMessage () const { return i18n ("Click to zoom in/out or left drag to zoom into a specific area."); } // public virtual [base kpTool] void kpToolZoom::begin () { viewManager ()->setCursor (Qt::CrossCursor); setUserMessage (haventBegunDrawUserMessage ()); } // public virtual [base kpTool] void kpToolZoom::end () { viewManager ()->unsetCursor (); } // public virtual [base kpTool] void kpToolZoom::globalDraw () { qCDebug(kpLogTools) << "CALL"; environ ()->fitToPage (); } // public virtual [base kpTool] void kpToolZoom::beginDraw () { d->dragHasBegun = false; d->dragCompleted = false; setUserMessage (cancelUserMessage ()); } // public virtual [base kpTool] void kpToolZoom::draw (const QPoint &thisPoint, const QPoint &, const QRect &normalizedRect) { qCDebug(kpLogTools) << "kpToomZoom::draw() currentPoint=" << currentPoint () << " lastPoint=" << lastPoint (); // TODO: Need accidental drag detection from selection tool (when dragging // out new selection) if (!d->dragHasBegun) { - if (thisPoint == startPoint ()) + if (thisPoint == startPoint ()) { return; + } // Left mouse drags select an area to zoom into. // However, it wouldn't make sense to select an area to "zoom out of" // (using the right mouse button). Therefore, make RMB drags do the // same as RMB clicks i.e. a simple zoom out, with no "area" to worry // about. - if (mouseButton () == 1/*RMB*/) + if (mouseButton () == 1/*RMB*/) { return; + } d->dragHasBegun = true; } d->drawPackage.normalizedRect = normalizedRect; kpTempImage newTempImage (false/*always display*/, normalizedRect.topLeft (), &::DrawZoomRect, &d->drawPackage, normalizedRect.width (), normalizedRect.height ()); viewManager ()->setFastUpdates (); { viewManager ()->setTempImage (newTempImage); } viewManager ()->restoreFastUpdates (); } // public virtual [base kpTool] void kpToolZoom::cancelShape () { viewManager ()->invalidateTempImage (); // LOREFACTOR: A lot of tools use this - push up to kpTool? setUserMessage (i18n ("Let go of all the mouse buttons.")); } // public virtual [base kpTool] void kpToolZoom::releasedAllButtons () { setUserMessage (haventBegunDrawUserMessage ()); } // public virtual [base kpTool] void kpToolZoom::endDraw (const QPoint &, const QRect &normalizedRect) { qCDebug(kpLogTools) << "kpToolZoom::endDraw(rect=" << normalizedRect << ")" << " dragHasBegun=" << d->dragHasBegun; // TODO: This cursor doesn't stay on for long enough because zooming uses // event loop tricks. kpSetOverrideCursorSaver cursorSaver (Qt::WaitCursor); viewManager ()->invalidateTempImage (); // Click? if (!d->dragHasBegun) { - if (mouseButton () == 0/*LMB*/) + if (mouseButton () == 0/*LMB*/) { environ ()->zoomIn (true/*center under cursor*/); - else + } + else { environ ()->zoomOut (false/*don't center under cursor - as is confusing behaviour when zooming out*/); + } } // Drag? else if (normalizedRect.isValid()) { environ ()->zoomToRect ( normalizedRect, false/*don't account for grips*/, true/*care about width*/, true/*care about height*/); d->dragCompleted = true; } } diff --git a/tools/kpTool_Drawing.cpp b/tools/kpTool_Drawing.cpp index d95085b8..6d5a5e9f 100644 --- a/tools/kpTool_Drawing.cpp +++ b/tools/kpTool_Drawing.cpp @@ -1,402 +1,407 @@ /* Copyright (c) 2003-2007 Clarence Dang All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ // // Tool methods for drawing shapes (subclasses reimplement most of these). // #define DEBUG_KP_TOOL 0 #include "tools/kpTool.h" #include "kpToolPrivate.h" #include #include "kpLogCategories.h" #include "environments/tools/kpToolEnvironment.h" #include "views/kpView.h" #include "views/manager/kpViewManager.h" #include "imagelib/kpPainter.h" #undef environ // macro on win32 //--------------------------------------------------------------------- // protected int kpTool::mouseButton () const { return d->mouseButton; } //--------------------------------------------------------------------- // protected bool kpTool::shiftPressed () const { return d->shiftPressed; } //--------------------------------------------------------------------- // protected bool kpTool::controlPressed () const { return d->controlPressed; } //--------------------------------------------------------------------- // protected bool kpTool::altPressed () const { return d->altPressed; } // protected QPoint kpTool::startPoint () const { return d->startPoint; } //--------------------------------------------------------------------- // protected QPoint kpTool::currentPoint () const { // TODO: Q_ASSERT (hasBegun()) and similar in other accessors. // We currently violate these kinds of invariants. return d->currentPoint; } //--------------------------------------------------------------------- // protected QPoint kpTool::currentViewPoint () const { return d->currentViewPoint; } //--------------------------------------------------------------------- // protected QRect kpTool::normalizedRect () const { return kpPainter::normalizedRect(d->startPoint, d->currentPoint); } //--------------------------------------------------------------------- // protected QPoint kpTool::lastPoint () const { return d->lastPoint; } //--------------------------------------------------------------------- // protected kpView *kpTool::viewUnderStartPoint () const { return d->viewUnderStartPoint; } //--------------------------------------------------------------------- // protected kpView *kpTool::viewUnderCursor () const { kpViewManager *vm = viewManager (); return vm ? vm->viewUnderCursor () : nullptr; } //--------------------------------------------------------------------- void kpTool::beginInternal () { qCDebug(kpLogTools) << "kpTool::beginInternal()"; if (!d->began) { // clear leftover statusbar messages setUserMessage (); d->currentPoint = calculateCurrentPoint (); d->currentViewPoint = calculateCurrentPoint (false/*view point*/); setUserShapePoints (d->currentPoint); // TODO: Audit all the code in this file - states like "d->began" & // "d->beganDraw" should be set before calling user func. // Also, d->currentPoint should be more frequently initialised. // call user virtual func begin (); // we've starting using the tool... d->began = true; // but we haven't started drawing with it d->beganDraw = false; uint keyState = QApplication::keyboardModifiers (); d->shiftPressed = (keyState & Qt::ShiftModifier); d->controlPressed = (keyState & Qt::ControlModifier); // TODO: Can't do much about ALT - unless it's always KApplication::Modifier1? // Ditto for everywhere else where I set SHIFT & CTRL but not alt. // COMPAT: Later: This is now supported by Qt. d->altPressed = false; } } //--------------------------------------------------------------------- void kpTool::endInternal () { if (d->began) { // before we can stop using the tool, we must stop the current drawing operation (if any) - if (hasBegunShape ()) + if (hasBegunShape ()) { endShapeInternal (d->currentPoint, normalizedRect ()); + } // call user virtual func end (); // clear leftover statusbar messages setUserMessage (); setUserShapePoints (calculateCurrentPoint ()); // we've stopped using the tool... d->began = false; // and so we can't be drawing with it d->beganDraw = false; d->environ->hideAllToolWidgets (); } } //--------------------------------------------------------------------- // virtual void kpTool::begin () { qCDebug(kpLogTools) << "kpTool::begin() base implementation"; } //--------------------------------------------------------------------- // virtual void kpTool::end () { qCDebug(kpLogTools) << "kpTool::end() base implementation"; } //--------------------------------------------------------------------- bool kpTool::hasBegun () const { return d->began; } //--------------------------------------------------------------------- bool kpTool::hasBegunDraw () const { return d->beganDraw; } //--------------------------------------------------------------------- // virtual bool kpTool::hasBegunShape () const { return hasBegunDraw (); } //--------------------------------------------------------------------- void kpTool::beginDrawInternal () { if (!d->beganDraw) { beginDraw (); d->beganDraw = true; emit beganDraw (d->currentPoint); } } //--------------------------------------------------------------------- // virtual void kpTool::beginDraw () { } //--------------------------------------------------------------------- // virtual void kpTool::hover (const QPoint &point) { qCDebug(kpLogTools) << "kpTool::hover" << point - << " base implementation" - << endl; + << " base implementation"; setUserShapePoints (point); } //--------------------------------------------------------------------- // virtual void kpTool::globalDraw () { } //--------------------------------------------------------------------- // virtual void kpTool::reselect () { qCDebug(kpLogTools) << "kpTool::reselect() base implementation"; } //--------------------------------------------------------------------- // virtual void kpTool::draw (const QPoint &, const QPoint &, const QRect &) { } //--------------------------------------------------------------------- // private void kpTool::drawInternal () { draw (d->currentPoint, d->lastPoint, normalizedRect ()); } //--------------------------------------------------------------------- // also called by kpView void kpTool::cancelShapeInternal () { if (hasBegunShape ()) { d->beganDraw = false; cancelShape (); d->viewUnderStartPoint = nullptr; emit cancelledShape (viewUnderCursor () ? d->currentPoint : KP_INVALID_POINT); - if (viewUnderCursor ()) + if (viewUnderCursor ()) { hover (d->currentPoint); + } else { d->currentPoint = KP_INVALID_POINT; d->currentViewPoint = KP_INVALID_POINT; hover (d->currentPoint); } if (returnToPreviousToolAfterEndDraw ()) { d->environ->selectPreviousTool (); } } } //--------------------------------------------------------------------- // virtual void kpTool::cancelShape () { qCWarning(kpLogTools) << "Tool cannot cancel operation!" ; } //--------------------------------------------------------------------- void kpTool::releasedAllButtons () { } //--------------------------------------------------------------------- void kpTool::endDrawInternal (const QPoint &thisPoint, const QRect &normalizedRect, bool wantEndShape) { qCDebug(kpLogTools) << "kpTool::endDrawInternal() wantEndShape=" << wantEndShape; - if (wantEndShape && !hasBegunShape ()) + if (wantEndShape && !hasBegunShape ()) { return; - else if (!wantEndShape && !hasBegunDraw ()) + } + + if (!wantEndShape && !hasBegunDraw ()) { return; + } d->beganDraw = false; if (wantEndShape) { qCDebug(kpLogTools) << "\tcalling endShape()"; endShape (thisPoint, normalizedRect); } else { qCDebug(kpLogTools) << "\tcalling endDraw()"; endDraw (thisPoint, normalizedRect); } d->viewUnderStartPoint = nullptr; emit endedDraw (d->currentPoint); - if (viewUnderCursor ()) + if (viewUnderCursor ()) { hover (d->currentPoint); + } else { d->currentPoint = KP_INVALID_POINT; d->currentViewPoint = KP_INVALID_POINT; hover (d->currentPoint); } if (returnToPreviousToolAfterEndDraw ()) { d->environ->selectPreviousTool (); } } //--------------------------------------------------------------------- // private void kpTool::endShapeInternal (const QPoint &thisPoint, const QRect &normalizedRect) { endDrawInternal (thisPoint, normalizedRect, true/*end shape*/); } //--------------------------------------------------------------------- // virtual void kpTool::endDraw (const QPoint &, const QRect &) { } //--------------------------------------------------------------------- diff --git a/tools/kpTool_KeyboardEvents.cpp b/tools/kpTool_KeyboardEvents.cpp index 982d19ba..877d0022 100644 --- a/tools/kpTool_KeyboardEvents.cpp +++ b/tools/kpTool_KeyboardEvents.cpp @@ -1,379 +1,396 @@ /* Copyright (c) 2003-2007 Clarence Dang All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ // // Tool reaction to view keyboard input. // #define DEBUG_KP_TOOL 0 // TODO: reduce number of includes #include "tools/kpTool.h" #include "kpToolPrivate.h" #include #include #include #include #include #include "kpLogCategories.h" #include #include "imagelib/kpColor.h" #include "widgets/toolbars/kpColorToolBar.h" #include "kpDefs.h" #include "pixmapfx/kpPixmapFX.h" #include "tools/kpToolAction.h" #include "environments/tools/kpToolEnvironment.h" #include "widgets/toolbars/kpToolToolBar.h" #include "views/kpView.h" #include "views/manager/kpViewManager.h" //--------------------------------------------------------------------- void kpTool::seeIfAndHandleModifierKey (QKeyEvent *e) { switch (e->key ()) { case 0: case Qt::Key_unknown: qCDebug(kpLogTools) << "kpTool::seeIfAndHandleModifierKey() picked up unknown key!"; // HACK: around Qt bug: if you hold a modifier before you start the // program and then release it over the view, // Qt reports it as the release of an unknown key // Qt4 update: I don't think this happens anymore... // --- fall thru and update all modifiers --- case Qt::Key_Alt: case Qt::Key_Shift: case Qt::Key_Control: qCDebug(kpLogTools) << "kpTool::setIfAndHandleModifierKey() accepting"; keyUpdateModifierState (e); e->accept (); break; } } //--------------------------------------------------------------------- // Returns in and the direction the arrow key "e->key()" is // pointing in or (0,0) if it's not a recognised arrow key. void kpTool::arrowKeyPressDirection (const QKeyEvent *e, int *dx, int *dy) { int dxLocal = 0, dyLocal = 0; switch (e->key ()) { case Qt::Key_Home: dxLocal = -1; dyLocal = -1; break; case Qt::Key_Up: dyLocal = -1; break; case Qt::Key_PageUp: dxLocal = +1; dyLocal = -1; break; case Qt::Key_Left: dxLocal = -1; break; case Qt::Key_Right: dxLocal = +1; break; case Qt::Key_End: dxLocal = -1; dyLocal = +1; break; case Qt::Key_Down: dyLocal = +1; break; case Qt::Key_PageDown: dxLocal = +1; dyLocal = +1; break; } - if (dx) + if (dx) { *dx = dxLocal; - if (dy) + } + if (dy) { *dy = dyLocal; + } } //--------------------------------------------------------------------- void kpTool::seeIfAndHandleArrowKeyPress (QKeyEvent *e) { int dx, dy; arrowKeyPressDirection (e, &dx, &dy); - if (dx == 0 && dy == 0) + if (dx == 0 && dy == 0) { return; + } kpView * const view = viewUnderCursor (); - if (!view) + if (!view) { return; + } const QPoint oldPoint = view->mapFromGlobal (QCursor::pos ()); qCDebug(kpLogTools) << "\toldPoint=" << oldPoint << " dx=" << dx << " dy=" << dy; const int viewIncX = (dx ? qMax (1, view->zoomLevelX () / 100) * dx : 0); const int viewIncY = (dy ? qMax (1, view->zoomLevelY () / 100) * dy : 0); int newViewX = oldPoint.x () + viewIncX; int newViewY = oldPoint.y () + viewIncY; qCDebug(kpLogTools) << "\tnewPoint=" << QPoint (newViewX, newViewY); // Make sure we really moved at least one doc point (needed due to // rounding error). if (view->transformViewToDoc (QPoint (newViewX, newViewY)) == view->transformViewToDoc (oldPoint)) { newViewX += viewIncX; newViewY += viewIncY; qCDebug(kpLogTools) << "\tneed adjust for doc - newPoint=" << QPoint (newViewX, newViewY); } // TODO: visible width/height (e.g. with scrollbars) const int x = qMin (qMax (newViewX, 0), view->width () - 1); const int y = qMin (qMax (newViewY, 0), view->height () - 1); // QCursor::setPos conveniently causes mouseMoveEvents QCursor::setPos (view->mapToGlobal (QPoint (x, y))); e->accept (); } //--------------------------------------------------------------------- bool kpTool::isDrawKey (int key) { return (key == Qt::Key_Enter || key == Qt::Key_Return || key == Qt::Key_Insert || key == Qt::Key_Clear/*Numpad 5 Key*/ || key == Qt::Key_L); } //--------------------------------------------------------------------- void kpTool::seeIfAndHandleBeginDrawKeyPress (QKeyEvent *e) { - if (e->isAutoRepeat ()) + if (e->isAutoRepeat ()) { return; + } - if (!isDrawKey (e->key ())) + if (!isDrawKey (e->key ())) { return; + } qCDebug(kpLogTools) << "kpTool::seeIfAndHandleBeginDrawKeyPress() accept"; // TODO: wrong for dragging lines outside of view (for e.g.) kpView * const view = viewUnderCursor (); - if (!view) + if (!view) { return; + } // TODO: what about the modifiers? QMouseEvent me (QEvent::MouseButtonPress, view->mapFromGlobal (QCursor::pos ()), Qt::LeftButton, Qt::LeftButton/*button state after event*/, Qt::NoModifier); mousePressEvent (&me); e->accept (); } void kpTool::seeIfAndHandleEndDrawKeyPress (QKeyEvent *e) { qCDebug(kpLogTools) << "kpTool::setIfAndHandleEndDrawKeyPress() key=" << e->key () << " isAutoRepeat=" << e->isAutoRepeat () << " isDrawKey=" << isDrawKey (e->key ()) << " view=" << viewUnderCursor (); - if (e->isAutoRepeat ()) + if (e->isAutoRepeat ()) { return; + } - if (!isDrawKey (e->key ())) + if (!isDrawKey (e->key ())) { return; + } qCDebug(kpLogTools) << "kpTool::seeIfAndHandleEndDrawKeyPress() accept"; kpView * const view = viewUnderCursor (); - if (!view) + if (!view) { return; + } // TODO: what about the modifiers? QMouseEvent me (QEvent::MouseButtonRelease, view->mapFromGlobal (QCursor::pos ()), Qt::LeftButton, Qt::NoButton/*button state after event*/, Qt::NoModifier); mouseReleaseEvent (&me); e->accept (); } //--------------------------------------------------------------------- void kpTool::keyPressEvent (QKeyEvent *e) { qCDebug(kpLogTools) << "kpTool::keyPressEvent() key=" << (int *) e->key () << " stateAfter: modifiers=" << (int *) (int) e->modifiers () - << " isAutoRep=" << e->isAutoRepeat () - << endl; + << " isAutoRep=" << e->isAutoRepeat (); e->ignore (); seeIfAndHandleModifierKey (e); - if (e->isAccepted ()) + if (e->isAccepted ()) { return; + } seeIfAndHandleArrowKeyPress (e); - if (e->isAccepted ()) + if (e->isAccepted ()) { return; + } seeIfAndHandleBeginDrawKeyPress (e); - if (e->isAccepted ()) + if (e->isAccepted ()) { return; + } switch (e->key ()) { case Qt::Key_Delete: d->environ->deleteSelection (); break; case Qt::Key_Escape: if (hasBegunDraw ()) { cancelShapeInternal (); e->accept (); } break; } } //--------------------------------------------------------------------- void kpTool::keyReleaseEvent (QKeyEvent *e) { qCDebug(kpLogTools) << "kpTool::keyReleaseEvent() key=" << (int *) e->key () << " stateAfter: modifiers=" << (int *) (int) e->modifiers () - << " isAutoRep=" << e->isAutoRepeat () - << endl; + << " isAutoRep=" << e->isAutoRepeat (); e->ignore (); seeIfAndHandleModifierKey (e); - if (e->isAccepted ()) + if (e->isAccepted ()) { return; + } seeIfAndHandleEndDrawKeyPress (e); - if (e->isAccepted ()) + if (e->isAccepted ()) { return; + } } //--------------------------------------------------------------------- // private void kpTool::keyUpdateModifierState (QKeyEvent *e) { qCDebug(kpLogTools) << "kpTool::keyUpdateModifierState() e->key=" << (int *) e->key (); qCDebug(kpLogTools) << "\tshift=" << (e->modifiers () & Qt::ShiftModifier) << " control=" << (e->modifiers () & Qt::ControlModifier) << " alt=" << (e->modifiers () & Qt::AltModifier); if (e->key () & (Qt::Key_Alt | Qt::Key_Shift | Qt::Key_Control)) { qCDebug(kpLogTools) << "\t\tmodifier changed - use e's claims"; setShiftPressed (e->modifiers () & Qt::ShiftModifier); setControlPressed (e->modifiers () & Qt::ControlModifier); setAltPressed (e->modifiers () & Qt::AltModifier); } // See seeIfAndHandleModifierKey() for why this code path exists. else { qCDebug(kpLogTools) << "\t\tmodifiers not changed - figure out the truth"; const Qt::KeyboardModifiers keyState = QApplication::keyboardModifiers (); setShiftPressed (keyState & Qt::ShiftModifier); setControlPressed (keyState & Qt::ControlModifier); setAltPressed (keyState & Qt::AltModifier); } } //--------------------------------------------------------------------- void kpTool::notifyModifierStateChanged () { if (careAboutModifierState ()) { - if (d->beganDraw) + if (d->beganDraw) { draw (d->currentPoint, d->lastPoint, normalizedRect ()); + } else { d->currentPoint = calculateCurrentPoint (); d->currentViewPoint = calculateCurrentPoint (false/*view point*/); hover (d->currentPoint); } } } //--------------------------------------------------------------------- void kpTool::setShiftPressed (bool pressed) { - if (pressed == d->shiftPressed) + if (pressed == d->shiftPressed) { return; + } d->shiftPressed = pressed; notifyModifierStateChanged (); } //--------------------------------------------------------------------- void kpTool::setControlPressed (bool pressed) { - if (pressed == d->controlPressed) + if (pressed == d->controlPressed) { return; + } d->controlPressed = pressed; notifyModifierStateChanged (); } //--------------------------------------------------------------------- void kpTool::setAltPressed (bool pressed) { - if (pressed == d->altPressed) + if (pressed == d->altPressed) { return; + } d->altPressed = pressed; notifyModifierStateChanged (); } //--------------------------------------------------------------------- diff --git a/tools/kpTool_MouseEvents.cpp b/tools/kpTool_MouseEvents.cpp index e91414c5..04cbc6d9 100644 --- a/tools/kpTool_MouseEvents.cpp +++ b/tools/kpTool_MouseEvents.cpp @@ -1,300 +1,301 @@ /* Copyright (c) 2003-2007 Clarence Dang All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ // // Tool reaction to view mouse input. // #define DEBUG_KP_TOOL 0 #include "tools/kpTool.h" #include "kpToolPrivate.h" #include "kpLogCategories.h" #include "environments/tools/kpToolEnvironment.h" #include "views/kpView.h" #include "views/manager/kpViewManager.h" #include #include #include //--------------------------------------------------------------------- // HITODO: If you press a mouse button and move it out of the view _really_ fast // and let go of the mouse button outside of the view, a mouseRelease // event will not be generated, so the tool will still be in drawing mode // (this is especially noticeable with the spraycan). // // When you move the mouse back into the view, it will still continue // continue drawing even though no mouse button is held down. // // It is somewhat hard to reproduce so the best way is to position the // mouse close to an edge of the view. If you do it right, no mouseMoveEvent // is generated at _all_, until you move it back into the view. void kpTool::mousePressEvent (QMouseEvent *e) { qCDebug(kpLogTools) << "kpTool::mousePressEvent pos=" << e->pos () << " button=" << (int) e->button () << " stateAfter: buttons=" << (int *) (int) e->buttons () << " modifiers=" << (int *) (int) e->modifiers () << " beganDraw=" << d->beganDraw; if (e->button () == Qt::MidButton) { const QString text = QApplication::clipboard ()->text (QClipboard::Selection); qCDebug(kpLogTools) << "\tMMB pasteText='" << text << "'"; if (!text.isEmpty ()) { if (hasBegunShape ()) { qCDebug(kpLogTools) << "\t\thasBegunShape - end"; endShapeInternal (d->currentPoint, normalizedRect ()); } if (viewUnderCursor ()) { d->environ->pasteTextAt (text, viewUnderCursor ()->transformViewToDoc (e->pos ()), true/*adjust topLeft so that cursor isn't on top of resize handle*/); } return; } } int mb = mouseButton (e->buttons ()); qCDebug(kpLogTools) << "\tmb=" << mb << " d->beganDraw=" << d->beganDraw; if (mb == -1 && !d->beganDraw) { // Ignore mouse press. return; } if (d->beganDraw) { if (mb == -1 || mb != d->mouseButton) { qCDebug(kpLogTools) << "\tCancelling operation as " << mb << " == -1 or != " << d->mouseButton; kpView *view = viewUnderStartPoint (); Q_ASSERT (view); // if we get a mousePressEvent when we're drawing, then the other // mouse button must have been pressed d->currentPoint = view->transformViewToDoc (e->pos ()); d->currentViewPoint = e->pos (); cancelShapeInternal (); } return; } kpView *view = viewUnderCursor (); Q_ASSERT (view); - if (view) + if (view) { qCDebug(kpLogTools) << "\tview=" << view->objectName (); + } // let user know what mouse button is being used for entire draw d->mouseButton = mouseButton (e->buttons ()); d->shiftPressed = (e->modifiers () & Qt::ShiftModifier); d->controlPressed = (e->modifiers () & Qt::ControlModifier); d->altPressed = (e->modifiers () & Qt::AltModifier); d->startPoint = d->currentPoint = view->transformViewToDoc (e->pos ()); d->currentViewPoint = e->pos (); d->viewUnderStartPoint = view; d->lastPoint = QPoint (-1, -1); qCDebug(kpLogTools) << "\tBeginning draw @ " << d->currentPoint; beginDrawInternal (); draw (d->currentPoint, d->lastPoint, QRect (d->currentPoint, d->currentPoint)); d->lastPoint = d->currentPoint; } //--------------------------------------------------------------------- // OPT: If the mouse is moving in terms of view pixels, it still might // not be moving in terms of document pixels (when zoomed in). // // So we should detect this and not call draw() or hover(). // // However, kpToolSelection needs hover() to be called on all view // point changes, not just document points, since the selection resize // handles may be smaller than document points. Also, I wonder if // selections' accidental drag detection feature cares? void kpTool::mouseMoveEvent (QMouseEvent *e) { qCDebug(kpLogTools) << "kpTool::mouseMoveEvent pos=" << e->pos () << " stateAfter: buttons=" << (int *) (int) e->buttons () << " modifiers=" << (int *) (int) e->modifiers (); kpView *v0 = viewUnderCursor (), *v1 = viewManager ()->viewUnderCursor (true/*use Qt*/), *v2 = viewUnderStartPoint (); qCDebug(kpLogTools) << "\tviewUnderCursor=" << (v0 ? v0->objectName () : "(none)") << " viewUnderCursorQt=" << (v1 ? v1->objectName () : "(none)") << " viewUnderStartPoint=" << (v2 ? v2->objectName () : "(none)"); qCDebug(kpLogTools) << "\tfocusWidget=" << qApp->focusWidget (); qCDebug(kpLogTools) << "\tbeganDraw=" << d->beganDraw; d->shiftPressed = (e->modifiers () & Qt::ShiftModifier); d->controlPressed = (e->modifiers () & Qt::ControlModifier); d->altPressed = (e->modifiers () & Qt::AltModifier); if (d->beganDraw) { kpView *view = viewUnderStartPoint (); Q_ASSERT (view); d->currentPoint = view->transformViewToDoc (e->pos ()); d->currentViewPoint = e->pos (); qCDebug(kpLogTools) << "\tDraw!"; bool dragScrolled = false; movedAndAboutToDraw (d->currentPoint, d->lastPoint, view->zoomLevelX (), &dragScrolled); if (dragScrolled) { d->currentPoint = calculateCurrentPoint (); d->currentViewPoint = calculateCurrentPoint (false/*view point*/); // Scrollview has scrolled contents and has scheduled an update // for the newly exposed region. If draw() schedules an update // as well (instead of immediately updating), the scrollview's // update will be executed first and it'll only update part of // the screen resulting in ugly tearing of the viewManager's // tempImage. viewManager ()->setFastUpdates (); } drawInternal (); - if (dragScrolled) + if (dragScrolled) { viewManager ()->restoreFastUpdates (); + } d->lastPoint = d->currentPoint; } else { kpView *view = viewUnderCursor (); if (!view) // possible if cancelShape()'ed but still holding down initial mousebtn { d->currentPoint = KP_INVALID_POINT; d->currentViewPoint = KP_INVALID_POINT; return; } d->currentPoint = view->transformViewToDoc (e->pos ()); d->currentViewPoint = e->pos (); hover (d->currentPoint); } } //--------------------------------------------------------------------- void kpTool::mouseReleaseEvent (QMouseEvent *e) { qCDebug(kpLogTools) << "kpTool::mouseReleaseEvent pos=" << e->pos () << " button=" << (int) e->button () << " stateAfter: buttons=" << (int *) (int) e->buttons () << " modifiers=" << (int *) (int) e->modifiers () - << " beganDraw=" << d->beganDraw << endl; + << " beganDraw=" << d->beganDraw; // Have _not_ already cancelShape()'ed by pressing other mouse button? // (e.g. you can cancel a line dragged out with the LMB, by pressing // the RMB) if (d->beganDraw) { kpView *view = viewUnderStartPoint (); Q_ASSERT (view); d->currentPoint = view->transformViewToDoc (e->pos ()); d->currentViewPoint = e->pos (); drawInternal (); endDrawInternal (d->currentPoint, normalizedRect ()); } if ((e->buttons () & Qt::MouseButtonMask) == 0) { releasedAllButtons (); } } //--------------------------------------------------------------------- void kpTool::wheelEvent (QWheelEvent *e) { qCDebug(kpLogTools) << "kpTool::wheelEvent() modifiers=" << (int *) (int) e->modifiers () << " hasBegunDraw=" << hasBegunDraw () - << " delta=" << e->delta () - << endl; + << " delta=" << e->delta (); e->ignore (); // If CTRL not pressed, bye. if ((e->modifiers () & Qt::ControlModifier) == 0) { qCDebug(kpLogTools) << "\tno CTRL -> bye"; return; } // If drawing, bye; don't care if a shape in progress though. if (hasBegunDraw ()) { qCDebug(kpLogTools) << "\thasBegunDraw() -> bye"; return; } // Zoom in/out depending on wheel direction. // Moved wheel away from user? if (e->delta () > 0) { qCDebug(kpLogTools) << "\tzoom in"; d->environ->zoomIn (true/*center under cursor*/); e->accept (); } // Moved wheel towards user? else if (e->delta () < 0) { qCDebug(kpLogTools) << "\tzoom out"; d->environ->zoomOut (true/*center under cursor - make zoom in/out stay under same doc pos*/); e->accept (); } } //--------------------------------------------------------------------- diff --git a/tools/kpTool_OtherEvents.cpp b/tools/kpTool_OtherEvents.cpp index 2b7f0207..f942be21 100644 --- a/tools/kpTool_OtherEvents.cpp +++ b/tools/kpTool_OtherEvents.cpp @@ -1,150 +1,152 @@ /* Copyright (c) 2003-2007 Clarence Dang All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ // // Tool reaction to all remaining events. // // 1. View events // 2. Non-view events // #include "tools/kpTool.h" #include "kpToolPrivate.h" #include "kpLogCategories.h" #include "imagelib/kpColor.h" #include //--------------------------------------------------------------------- // // 1. View Events // bool kpTool::viewEvent (QEvent *e) { qCDebug(kpLogTools) << "kpTool<" << objectName () << "," << this << ">::viewEvent(type=" << e->type () << ") returning false"; // Don't handle. return false; } //--------------------------------------------------------------------- void kpTool::focusInEvent (QFocusEvent *) { } //--------------------------------------------------------------------- void kpTool::focusOutEvent (QFocusEvent *) { qCDebug(kpLogTools) << "kpTool::focusOutEvent() beganDraw=" << d->beganDraw; - if (d->beganDraw) + if (d->beganDraw) { endDrawInternal (d->currentPoint, normalizedRect ()); + } } //--------------------------------------------------------------------- void kpTool::enterEvent (QEvent *) { qCDebug(kpLogTools) << "kpTool::enterEvent() beganDraw=" << d->beganDraw; } //--------------------------------------------------------------------- void kpTool::leaveEvent (QEvent *) { qCDebug(kpLogTools) << "kpTool::leaveEvent() beganDraw=" << d->beganDraw; // if we haven't started drawing (e.g. dragging a rectangle)... if (!d->beganDraw) { d->currentPoint = KP_INVALID_POINT; d->currentViewPoint = KP_INVALID_POINT; hover (d->currentPoint); } } //--------------------------------------------------------------------- // // 2. Non-view events // void kpTool::slotColorsSwappedInternal (const kpColor &newForegroundColor, const kpColor &newBackgroundColor) { if (careAboutColorsSwapped ()) { slotColorsSwapped (newForegroundColor, newBackgroundColor); d->ignoreColorSignals = 2; } - else + else { d->ignoreColorSignals = 0; + } } //--------------------------------------------------------------------- void kpTool::slotForegroundColorChangedInternal (const kpColor &color) { if (d->ignoreColorSignals > 0) { qCDebug(kpLogTools) << "kpTool::slotForegroundColorChangedInternal() ignoreColorSignals=" << d->ignoreColorSignals; d->ignoreColorSignals--; return; } slotForegroundColorChanged (color); } //--------------------------------------------------------------------- void kpTool::slotBackgroundColorChangedInternal (const kpColor &color) { if (d->ignoreColorSignals > 0) { qCDebug(kpLogTools) << "kpTool::slotBackgroundColorChangedInternal() ignoreColorSignals=" << d->ignoreColorSignals; d->ignoreColorSignals--; return; } slotBackgroundColorChanged (color); } //--------------------------------------------------------------------- void kpTool::slotColorSimilarityChangedInternal (double similarity, int processedSimilarity) { slotColorSimilarityChanged (similarity, processedSimilarity); } //--------------------------------------------------------------------- diff --git a/tools/kpTool_UserNotifications.cpp b/tools/kpTool_UserNotifications.cpp index d031caac..d8b4407f 100644 --- a/tools/kpTool_UserNotifications.cpp +++ b/tools/kpTool_UserNotifications.cpp @@ -1,162 +1,165 @@ /* Copyright (c) 2003-2007 Clarence Dang All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ // // Tools' statusbar updates. // #include "tools/kpTool.h" #include "kpToolPrivate.h" #include //--------------------------------------------------------------------- // public static QString kpTool::cancelUserMessage (int mouseButton) { - if (mouseButton == 0) + if (mouseButton == 0) { return i18n ("Right click to cancel."); - else - return i18n ("Left click to cancel."); + } + + return i18n ("Left click to cancel."); } //--------------------------------------------------------------------- // public QString kpTool::cancelUserMessage () const { return cancelUserMessage (d->mouseButton); } //--------------------------------------------------------------------- // public QString kpTool::userMessage () const { return d->userMessage; } //--------------------------------------------------------------------- // public void kpTool::setUserMessage (const QString &userMessage) { d->userMessage = userMessage; - if (d->userMessage.isEmpty ()) + if (d->userMessage.isEmpty ()) { d->userMessage = text (); - else + } + else { d->userMessage.prepend (i18n ("%1: ", text ())); + } emit userMessageChanged (d->userMessage); } //--------------------------------------------------------------------- // public QPoint kpTool::userShapeStartPoint () const { return d->userShapeStartPoint; } //--------------------------------------------------------------------- // public QPoint kpTool::userShapeEndPoint () const { return d->userShapeEndPoint; } //--------------------------------------------------------------------- // public void kpTool::setUserShapePoints (const QPoint &startPoint, const QPoint &endPoint, bool setSize) { d->userShapeStartPoint = startPoint; d->userShapeEndPoint = endPoint; emit userShapePointsChanged (d->userShapeStartPoint, d->userShapeEndPoint); if (setSize) { if (startPoint != KP_INVALID_POINT && endPoint != KP_INVALID_POINT) { setUserShapeSize (calculateLength (startPoint.x (), endPoint.x ()), calculateLength (startPoint.y (), endPoint.y ())); } else { setUserShapeSize (); } } } //--------------------------------------------------------------------- // public QSize kpTool::userShapeSize () const { return d->userShapeSize; } //--------------------------------------------------------------------- // public int kpTool::userShapeWidth () const { return d->userShapeSize.width (); } //--------------------------------------------------------------------- // public int kpTool::userShapeHeight () const { return d->userShapeSize.height (); } //--------------------------------------------------------------------- // public void kpTool::setUserShapeSize (const QSize &size) { d->userShapeSize = size; emit userShapeSizeChanged (d->userShapeSize); } //--------------------------------------------------------------------- // public void kpTool::setUserShapeSize (int width, int height) { setUserShapeSize (QSize (width, height)); } //--------------------------------------------------------------------- diff --git a/tools/kpTool_Utilities.cpp b/tools/kpTool_Utilities.cpp index fb545e50..6bf53a01 100644 --- a/tools/kpTool_Utilities.cpp +++ b/tools/kpTool_Utilities.cpp @@ -1,266 +1,270 @@ /* Copyright (c) 2003-2007 Clarence Dang All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ // // Tool utility methods - mainly for subclasses' convenience. // #define DEBUG_KP_TOOL 0 #include "tools/kpTool.h" #include "kpToolPrivate.h" #include #include #include "kpLogCategories.h" #include #include "commands/kpCommandSize.h" #include "kpDefs.h" #include "imagelib/kpPainter.h" #include "pixmapfx/kpPixmapFX.h" #include "views/kpView.h" //--------------------------------------------------------------------- // static QRect kpTool::neededRect (const QRect &rect, int lineWidth) { int x1, y1, x2, y2; rect.getCoords (&x1, &y1, &x2, &y2); - if (lineWidth < 1) + if (lineWidth < 1) { lineWidth = 1; + } // TODO: why not divide by 2? return QRect (QPoint (x1 - lineWidth + 1, y1 - lineWidth + 1), QPoint (x2 + lineWidth - 1, y2 + lineWidth - 1)); } //--------------------------------------------------------------------- // static QImage kpTool::neededPixmap (const QImage &image, const QRect &boundingRect) { return kpPixmapFX::getPixmapAt (image, boundingRect); } //--------------------------------------------------------------------- // public bool kpTool::hasCurrentPoint () const { return (viewUnderStartPoint () || viewUnderCursor ()); } //--------------------------------------------------------------------- // public QPoint kpTool::calculateCurrentPoint (bool zoomToDoc) const { qCDebug(kpLogTools) << "kpTool::currentPoint(zoomToDoc=" << zoomToDoc << ")"; qCDebug(kpLogTools) << "\tviewUnderStartPoint=" << (viewUnderStartPoint () ? viewUnderStartPoint ()->objectName () : "(none)") << " viewUnderCursor=" << (viewUnderCursor () ? viewUnderCursor ()->objectName () : "(none)"); kpView *v = viewUnderStartPoint (); if (!v) { v = viewUnderCursor (); if (!v) { qCDebug(kpLogTools) << "\tno view - returning sentinel"; return KP_INVALID_POINT; } } const QPoint globalPos = QCursor::pos (); const QPoint viewPos = v->mapFromGlobal (globalPos); qCDebug(kpLogTools) << "\tglobalPos=" << globalPos << " viewPos=" << viewPos; - if (!zoomToDoc) + if (!zoomToDoc) { return viewPos; + } const QPoint docPos = v->transformViewToDoc (viewPos); qCDebug(kpLogTools) << "\tdocPos=" << docPos; return docPos; } //--------------------------------------------------------------------- // public slot void kpTool::somethingBelowTheCursorChanged () { somethingBelowTheCursorChanged (calculateCurrentPoint (), calculateCurrentPoint (false/*view point*/)); } //--------------------------------------------------------------------- // private // TODO: don't dup code from mouseMoveEvent() void kpTool::somethingBelowTheCursorChanged (const QPoint ¤tPoint_, const QPoint ¤tViewPoint_) { qCDebug(kpLogTools) << "kpTool::somethingBelowTheCursorChanged(docPoint=" << currentPoint_ << " viewPoint=" << currentViewPoint_ << ")"; qCDebug(kpLogTools) << "\tviewUnderStartPoint=" << (viewUnderStartPoint () ? viewUnderStartPoint ()->objectName () : "(none)") << " viewUnderCursor=" << (viewUnderCursor () ? viewUnderCursor ()->objectName () : "(none)"); qCDebug(kpLogTools) << "\tbegan draw=" << d->beganDraw; d->currentPoint = currentPoint_; d->currentViewPoint = currentViewPoint_; if (d->beganDraw) { if (d->currentPoint != KP_INVALID_POINT) { draw (d->currentPoint, d->lastPoint, normalizedRect ()); d->lastPoint = d->currentPoint; } } else { hover (d->currentPoint); } } //--------------------------------------------------------------------- bool kpTool::currentPointNextToLast () const { - if (d->lastPoint == QPoint (-1, -1)) + if (d->lastPoint == QPoint (-1, -1)) { return true; + } int dx = qAbs (d->currentPoint.x () - d->lastPoint.x ()); int dy = qAbs (d->currentPoint.y () - d->lastPoint.y ()); return (dx <= 1 && dy <= 1); } //--------------------------------------------------------------------- bool kpTool::currentPointCardinallyNextToLast () const { - if (d->lastPoint == QPoint (-1, -1)) + if (d->lastPoint == QPoint (-1, -1)) { return true; + } return (d->currentPoint == d->lastPoint || kpPainter::pointsAreCardinallyAdjacent (d->currentPoint, d->lastPoint)); } //--------------------------------------------------------------------- // static // TODO: we don't handle Qt::XButton1 and Qt::XButton2 at the moment. int kpTool::mouseButton (Qt::MouseButtons mouseButtons) { // we have nothing to do with mid-buttons - if (mouseButtons & Qt::MidButton) + if (mouseButtons & Qt::MidButton) { return -1; + } // both left & right together is quite meaningless... const Qt::MouseButtons bothButtons = (Qt::LeftButton | Qt::RightButton); - if ((mouseButtons & bothButtons) == bothButtons) + if ((mouseButtons & bothButtons) == bothButtons) { return -1; + } - if (mouseButtons & Qt::LeftButton) + if (mouseButtons & Qt::LeftButton) { return 0; - else if (mouseButtons & Qt::RightButton) + } + if (mouseButtons & Qt::RightButton) { return 1; - else - return -1; + } + + return -1; } //--------------------------------------------------------------------- // public static int kpTool::calculateLength (int start, int end) { if (start <= end) { return end - start + 1; } - else - { - return end - start - 1; - } + + return end - start - 1; } //--------------------------------------------------------------------- // public static bool kpTool::warnIfBigImageSize (int oldWidth, int oldHeight, int newWidth, int newHeight, const QString &text, const QString &caption, const QString &continueButtonText, QWidget *parent) { // Only got smaller or unchanged - don't complain if (!(newWidth > oldWidth || newHeight > oldHeight)) { return true; } // Was already large - user was warned before, don't annoy him/her again if (kpCommandSize::PixmapSize (oldWidth, oldHeight, QPixmap::defaultDepth ()) >= KP_BIG_IMAGE_SIZE) { return true; } if (kpCommandSize::PixmapSize (newWidth, newHeight, QPixmap::defaultDepth ()) >= KP_BIG_IMAGE_SIZE) { int accept = KMessageBox::warningContinueCancel (parent, text, caption, KGuiItem (continueButtonText), KStandardGuiItem::cancel(), QLatin1String ("BigImageDontAskAgain")); return (accept == KMessageBox::Continue); } - else - { - return true; - } + + return true; } //--------------------------------------------------------------------- diff --git a/tools/polygonal/kpToolCurve.cpp b/tools/polygonal/kpToolCurve.cpp index e4c137f2..73819e83 100644 --- a/tools/polygonal/kpToolCurve.cpp +++ b/tools/polygonal/kpToolCurve.cpp @@ -1,194 +1,192 @@ /* Copyright (c) 2003-2007 Clarence Dang Copyright (c) 2017 Martin Koller All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #define DEBUG_KP_TOOL_CURVE 0 #include "kpToolCurve.h" #include "kpLogCategories.h" #include "environments/tools/kpToolEnvironment.h" #include "pixmapfx/kpPixmapFX.h" #include #include #include #include //-------------------------------------------------------------------------------- static void DrawCurveShape (kpImage *image, const QPolygon &points, const kpColor &fcolor, int penWidth, const kpColor &bcolor, bool isFinal) { (void) bcolor; (void) isFinal; Q_ASSERT (points.count () >= 2 && points.count () <= 4); const QPoint startPoint = points [0]; const QPoint endPoint = points [1]; QPoint controlPointP, controlPointQ; switch (points.count ()) { // Just a line? case 2: controlPointP = startPoint; controlPointQ = endPoint; break; // Single control point? case 3: controlPointP = controlPointQ = points [2]; break; // Two control points? case 4: controlPointP = points [2]; controlPointQ = points [3]; break; } QPainter painter(image); painter.setRenderHint(QPainter::Antialiasing, kpToolEnvironment::drawAntiAliased); painter.setPen(QPen(fcolor.toQColor(), penWidth, Qt::SolidLine, Qt::RoundCap, Qt::RoundJoin)); if ( kpPixmapFX::Only1PixelInPointArray(points) ) { painter.drawPoint(points[0]); return; } QPainterPath curvePath; curvePath.moveTo(startPoint); curvePath.cubicTo(controlPointP, controlPointQ, endPoint); painter.strokePath(curvePath, painter.pen()); } //-------------------------------------------------------------------------------- kpToolCurve::kpToolCurve (kpToolEnvironment *environ, QObject *parent) : kpToolPolygonalBase ( i18n ("Curve"), i18n ("Draws curves"), &::DrawCurveShape, Qt::Key_V, environ, parent, "tool_curve") { } -kpToolCurve::~kpToolCurve () -{ -} +kpToolCurve::~kpToolCurve () = default; // protected virtual [base kpToolPolygonalBase] QString kpToolCurve::haventBegunShapeUserMessage () const { return i18n ("Drag out the start and end points."); } // protected virtual [base kpToolPolygonalBase] bool kpToolCurve::drawingALine () const { // On the initial drag (consisting of 2 points) creates a line. // Future drags are for control points. return (points ()->count () == 2); } // public virtual [base kpTool] void kpToolCurve::endDraw (const QPoint &, const QRect &) { qCDebug(kpLogTools) << "kpToolCurve::endDraw() points=" - << points ()->toList () << endl; + << points ()->toList (); switch (points ()->count ()) { // A click of the other mouse button (to finish shape, instead of adding // another control point) would have caused endShape() to have been // called in kpToolPolygonalBase::beginDraw(). The points list would now // be empty. We are being called by kpTool::mouseReleaseEvent(). case 0: break; case 1: Q_ASSERT (!"kpToolPolygonalBase::beginDraw() ensures we have >= 2 ctrl points"); break; // Just completed initial line? case 2: if (originatingMouseButton () == 0) { setUserMessage ( i18n ("Left drag to set the first control point or right click to finish.")); } else { setUserMessage ( i18n ("Right drag to set the first control point or left click to finish.")); } break; // Have initial line and first control point? case 3: if (originatingMouseButton () == 0) { setUserMessage ( i18n ("Left drag to set the last control point or right click to finish.")); } else { setUserMessage ( i18n ("Right drag to set the last control point or left click to finish.")); } break; // Have initial line and both control points? case 4: qCDebug(kpLogTools) << "\tending shape"; endShape (); break; default: Q_ASSERT (!"Impossible number of points"); break; } } diff --git a/tools/polygonal/kpToolPolygon.cpp b/tools/polygonal/kpToolPolygon.cpp index 26e632a7..b115d7db 100644 --- a/tools/polygonal/kpToolPolygon.cpp +++ b/tools/polygonal/kpToolPolygon.cpp @@ -1,178 +1,183 @@ /* Copyright (c) 2003-2007 Clarence Dang Copyright (c) 2017 Martin Koller All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include "kpToolPolygon.h" #include "widgets/toolbars/kpToolToolBar.h" #include "environments/tools/kpToolEnvironment.h" #include "imagelib/kpColor.h" #include "pixmapfx/kpPixmapFX.h" #include #include #include #include "kpLogCategories.h" //-------------------------------------------------------------------------------- static void DrawPolygonShape (kpImage *image, const QPolygon &points, const kpColor &fcolor, int penWidth, const kpColor &bcolor, bool isFinal) { QPainter painter(image); painter.setRenderHint(QPainter::Antialiasing, kpToolEnvironment::drawAntiAliased); painter.setPen(QPen(fcolor.toQColor(), penWidth, Qt::SolidLine, Qt::RoundCap, Qt::RoundJoin)); if ( kpPixmapFX::Only1PixelInPointArray(points) ) { painter.drawPoint(points[0]); return; } - if ( bcolor.isValid() ) + if ( bcolor.isValid() ) { painter.setBrush(QBrush(bcolor.toQColor())); - else + } + else { painter.setBrush(Qt::NoBrush); + } painter.drawPolygon(points, Qt::OddEvenFill); - if ( isFinal ) + if ( isFinal ) { return; + } - if ( points.count() <= 2 ) + if ( points.count() <= 2 ) { return; + } painter.setCompositionMode(QPainter::RasterOp_SourceXorDestination); painter.setPen(QPen(Qt::white)); painter.drawLine(points[0], points[points.count() - 1]); } //-------------------------------------------------------------------------------- struct kpToolPolygonPrivate { kpToolWidgetFillStyle *toolWidgetFillStyle; }; kpToolPolygon::kpToolPolygon (kpToolEnvironment *environ, QObject *parent) : kpToolPolygonalBase ( i18n ("Polygon"), i18n ("Draws polygons"), &::DrawPolygonShape, Qt::Key_G, environ, parent, "tool_polygon"), d (new kpToolPolygonPrivate ()) { } kpToolPolygon::~kpToolPolygon () { delete d; } // private virtual [base kpToolPolygonBase] QString kpToolPolygon::haventBegunShapeUserMessage () const { return i18n ("Drag to draw the first line."); } // public virtual [base kpToolPolygonalBase] void kpToolPolygon::begin () { kpToolPolygonalBase::begin (); kpToolToolBar *tb = toolToolBar (); Q_ASSERT (tb); d->toolWidgetFillStyle = tb->toolWidgetFillStyle (); connect (d->toolWidgetFillStyle, &kpToolWidgetFillStyle::fillStyleChanged, this, &kpToolPolygon::updateShape); d->toolWidgetFillStyle->show (); } // public virtual [base kpToolPolygonalBase] void kpToolPolygon::end () { kpToolPolygonalBase::end (); disconnect (d->toolWidgetFillStyle, &kpToolWidgetFillStyle::fillStyleChanged, this, &kpToolPolygon::updateShape); d->toolWidgetFillStyle = nullptr; } // TODO: code dup with kpToolRectangle // protected virtual [base kpToolPolygonalBase] kpColor kpToolPolygon::drawingBackgroundColor () const { const kpColor foregroundColor = color (originatingMouseButton ()); const kpColor backgroundColor = color (1 - originatingMouseButton ()); return d->toolWidgetFillStyle->drawingBackgroundColor ( foregroundColor, backgroundColor); } // public virtual [base kpTool] // TODO: dup with kpToolPolyline but we don't want to create another level of // inheritance and readability. void kpToolPolygon::endDraw (const QPoint &, const QRect &) { qCDebug(kpLogTools) << "kpToolPolygon::endDraw() points=" - << points ()->toList () << endl; + << points ()->toList (); // A click of the other mouse button (to finish shape, instead of adding // another control point) would have caused endShape() to have been // called in kpToolPolygonalBase::beginDraw(). The points list would now // be empty. We are being called by kpTool::mouseReleaseEvent(). - if (points ()->count () == 0) + if (points ()->count () == 0) { return; + } if (points ()->count () >= kpToolPolygonalBase::MaxPoints) { qCDebug(kpLogTools) << "\tending shape"; endShape (); return; } if (originatingMouseButton () == 0) { setUserMessage (i18n ("Left drag another line or right click to finish.")); } else { setUserMessage (i18n ("Right drag another line or left click to finish.")); } } diff --git a/tools/polygonal/kpToolPolygonalBase.cpp b/tools/polygonal/kpToolPolygonalBase.cpp index bac9ef65..34037426 100644 --- a/tools/polygonal/kpToolPolygonalBase.cpp +++ b/tools/polygonal/kpToolPolygonalBase.cpp @@ -1,472 +1,479 @@ /* Copyright (c) 2003-2007 Clarence Dang All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #define DEBUG_KP_TOOL_POLYGON 0 #include "kpToolPolygonalBase.h" #include #include #include #include #include #include #include #include "kpLogCategories.h" #include "commands/kpCommandHistory.h" #include "document/kpDocument.h" #include "kpDefs.h" #include "imagelib/kpImage.h" #include "imagelib/kpPainter.h" #include "pixmapfx/kpPixmapFX.h" #include "layers/tempImage/kpTempImage.h" #include "environments/tools/kpToolEnvironment.h" #include "commands/tools/polygonal/kpToolPolygonalCommand.h" #include "widgets/toolbars/kpToolToolBar.h" #include "widgets/toolbars/options/kpToolWidgetLineWidth.h" #include "views/manager/kpViewManager.h" struct kpToolPolygonalBasePrivate { kpToolPolygonalBasePrivate () : drawShapeFunc(nullptr), toolWidgetLineWidth(nullptr), originatingMouseButton(-1) { } kpToolPolygonalBase::DrawShapeFunc drawShapeFunc; kpToolWidgetLineWidth *toolWidgetLineWidth; int originatingMouseButton; QPolygon points; }; //--------------------------------------------------------------------- kpToolPolygonalBase::kpToolPolygonalBase ( const QString &text, const QString &description, DrawShapeFunc drawShapeFunc, int key, kpToolEnvironment *environ, QObject *parent, const QString &name) : kpTool (text, description, key, environ, parent, name), d (new kpToolPolygonalBasePrivate ()) { d->drawShapeFunc = drawShapeFunc; d->toolWidgetLineWidth = nullptr; // (hopefully cause crash if we use it before initialising it) d->originatingMouseButton = -1; } //--------------------------------------------------------------------- kpToolPolygonalBase::~kpToolPolygonalBase () { delete d; } //--------------------------------------------------------------------- // virtual void kpToolPolygonalBase::begin () { kpToolToolBar *tb = toolToolBar (); Q_ASSERT (tb); qCDebug(kpLogTools) << "kpToolPolygonalBase::begin() tb=" << tb; d->toolWidgetLineWidth = tb->toolWidgetLineWidth (); connect (d->toolWidgetLineWidth, &kpToolWidgetLineWidth::lineWidthChanged, this, &kpToolPolygonalBase::updateShape); d->toolWidgetLineWidth->show (); viewManager ()->setCursor (QCursor (Qt::ArrowCursor)); d->originatingMouseButton = -1; setUserMessage (/*virtual*/haventBegunShapeUserMessage ()); } //--------------------------------------------------------------------- // virtual void kpToolPolygonalBase::end () { // TODO: needed? endShape (); disconnect (d->toolWidgetLineWidth, &kpToolWidgetLineWidth::lineWidthChanged, this, &kpToolPolygonalBase::updateShape); d->toolWidgetLineWidth = nullptr; viewManager ()->unsetCursor (); } void kpToolPolygonalBase::beginDraw () { qCDebug(kpLogTools) << "kpToolPolygonalBase::beginDraw() d->points=" << d->points.toList () - << ", startPoint=" << startPoint () << endl; + << ", startPoint=" << startPoint (); bool endedShape = false; // We now need to start with dragging out the initial line? if (d->points.count () == 0) { d->originatingMouseButton = mouseButton (); // The line starts and ends at the start point of the drag. // draw() will modify the last point in d->points to reflect the // mouse drag, as the drag proceeds. d->points.append (startPoint ()); d->points.append (startPoint ()); } // Already have control points - not dragging out initial line. else { // Clicking the other mouse button? if (mouseButton () != d->originatingMouseButton) { // Finish shape. TODO: I suspect we need to call endShapeInternal instead. endShape (); endedShape = true; } // Are we dragging out an extra control point? else { // Add another control point. d->points.append (startPoint ()); } } qCDebug(kpLogTools) << "\tafterwards, d->points=" << d->points.toList (); if (!endedShape) { // We've started dragging. Print instructions on how to cancel shape. setUserMessage (cancelUserMessage ()); } } // protected void kpToolPolygonalBase::applyModifiers () { const int count = d->points.count (); QPoint &lineStartPoint = d->points [count - 2]; QPoint &lineEndPoint = d->points [count - 1]; qCDebug(kpLogTools) << "kpToolPolygonalBase::applyModifiers() #pts=" << count << " line: startPt=" << lineStartPoint << " endPt=" << lineEndPoint << " modifiers: shift=" << shiftPressed () << " alt=" << altPressed () - << " ctrl=" << controlPressed () - << endl; + << " ctrl=" << controlPressed (); // angles if (shiftPressed () || controlPressed ()) { int diffx = lineEndPoint.x () - lineStartPoint.x (); int diffy = lineEndPoint.y () - lineStartPoint.y (); double ratio; - if (diffx == 0) + if (diffx == 0) { ratio = DBL_MAX; - else + } + else { ratio = fabs (double (diffy) / double (diffx)); - qCDebug(kpLogTools) << "\tdiffx=" << diffx << " diffy=" << diffy - << " ratio=" << ratio - << endl; + } + qCDebug(kpLogTools) << "\tdiffx=" << diffx << " diffy=" << diffy << " ratio=" << ratio; // Shift = 0, 45, 90 // Ctrl = 0, 30, 60, 90 // Shift + Ctrl = 0, 30, 45, 60, 90 double angles [10]; // "ought to be enough for anybody" int numAngles = 0; angles [numAngles++] = 0; - if (controlPressed ()) + if (controlPressed ()) { angles [numAngles++] = M_PI / 6; - if (shiftPressed ()) + } + if (shiftPressed ()) { angles [numAngles++] = M_PI / 4; - if (controlPressed ()) + } + if (controlPressed ()) { angles [numAngles++] = M_PI / 3; + } angles [numAngles++] = M_PI / 2; Q_ASSERT (numAngles <= int (sizeof (angles) / sizeof (angles [0]))); double angle = angles [numAngles - 1]; for (int i = 0; i < numAngles - 1; i++) { double acceptingRatio = std::tan ((angles [i] + angles [i + 1]) / 2.0); if (ratio < acceptingRatio) { angle = angles [i]; break; } } // horizontal (dist from start not maintained) if (std::fabs (qRadiansToDegrees (angle) - 0) < kpPixmapFX::AngleInDegreesEpsilon) { lineEndPoint = QPoint (lineEndPoint.x (), lineStartPoint.y ()); } // vertical (dist from start not maintained) else if (std::fabs (qRadiansToDegrees (angle) - 90) < kpPixmapFX::AngleInDegreesEpsilon) { lineEndPoint = QPoint (lineStartPoint.x (), lineEndPoint.y ()); } // diagonal (dist from start maintained) else { const double dist = std::sqrt (static_cast (diffx * diffx + diffy * diffy)); #define sgn(a) ((a)<0?-1:1) // Round distances _before_ adding to any coordinate // (ensures consistent rounding behaviour in x & y directions) const int newdx = qRound (dist * cos (angle) * sgn (diffx)); const int newdy = qRound (dist * sin (angle) * sgn (diffy)); #undef sgn lineEndPoint = QPoint (lineStartPoint.x () + newdx, lineStartPoint.y () + newdy); qCDebug(kpLogTools) << "\t\tdiagonal line: dist=" << dist << " angle=" << (angle * 180 / M_PI) - << " endPoint=" << lineEndPoint - << endl; + << " endPoint=" << lineEndPoint; } } // if (shiftPressed () || controlPressed ()) { // centring if (altPressed () && 0/*ALT is unreliable*/) { // start = start - diff // = start - (end - start) // = start - end + start // = 2 * start - end - if (count == 2) + if (count == 2) { lineStartPoint += (lineStartPoint - lineEndPoint); - else + } + else { lineEndPoint += (lineEndPoint - lineStartPoint); + } } // if (altPressed ()) { } // protected QPolygon *kpToolPolygonalBase::points () const { return &d->points; } // protected int kpToolPolygonalBase::originatingMouseButton () const { Q_ASSERT (hasBegunShape ()); return d->originatingMouseButton; } // virtual void kpToolPolygonalBase::draw (const QPoint &, const QPoint &, const QRect &) { // A click of the other mouse button (to finish shape, instead of adding // another control point) would have caused endShape() to have been // called in kpToolPolygonalBase::beginDraw(). The points list would now // be empty. We are being called by kpTool::mouseReleaseEvent(). - if (d->points.count () == 0) + if (d->points.count () == 0) { return; + } qCDebug(kpLogTools) << "kpToolPolygonalBase::draw() d->points=" << d->points.toList () - << ", endPoint=" << currentPoint () << endl; + << ", endPoint=" << currentPoint (); // Update points() so that last point reflects current mouse position. const int count = d->points.count (); d->points [count - 1] = currentPoint (); qCDebug(kpLogTools) << "\tafterwards, d->points=" << d->points.toList (); // Are we drawing a line? if (/*virtual*/drawingALine ()) { // Adjust the line (end points given by the last 2 points of points()) // in response to keyboard modifiers. applyModifiers (); // Update the preview of the shape. updateShape (); // Inform the user that we're dragging out a line with 2 control points. setUserShapePoints (d->points [count - 2], d->points [count - 1]); } // We're modifying a point. else { // Update the preview of the shape. updateShape (); // Informs the user that we're just modifying a point (perhaps, a control // point of a Bezier). setUserShapePoints (d->points [count - 1]); } } // TODO: code dup with kpToolRectangle // private kpColor kpToolPolygonalBase::drawingForegroundColor () const { return color (originatingMouseButton ()); } // protected virtual kpColor kpToolPolygonalBase::drawingBackgroundColor () const { return kpColor::Invalid; } // TODO: code dup with kpToolRectangle // protected slot void kpToolPolygonalBase::updateShape () { - if (d->points.count () == 0) + if (d->points.count () == 0) { return; + } const QRect boundingRect = kpTool::neededRect ( d->points.boundingRect (), d->toolWidgetLineWidth->lineWidth ()); qCDebug(kpLogTools) << "kpToolPolygonalBase::updateShape() boundingRect=" << boundingRect << " lineWidth=" << d->toolWidgetLineWidth->lineWidth (); kpImage image = document ()->getImageAt (boundingRect); QPolygon pointsTranslated = d->points; pointsTranslated.translate (-boundingRect.x (), -boundingRect.y ()); (*d->drawShapeFunc) (&image, pointsTranslated, drawingForegroundColor (), d->toolWidgetLineWidth->lineWidth (), /*virtual*/drawingBackgroundColor (), false/*not final*/); kpTempImage newTempImage (false/*always display*/, kpTempImage::SetImage/*render mode*/, boundingRect.topLeft (), image); viewManager ()->setFastUpdates (); { viewManager ()->setTempImage (newTempImage); } viewManager ()->restoreFastUpdates (); } // virtual void kpToolPolygonalBase::cancelShape () { viewManager ()->invalidateTempImage (); d->points.resize (0); setUserMessage (i18n ("Let go of all the mouse buttons.")); } void kpToolPolygonalBase::releasedAllButtons () { - if (!hasBegunShape ()) + if (!hasBegunShape ()) { setUserMessage (/*virtual*/haventBegunShapeUserMessage ()); + } // --- else case already handled by endDraw() --- } // public virtual [base kpTool] void kpToolPolygonalBase::endShape (const QPoint &, const QRect &) { qCDebug(kpLogTools) << "kpToolPolygonalBase::endShape() d->points=" << d->points.toList (); - if (!hasBegunShape ()) + if (!hasBegunShape ()) { return; + } viewManager ()->invalidateTempImage (); QRect boundingRect = kpTool::neededRect ( d->points.boundingRect (), d->toolWidgetLineWidth->lineWidth ()); commandHistory ()->addCommand ( new kpToolPolygonalCommand ( text (), d->drawShapeFunc, d->points, boundingRect, drawingForegroundColor (), d->toolWidgetLineWidth->lineWidth (), /*virtual*/drawingBackgroundColor (), environ ()->commandEnvironment ())); d->points.resize (0); setUserMessage (/*virtual*/haventBegunShapeUserMessage ()); } // public virtual [base kpTool] bool kpToolPolygonalBase::hasBegunShape () const { return (d->points.count () > 0); } // virtual protected slot [base kpTool] void kpToolPolygonalBase::slotForegroundColorChanged (const kpColor &) { updateShape (); } // virtual protected slot [base kpTool] void kpToolPolygonalBase::slotBackgroundColorChanged (const kpColor &) { updateShape (); } diff --git a/tools/polygonal/kpToolPolyline.cpp b/tools/polygonal/kpToolPolyline.cpp index 3feb841a..9e61cf89 100644 --- a/tools/polygonal/kpToolPolyline.cpp +++ b/tools/polygonal/kpToolPolyline.cpp @@ -1,122 +1,125 @@ /* Copyright (c) 2003-2007 Clarence Dang All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #define DEBUG_KP_TOOL_POLYLINE 0 #include "kpToolPolyline.h" #include "kpLogCategories.h" #include "environments/tools/kpToolEnvironment.h" #include "pixmapfx/kpPixmapFX.h" #include #include #include //-------------------------------------------------------------------------------- kpToolPolyline::kpToolPolyline (kpToolEnvironment *environ, QObject *parent) : kpToolPolygonalBase ( i18n ("Connected Lines"), i18n ("Draws connected lines"), &drawShape, Qt::Key_N, environ, parent, "tool_polyline") { } //-------------------------------------------------------------------------------- // private virtual [base kpToolPolygonalBase] QString kpToolPolyline::haventBegunShapeUserMessage () const { return i18n ("Drag to draw the first line."); } //-------------------------------------------------------------------------------- // public static void kpToolPolyline::drawShape(kpImage *image, const QPolygon &points, const kpColor &fcolor, int penWidth, const kpColor &bcolor, bool isFinal) { (void) bcolor; (void) isFinal; QPainter painter(image); painter.setRenderHint(QPainter::Antialiasing, kpToolEnvironment::drawAntiAliased); painter.setPen(QPen(fcolor.toQColor(), penWidth, Qt::SolidLine, Qt::RoundCap, Qt::RoundJoin)); - if ( kpPixmapFX::Only1PixelInPointArray(points) ) + if ( kpPixmapFX::Only1PixelInPointArray(points) ) { painter.drawPoint(points[0]); - else + } + else { painter.drawPolyline(points); + } } //-------------------------------------------------------------------------------- // public virtual [base kpTool] void kpToolPolyline::endDraw (const QPoint &, const QRect &) { #if DEBUG_KP_TOOL_POLYLINE qCDebug(kpLogTools) << "kpToolPolyline::endDraw() points=" - << points ()->toList () << endl; + << points ()->toList (); #endif // A click of the other mouse button (to finish shape, instead of adding // another control point) would have caused endShape() to have been // called in kpToolPolygonalBase::beginDraw(). The points list would now // be empty. We are being called by kpTool::mouseReleaseEvent(). - if (points ()->count () == 0) + if (points ()->count () == 0) { return; + } if (points ()->count () >= kpToolPolygonalBase::MaxPoints) { #if DEBUG_KP_TOOL_POLYLINE qCDebug(kpLogTools) << "\tending shape"; #endif endShape (); return; } if (originatingMouseButton () == 0) { setUserMessage (i18n ("Left drag another line or right click to finish.")); } else { setUserMessage (i18n ("Right drag another line or left click to finish.")); } } diff --git a/tools/rectangular/kpToolEllipse.cpp b/tools/rectangular/kpToolEllipse.cpp index 34a1af4a..d99e4030 100644 --- a/tools/rectangular/kpToolEllipse.cpp +++ b/tools/rectangular/kpToolEllipse.cpp @@ -1,82 +1,86 @@ /* Copyright (c) 2003-2007 Clarence Dang Copyright (c) 2017 Martin Koller All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include "kpToolEllipse.h" #include "environments/tools/kpToolEnvironment.h" #include "imagelib/kpColor.h" #include #include #include #include //--------------------------------------------------------------------- kpToolEllipse::kpToolEllipse (kpToolEnvironment *environ, QObject *parent) : kpToolRectangularBase (i18n ("Ellipse"), i18n ("Draws ellipses and circles"), &kpToolEllipse::drawEllipse, Qt::Key_E, environ, parent, "tool_ellipse") { } //--------------------------------------------------------------------- void kpToolEllipse::drawEllipse(kpImage *image, int x, int y, int width, int height, const kpColor &fcolor, int penWidth, const kpColor &bcolor) { - if ( (width == 0) || (height == 0) ) + if ( (width == 0) || (height == 0) ) { return; + } QPainter painter(image); painter.setRenderHint(QPainter::Antialiasing, kpToolEnvironment::drawAntiAliased); - if ( ((2 * penWidth) > width) || ((2 * penWidth) > height) ) + if ( ((2 * penWidth) > width) || ((2 * penWidth) > height) ) { penWidth = qMin(width, height) / 2; + } painter.setPen(QPen(fcolor.toQColor(), penWidth)); - if ( bcolor.isValid() ) + if ( bcolor.isValid() ) { painter.setBrush(QBrush(bcolor.toQColor())); - else + } + else { painter.setBrush(Qt::NoBrush); + } int offset = painter.testRenderHint(QPainter::Antialiasing) ? 1 : 0; painter.drawEllipse( x + penWidth / 2 + offset, y + penWidth / 2 + offset, qMax(1, width - penWidth - offset), qMax(1, height - penWidth - offset)); } //--------------------------------------------------------------------- diff --git a/tools/rectangular/kpToolRectangle.cpp b/tools/rectangular/kpToolRectangle.cpp index d214d993..ed179b20 100644 --- a/tools/rectangular/kpToolRectangle.cpp +++ b/tools/rectangular/kpToolRectangle.cpp @@ -1,83 +1,87 @@ /* Copyright (c) 2003-2007 Clarence Dang Copyright (c) 2017 Martin Koller All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include "kpToolRectangle.h" #include "environments/tools/kpToolEnvironment.h" #include "imagelib/kpColor.h" #include #include #include #include //--------------------------------------------------------------------- kpToolRectangle::kpToolRectangle (kpToolEnvironment *environ, QObject *parent) : kpToolRectangularBase (i18n ("Rectangle"), i18n ("Draws rectangles and squares"), &kpToolRectangle::drawRect, Qt::Key_R, environ, parent, "tool_rectangle") { } //--------------------------------------------------------------------- void kpToolRectangle::drawRect(kpImage *image, int x, int y, int width, int height, const kpColor &fcolor, int penWidth, const kpColor &bcolor) { - if ( (width == 0) || (height == 0) ) + if ( (width == 0) || (height == 0) ) { return; + } QPainter painter(image); painter.setRenderHint(QPainter::Antialiasing, kpToolEnvironment::drawAntiAliased); - if ( ((2 * penWidth) > width) || ((2 * penWidth) > height) ) + if ( ((2 * penWidth) > width) || ((2 * penWidth) > height) ) { penWidth = qMin(width, height) / 2; + } painter.setPen(QPen(fcolor.toQColor(), penWidth, Qt::SolidLine, Qt::SquareCap, Qt::MiterJoin)); - if ( bcolor.isValid() ) + if ( bcolor.isValid() ) { painter.setBrush(QBrush(bcolor.toQColor())); - else + } + else { painter.setBrush(Qt::NoBrush); + } int offset = painter.testRenderHint(QPainter::Antialiasing) ? 1 : 0; painter.drawRect( x + penWidth / 2 + offset, y + penWidth / 2 + offset, qMax(1, width - penWidth - offset), qMax(1, height - penWidth - offset)); } //--------------------------------------------------------------------- diff --git a/tools/rectangular/kpToolRectangularBase.cpp b/tools/rectangular/kpToolRectangularBase.cpp index dab80b61..8abfa85a 100644 --- a/tools/rectangular/kpToolRectangularBase.cpp +++ b/tools/rectangular/kpToolRectangularBase.cpp @@ -1,373 +1,379 @@ /* Copyright (c) 2003-2007 Clarence Dang All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #define DEBUG_KP_TOOL_RECTANGULAR_BASE 0 #include "tools/rectangular/kpToolRectangularBase.h" #include #include "kpLogCategories.h" #include #include "imagelib/kpColor.h" #include "commands/kpCommandHistory.h" #include "kpDefs.h" #include "document/kpDocument.h" #include "imagelib/kpPainter.h" #include "pixmapfx/kpPixmapFX.h" #include "layers/tempImage/kpTempImage.h" #include "environments/tools/kpToolEnvironment.h" #include "commands/tools/rectangular/kpToolRectangularCommand.h" #include "widgets/toolbars/kpToolToolBar.h" #include "widgets/toolbars/options/kpToolWidgetFillStyle.h" #include "widgets/toolbars/options/kpToolWidgetLineWidth.h" #include "views/kpView.h" #include "views/manager/kpViewManager.h" //--------------------------------------------------------------------- struct kpToolRectangularBasePrivate { - kpToolRectangularBase::DrawShapeFunc drawShapeFunc; + kpToolRectangularBase::DrawShapeFunc drawShapeFunc{}; - kpToolWidgetLineWidth *toolWidgetLineWidth; - kpToolWidgetFillStyle *toolWidgetFillStyle; + kpToolWidgetLineWidth *toolWidgetLineWidth{}; + kpToolWidgetFillStyle *toolWidgetFillStyle{}; QRect toolRectangleRect; }; //--------------------------------------------------------------------- kpToolRectangularBase::kpToolRectangularBase ( const QString &text, const QString &description, DrawShapeFunc drawShapeFunc, int key, kpToolEnvironment *environ, QObject *parent, const QString &name) : kpTool (text, description, key, environ, parent, name), d (new kpToolRectangularBasePrivate ()) { d->drawShapeFunc = drawShapeFunc; d->toolWidgetLineWidth = nullptr; d->toolWidgetFillStyle = nullptr; } //--------------------------------------------------------------------- kpToolRectangularBase::~kpToolRectangularBase () { delete d; } //--------------------------------------------------------------------- // private slot virtual void kpToolRectangularBase::slotLineWidthChanged () { - if (hasBegunDraw ()) + if (hasBegunDraw ()) { updateShape (); + } } //--------------------------------------------------------------------- // private slot virtual void kpToolRectangularBase::slotFillStyleChanged () { - if (hasBegunDraw ()) + if (hasBegunDraw ()) { updateShape (); + } } //--------------------------------------------------------------------- // private QString kpToolRectangularBase::haventBegunDrawUserMessage () const { return i18n ("Drag to draw."); } //--------------------------------------------------------------------- // virtual void kpToolRectangularBase::begin () { qCDebug(kpLogTools) << "kpToolRectangularBase::begin ()"; kpToolToolBar *tb = toolToolBar (); Q_ASSERT (tb); qCDebug(kpLogTools) << "\ttoolToolBar=" << tb; d->toolWidgetLineWidth = tb->toolWidgetLineWidth (); connect (d->toolWidgetLineWidth, &kpToolWidgetLineWidth::lineWidthChanged, this, &kpToolRectangularBase::slotLineWidthChanged); d->toolWidgetLineWidth->show (); d->toolWidgetFillStyle = tb->toolWidgetFillStyle (); connect (d->toolWidgetFillStyle, &kpToolWidgetFillStyle::fillStyleChanged, this, &kpToolRectangularBase::slotFillStyleChanged); d->toolWidgetFillStyle->show (); viewManager ()->setCursor (QCursor (Qt::ArrowCursor)); setUserMessage (haventBegunDrawUserMessage ()); } //--------------------------------------------------------------------- // virtual void kpToolRectangularBase::end () { qCDebug(kpLogTools) << "kpToolRectangularBase::end ()"; if (d->toolWidgetLineWidth) { disconnect (d->toolWidgetLineWidth, &kpToolWidgetLineWidth::lineWidthChanged, this, &kpToolRectangularBase::slotLineWidthChanged); d->toolWidgetLineWidth = nullptr; } if (d->toolWidgetFillStyle) { disconnect (d->toolWidgetFillStyle, &kpToolWidgetFillStyle::fillStyleChanged, this, &kpToolRectangularBase::slotFillStyleChanged); d->toolWidgetFillStyle = nullptr; } viewManager ()->unsetCursor (); } //--------------------------------------------------------------------- void kpToolRectangularBase::applyModifiers () { QRect rect = normalizedRect (); qCDebug(kpLogTools) << "kpToolRectangularBase::applyModifiers(" << rect << ") shift=" << shiftPressed () << " ctrl=" << controlPressed (); // user wants to startPoint () == center if (controlPressed ()) { int xdiff = qAbs (startPoint ().x () - currentPoint ().x ()); int ydiff = qAbs (startPoint ().y () - currentPoint ().y ()); rect = QRect (startPoint ().x () - xdiff, startPoint ().y () - ydiff, xdiff * 2 + 1, ydiff * 2 + 1); } // user wants major axis == minor axis: // rectangle --> square // rounded rectangle --> rounded square // ellipse --> circle if (shiftPressed ()) { if (!controlPressed ()) { if (rect.width () < rect.height ()) { - if (startPoint ().y () == rect.y ()) + if (startPoint ().y () == rect.y ()) { rect.setHeight (rect.width ()); - else + } + else { rect.setY (rect.bottom () - rect.width () + 1); + } } else { - if (startPoint ().x () == rect.x ()) + if (startPoint ().x () == rect.x ()) { rect.setWidth (rect.height ()); - else + } + else { rect.setX (rect.right () - rect.height () + 1); + } } } // have to maintain the center else { if (rect.width () < rect.height ()) { QPoint center = rect.center (); rect.setHeight (rect.width ()); rect.moveCenter (center); } else { QPoint center = rect.center (); rect.setWidth (rect.height ()); rect.moveCenter (center); } } } d->toolRectangleRect = rect; } //--------------------------------------------------------------------- void kpToolRectangularBase::beginDraw () { setUserMessage (cancelUserMessage ()); } //--------------------------------------------------------------------- // private kpColor kpToolRectangularBase::drawingForegroundColor () const { return color (mouseButton ()); } //--------------------------------------------------------------------- // private kpColor kpToolRectangularBase::drawingBackgroundColor () const { const kpColor foregroundColor = color (mouseButton ()); const kpColor backgroundColor = color (1 - mouseButton ()); return d->toolWidgetFillStyle->drawingBackgroundColor ( foregroundColor, backgroundColor); } //--------------------------------------------------------------------- // private void kpToolRectangularBase::updateShape () { kpImage image = document ()->getImageAt (d->toolRectangleRect); // Invoke shape drawing function passed in ctor. (*d->drawShapeFunc) (&image, 0, 0, d->toolRectangleRect.width (), d->toolRectangleRect.height (), drawingForegroundColor (), d->toolWidgetLineWidth->lineWidth (), drawingBackgroundColor ()); kpTempImage newTempImage (false/*always display*/, kpTempImage::SetImage/*render mode*/, d->toolRectangleRect.topLeft (), image); viewManager ()->setFastUpdates (); viewManager ()->setTempImage (newTempImage); viewManager ()->restoreFastUpdates (); } //--------------------------------------------------------------------- void kpToolRectangularBase::draw (const QPoint &, const QPoint &, const QRect &) { applyModifiers (); updateShape (); // Recover the start and end points from the transformed & normalized d->toolRectangleRect // S. or S or SC or S == C // .C C if (currentPoint ().x () >= startPoint ().x () && currentPoint ().y () >= startPoint ().y ()) { setUserShapePoints (d->toolRectangleRect.topLeft (), d->toolRectangleRect.bottomRight ()); } // .C or C // S. S else if (currentPoint ().x () >= startPoint ().x () && currentPoint ().y () < startPoint ().y ()) { setUserShapePoints (d->toolRectangleRect.bottomLeft (), d->toolRectangleRect.topRight ()); } // .S or CS // C. else if (currentPoint ().x () < startPoint ().x () && currentPoint ().y () >= startPoint ().y ()) { setUserShapePoints (d->toolRectangleRect.topRight (), d->toolRectangleRect.bottomLeft ()); } // C. // .S else { setUserShapePoints (d->toolRectangleRect.bottomRight (), d->toolRectangleRect.topLeft ()); } } //--------------------------------------------------------------------- void kpToolRectangularBase::cancelShape () { viewManager ()->invalidateTempImage (); setUserMessage (i18n ("Let go of all the mouse buttons.")); } //--------------------------------------------------------------------- void kpToolRectangularBase::releasedAllButtons () { setUserMessage (haventBegunDrawUserMessage ()); } //--------------------------------------------------------------------- void kpToolRectangularBase::endDraw (const QPoint &, const QRect &) { applyModifiers (); // TODO: flicker // Later: So why can't we use kpViewManager::setQueueUpdates()? Check SVN // log to see if this method was not available at the time of the // TODO, hence justifying the TODO. // Later2: kpToolPolygonalBase, and perhaps, other shapes will have the // same problem. viewManager ()->invalidateTempImage (); environ ()->commandHistory ()->addCommand ( new kpToolRectangularCommand ( text (), d->drawShapeFunc, d->toolRectangleRect, drawingForegroundColor (), d->toolWidgetLineWidth->lineWidth (), drawingBackgroundColor (), environ ()->commandEnvironment ())); setUserMessage (haventBegunDrawUserMessage ()); } //--------------------------------------------------------------------- diff --git a/tools/rectangular/kpToolRoundedRectangle.cpp b/tools/rectangular/kpToolRoundedRectangle.cpp index e02c3247..82ac0633 100644 --- a/tools/rectangular/kpToolRoundedRectangle.cpp +++ b/tools/rectangular/kpToolRoundedRectangle.cpp @@ -1,85 +1,89 @@ /* Copyright (c) 2003-2007 Clarence Dang Copyright (c) 2017 Martin Koller All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include "kpToolRoundedRectangle.h" #include "environments/tools/kpToolEnvironment.h" #include "imagelib/kpColor.h" #include #include #include #include //--------------------------------------------------------------------- kpToolRoundedRectangle::kpToolRoundedRectangle (kpToolEnvironment *environ, QObject *parent) : kpToolRectangularBase (i18n ("Rounded Rectangle"), i18n ("Draws rectangles and squares with rounded corners"), &kpToolRoundedRectangle::drawRoundedRect, Qt::Key_U, environ, parent, "tool_rounded_rectangle") { } //--------------------------------------------------------------------- void kpToolRoundedRectangle::drawRoundedRect(kpImage *image, int x, int y, int width, int height, const kpColor &fcolor, int penWidth, const kpColor &bcolor) { - if ( (width == 0) || (height == 0) ) + if ( (width == 0) || (height == 0) ) { return; + } QPainter painter(image); painter.setRenderHint(QPainter::Antialiasing, kpToolEnvironment::drawAntiAliased); - if ( ((2 * penWidth) > width) || ((2 * penWidth) > height) ) + if ( ((2 * penWidth) > width) || ((2 * penWidth) > height) ) { penWidth = qMin(width, height) / 2; + } painter.setPen(QPen(fcolor.toQColor(), penWidth, Qt::SolidLine, Qt::SquareCap, Qt::MiterJoin)); - if ( bcolor.isValid() ) + if ( bcolor.isValid() ) { painter.setBrush(QBrush(bcolor.toQColor())); - else + } + else { painter.setBrush(Qt::NoBrush); + } int offset = painter.testRenderHint(QPainter::Antialiasing) ? 1 : 0; int radius = qMin(width, height) / 4; painter.drawRoundedRect( x + penWidth / 2 + offset, y + penWidth / 2 + offset, qMax(1, width - penWidth - offset), qMax(1, height - penWidth - offset), radius, radius); } //--------------------------------------------------------------------- diff --git a/tools/selection/image/kpAbstractImageSelectionTool.cpp b/tools/selection/image/kpAbstractImageSelectionTool.cpp index 8847e88e..e36192a5 100644 --- a/tools/selection/image/kpAbstractImageSelectionTool.cpp +++ b/tools/selection/image/kpAbstractImageSelectionTool.cpp @@ -1,102 +1,103 @@ /* Copyright (c) 2003-2007 Clarence Dang All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include "kpAbstractImageSelectionTool.h" #include #include "layers/selections/image/kpAbstractImageSelection.h" #include "document/kpDocument.h" #include "environments/tools/selection/kpToolSelectionEnvironment.h" #include "commands/tools/selection/kpToolSelectionPullFromDocumentCommand.h" //--------------------------------------------------------------------- kpAbstractImageSelectionTool::kpAbstractImageSelectionTool ( const QString &text, const QString &description, int key, kpToolSelectionEnvironment *environ, QObject *parent, const QString &name) : kpAbstractSelectionTool (text, description, key, environ, parent, name) { } //--------------------------------------------------------------------- // protected virtual [kpAbstractSelectionTool] kpAbstractSelectionContentCommand *kpAbstractImageSelectionTool::newGiveContentCommand () const { kpAbstractImageSelection *imageSel = document ()->imageSelection (); Q_ASSERT (imageSel && !imageSel->hasContent ()); - if (imageSel->transparency ().isTransparent ()) + if (imageSel->transparency ().isTransparent ()) { environ ()->flashColorSimilarityToolBarItem (); + } return new kpToolSelectionPullFromDocumentCommand ( *imageSel, environ ()->backgroundColor (), QString()/*uninteresting child of macro cmd*/, environ ()->commandEnvironment ()); } //--------------------------------------------------------------------- // protected virtual [kpAbstractSelectionTool] QString kpAbstractImageSelectionTool::nameOfCreateCommand () const { return i18n ("Selection: Create"); } //--------------------------------------------------------------------- // protected virtual [kpAbstractSelectionTool] QString kpAbstractImageSelectionTool::haventBegunDrawUserMessageCreate () const { // TODO: This is wrong because you can still use RMB. return i18n ("Left drag to create selection."); } //--------------------------------------------------------------------- // protected virtual [kpAbstractSelectionTool] QString kpAbstractImageSelectionTool::haventBegunDrawUserMessageMove () const { return i18n ("Left drag to move selection."); } //--------------------------------------------------------------------- // protected virtual [kpAbstractSelectionTool] QString kpAbstractImageSelectionTool::haventBegunDrawUserMessageResizeScale () const { return i18n ("Left drag to scale selection."); } //--------------------------------------------------------------------- diff --git a/tools/selection/image/kpAbstractImageSelectionTool_Transparency.cpp b/tools/selection/image/kpAbstractImageSelectionTool_Transparency.cpp index 05ec1c84..850f848e 100644 --- a/tools/selection/image/kpAbstractImageSelectionTool_Transparency.cpp +++ b/tools/selection/image/kpAbstractImageSelectionTool_Transparency.cpp @@ -1,201 +1,207 @@ /* Copyright (c) 2003-2007 Clarence Dang All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #define DEBUG_KP_TOOL_SELECTION 0 #include "kpAbstractImageSelectionTool.h" #include "layers/selections/image/kpAbstractImageSelection.h" #include "layers/selections/kpAbstractSelection.h" #include "commands/kpCommandHistory.h" #include "kpDefs.h" #include "document/kpDocument.h" #include "commands/kpMacroCommand.h" #include "generic/kpSetOverrideCursorSaver.h" #include "layers/selections/text/kpTextSelection.h" #include "commands/tools/selection/kpToolSelectionCreateCommand.h" #include "commands/tools/selection/kpToolSelectionDestroyCommand.h" #include "environments/tools/selection/kpToolSelectionEnvironment.h" #include "commands/tools/selection/kpToolSelectionMoveCommand.h" #include "commands/tools/selection/kpToolSelectionResizeScaleCommand.h" #include "commands/tools/selection/kpToolImageSelectionTransparencyCommand.h" #include "commands/tools/selection/text/kpToolTextGiveContentCommand.h" #include "widgets/toolbars/kpToolToolBar.h" #include "widgets/toolbars/options/kpToolWidgetOpaqueOrTransparent.h" #include "views/kpView.h" #include "views/manager/kpViewManager.h" #include "kpLogCategories.h" #include // protected bool kpAbstractImageSelectionTool::shouldChangeImageSelectionTransparency () const { if (environ ()->settingImageSelectionTransparency ()) { #if DEBUG_KP_TOOL_SELECTION qCDebug(kpLogTools) << "\trecursion - abort setting selection transparency: " - << environ ()->settingImageSelectionTransparency () << endl; + << environ ()->settingImageSelectionTransparency (); #endif return false; } - if (!document ()->imageSelection ()) + if (!document ()->imageSelection ()) { return false; + } // TODO: Can probably return false if the selection transparency mode // is Opaque, since neither background color nor color similarity // would matter. return true; } // protected void kpAbstractImageSelectionTool::changeImageSelectionTransparency ( const QString &name, const kpImageSelectionTransparency &newTrans, const kpImageSelectionTransparency &oldTrans) { #if DEBUG_KP_TOOL_SELECTION qCDebug(kpLogTools) << "CALL(" << name << ")"; #endif kpSetOverrideCursorSaver cursorSaver (Qt::WaitCursor); - if (hasBegunShape ()) + if (hasBegunShape ()) { endShapeInternal (); + } kpAbstractImageSelection *imageSel = document ()->imageSelection (); - if (imageSel->hasContent () && newTrans.isTransparent ()) + if (imageSel->hasContent () && newTrans.isTransparent ()) { environ ()->flashColorSimilarityToolBarItem (); + } imageSel->setTransparency (newTrans); // We _must_ add the command even if kpAbstractImageSelection::setTransparency() // above did not change the selection transparency mask at all. // Consider the following case: // // 0. Ensure that selection transparency is opaque and any // color other than red is the background color. Ensure that // the color similarity setting is 0. // // 1. Select a solid red rectangle and pull it off. // // 2. Switch to transparent and set red as the background color. // [the selection is now invisible as red is the background // color, which is the same as the contents of the selection] // // 3. Invert Colors. // [the selection is now cyan, red is still the background color] // // 4. Change the background color to green. // [the selection transparency mask does not change so the // selection is still cyan; green is the background color] // // 5. Undo // // If no transparency command were added for Step 4., the Undo // in Step 5. would take us straight to the state after Step 2., // where we would expect the red selection to be invisible. However, // as the background color was changed to green in Step 4. and was not // undone, the red selection is not invisible when it should be -- Undo // has moved us to an incorrect state. // // KDE3: Copy this comment into the KDE 3 branch. commandHistory ()->addCommand (new kpToolImageSelectionTransparencyCommand ( name, newTrans, oldTrans, environ ()->commandEnvironment ()), false/*no exec*/); } // protected slot virtual [kpAbstractSelectionTool] void kpAbstractImageSelectionTool::slotIsOpaqueChanged (bool /*isOpaque*/) { #if DEBUG_KP_TOOL_SELECTION qCDebug(kpLogTools) << "kpAbstractImageSelectionTool::slotIsOpaqueChanged()"; #endif - if (!shouldChangeImageSelectionTransparency ()) + if (!shouldChangeImageSelectionTransparency ()) { return; + } kpImageSelectionTransparency st = environ ()->imageSelectionTransparency (); kpImageSelectionTransparency oldST = st; oldST.setOpaque (!oldST.isOpaque ()); changeImageSelectionTransparency ( st.isOpaque () ? i18n ("Selection: Opaque") : i18n ("Selection: Transparent"), st, oldST); } // protected slot virtual [base kpTool] void kpAbstractImageSelectionTool::slotBackgroundColorChanged (const kpColor &) { #if DEBUG_KP_TOOL_SELECTION qCDebug(kpLogTools) << "kpAbstractImageSelectionTool::slotBackgroundColorChanged()"; #endif - if (!shouldChangeImageSelectionTransparency ()) + if (!shouldChangeImageSelectionTransparency ()) { return; + } kpImageSelectionTransparency st = environ ()->imageSelectionTransparency (); kpImageSelectionTransparency oldST = st; oldST.setTransparentColor (oldBackgroundColor ()); changeImageSelectionTransparency ( i18n ("Selection: Transparency Color"), st, oldST); } // protected slot virtual [base kpTool] void kpAbstractImageSelectionTool::slotColorSimilarityChanged (double, int) { #if DEBUG_KP_TOOL_SELECTION qCDebug(kpLogTools) << "kpAbstractImageSelectionTool::slotColorSimilarityChanged()"; #endif - if (!shouldChangeImageSelectionTransparency ()) + if (!shouldChangeImageSelectionTransparency ()) { return; + } kpImageSelectionTransparency st = environ ()->imageSelectionTransparency (); kpImageSelectionTransparency oldST = st; oldST.setColorSimilarity (oldColorSimilarity ()); changeImageSelectionTransparency ( i18n ("Selection: Transparency Color Similarity"), st, oldST); } diff --git a/tools/selection/image/kpToolEllipticalSelection.cpp b/tools/selection/image/kpToolEllipticalSelection.cpp index 1f782d8f..0ae0d30c 100644 --- a/tools/selection/image/kpToolEllipticalSelection.cpp +++ b/tools/selection/image/kpToolEllipticalSelection.cpp @@ -1,81 +1,79 @@ /* Copyright (c) 2003-2007 Clarence Dang All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #define DEBUG_KP_TOOL_ELLIPTICAL_SELECTION 0 #include "kpToolEllipticalSelection.h" #include "kpLogCategories.h" #include "document/kpDocument.h" #include "layers/selections/image/kpEllipticalImageSelection.h" #include "environments/tools/selection/kpToolSelectionEnvironment.h" #include kpToolEllipticalSelection::kpToolEllipticalSelection (kpToolSelectionEnvironment *environ, QObject *parent) : kpAbstractImageSelectionTool (i18n ("Selection (Elliptical)"), i18n ("Makes an elliptical or circular selection"), Qt::Key_I, environ, parent, "tool_elliptical_selection") { } -kpToolEllipticalSelection::~kpToolEllipticalSelection () -{ -} +kpToolEllipticalSelection::~kpToolEllipticalSelection () = default; // protected virtual [base kpAbstractSelectionTool] bool kpToolEllipticalSelection::drawCreateMoreSelectionAndUpdateStatusBar ( bool dragAccepted, const QPoint &accidentalDragAdjustedPoint, const QRect &normalizedRect) { // Prevent unintentional creation of 1-pixel selections. if (!dragAccepted && accidentalDragAdjustedPoint == startPoint ()) { #if DEBUG_KP_TOOL_ELLIPTICAL_SELECTION && 1 qCDebug(kpLogTools) << "\tnon-text NOP - return"; #endif setUserShapePoints (accidentalDragAdjustedPoint); return false; } Q_ASSERT (accidentalDragAdjustedPoint == currentPoint ()); document ()->setSelection ( kpEllipticalImageSelection ( normalizedRect, environ ()->imageSelectionTransparency ())); setUserShapePoints (startPoint (), currentPoint ()); return true; } diff --git a/tools/selection/image/kpToolFreeFormSelection.cpp b/tools/selection/image/kpToolFreeFormSelection.cpp index 9381649e..c2886115 100644 --- a/tools/selection/image/kpToolFreeFormSelection.cpp +++ b/tools/selection/image/kpToolFreeFormSelection.cpp @@ -1,141 +1,139 @@ /* Copyright (c) 2003-2007 Clarence Dang All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #define DEBUG_KP_TOOL_FREE_FROM_SELECTION 0 #include "kpToolFreeFormSelection.h" #include "kpLogCategories.h" #include #include "document/kpDocument.h" #include "layers/selections/image/kpFreeFormImageSelection.h" #include "environments/tools/selection/kpToolSelectionEnvironment.h" //--------------------------------------------------------------------- kpToolFreeFormSelection::kpToolFreeFormSelection (kpToolSelectionEnvironment *environ, QObject *parent) : kpAbstractImageSelectionTool (i18n ("Selection (Free-Form)"), i18n ("Makes a free-form selection"), Qt::Key_M, environ, parent, "tool_free_form_selection") { } //--------------------------------------------------------------------- -kpToolFreeFormSelection::~kpToolFreeFormSelection () -{ -} +kpToolFreeFormSelection::~kpToolFreeFormSelection () = default; //--------------------------------------------------------------------- // protected virtual [base kpAbstractSelectionTool] bool kpToolFreeFormSelection::drawCreateMoreSelectionAndUpdateStatusBar ( bool dragAccepted, const QPoint &accidentalDragAdjustedPoint, const QRect &/*normalizedRect*/) { #if DEBUG_KP_TOOL_FREE_FROM_SELECTION qCDebug(kpLogTools) << "kpToolFreeFormSelection::createMoreSelectionAndUpdateStatusBar(" << "dragAccepted=" << dragAccepted << ",accidentalDragAdjustedPoint=" << accidentalDragAdjustedPoint - << ")" << endl; + << ")"; #endif // Prevent unintentional creation of 1-pixel selections. if (!dragAccepted && accidentalDragAdjustedPoint == startPoint ()) { #if DEBUG_KP_TOOL_FREE_FROM_SELECTION && 1 qCDebug(kpLogTools) << "\tnon-text NOP - return"; #endif setUserShapePoints (accidentalDragAdjustedPoint); return false; } Q_ASSERT (accidentalDragAdjustedPoint == currentPoint ()); Q_ASSERT (dragAccepted == static_cast (document ()->selection ())); const kpFreeFormImageSelection *oldPointsSel = nullptr; if (document ()->selection ()) { kpAbstractSelection *sel = document ()->selection (); Q_ASSERT (dynamic_cast (sel)); oldPointsSel = dynamic_cast (sel); } QPolygon points; // First point in drag? if (!dragAccepted) { points.append (startPoint ()); } // Not first point in drag. else { - if ( !oldPointsSel ) // assert above says we never reach this, but let's make coverity happy - return false; + if ( !oldPointsSel ) { // assert above says we never reach this, but let's make coverity happy + return false; + } // Get existing points in selection. points = oldPointsSel->cardinallyAdjacentPoints (); } #if DEBUG_KP_TOOL_FREE_FROM_SELECTION qCDebug(kpLogTools) << "\tlast old point=" << points.last (); #endif // TODO: There should be an upper limit on this before drawing the // polygon becomes too slow. points.append (accidentalDragAdjustedPoint); document ()->setSelection ( kpFreeFormImageSelection (points, environ ()->imageSelectionTransparency ())); // Prevent accidental usage of dangling pointer to old selection // (deleted by kpDocument::setSelection()). oldPointsSel = nullptr; #if DEBUG_KP_TOOL_FREE_FROM_SELECTION && 1 qCDebug(kpLogTools) << "\t\tfreeform; #points=" - << document ()->selection ()->calculatePoints ().count () - << endl; + << document ()->selection ()->calculatePoints ().count (); #endif setUserShapePoints (accidentalDragAdjustedPoint); return true; } //--------------------------------------------------------------------- diff --git a/tools/selection/image/kpToolRectSelection.cpp b/tools/selection/image/kpToolRectSelection.cpp index c0103b62..4ebdba99 100644 --- a/tools/selection/image/kpToolRectSelection.cpp +++ b/tools/selection/image/kpToolRectSelection.cpp @@ -1,83 +1,81 @@ /* Copyright (c) 2003-2007 Clarence Dang All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #define DEBUG_KP_TOOL_RECT_SELECTION 0 #include "kpToolRectSelection.h" #include "kpLogCategories.h" #include "document/kpDocument.h" #include "layers/selections/image/kpRectangularImageSelection.h" #include "environments/tools/selection/kpToolSelectionEnvironment.h" #include kpToolRectSelection::kpToolRectSelection (kpToolSelectionEnvironment *environ, QObject *parent) : kpAbstractImageSelectionTool (i18n ("Selection (Rectangular)"), i18n ("Makes a rectangular selection"), Qt::Key_S, environ, parent, "tool_rect_selection") { } -kpToolRectSelection::~kpToolRectSelection () -{ -} +kpToolRectSelection::~kpToolRectSelection () = default; // protected virtual [base kpAbstractSelectionTool] bool kpToolRectSelection::drawCreateMoreSelectionAndUpdateStatusBar ( bool dragAccepted, const QPoint &accidentalDragAdjustedPoint, const QRect &normalizedRect) { // Prevent unintentional creation of 1-pixel selections. // REFACTOR: This line is duplicated code with other tools. if (!dragAccepted && accidentalDragAdjustedPoint == startPoint ()) { #if DEBUG_KP_TOOL_RECT_SELECTION && 1 qCDebug(kpLogTools) << "\tnon-text NOP - return"; #endif setUserShapePoints (accidentalDragAdjustedPoint); return false; } Q_ASSERT (accidentalDragAdjustedPoint == currentPoint ()); const QRect usefulRect = normalizedRect.intersected (document ()->rect ()); document ()->setSelection ( kpRectangularImageSelection ( usefulRect, environ ()->imageSelectionTransparency ())); setUserShapePoints (startPoint (), QPoint (qMax (0, qMin (currentPoint ().x (), document ()->width () - 1)), qMax (0, qMin (currentPoint ().y (), document ()->height () - 1)))); return true; } diff --git a/tools/selection/kpAbstractSelectionTool.cpp b/tools/selection/kpAbstractSelectionTool.cpp index 7b667c4a..be048a83 100644 --- a/tools/selection/kpAbstractSelectionTool.cpp +++ b/tools/selection/kpAbstractSelectionTool.cpp @@ -1,632 +1,641 @@ /* Copyright (c) 2003-2007 Clarence Dang All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #define DEBUG_KP_TOOL_SELECTION 0 #include "kpAbstractSelectionTool.h" #include "kpAbstractSelectionToolPrivate.h" #include #include #include #include "kpLogCategories.h" #include "layers/selections/kpAbstractSelection.h" #include "commands/tools/selection/kpAbstractSelectionContentCommand.h" #include "commands/kpCommandHistory.h" #include "kpDefs.h" #include "document/kpDocument.h" #include "commands/kpMacroCommand.h" #include "commands/tools/selection/kpToolSelectionCreateCommand.h" #include "environments/tools/selection/kpToolSelectionEnvironment.h" #include "widgets/toolbars/kpToolToolBar.h" #include "widgets/toolbars/options/kpToolWidgetOpaqueOrTransparent.h" #include "views/kpView.h" #include "views/manager/kpViewManager.h" #include "imagelib/kpPainter.h" #include //--------------------------------------------------------------------- // For either of these timers, they are only active during the "drawing" phase // of kpTool. static void AssertAllTimersInactive (struct kpAbstractSelectionToolPrivate *d) { Q_ASSERT (!d->createNOPTimer->isActive ()); Q_ASSERT (!d->RMBMoveUpdateGUITimer->isActive ()); } //--------------------------------------------------------------------- kpAbstractSelectionTool::kpAbstractSelectionTool ( const QString &text, const QString &description, int key, kpToolSelectionEnvironment *environ, QObject *parent, const QString &name) : kpTool (text, description, key, environ, parent, name), d (new kpAbstractSelectionToolPrivate ()) { d->drawType = None; d->currentSelContentCommand = nullptr; // d->dragAccepted // d->hadSelectionBeforeDrag // d->cancelledShapeButStillHoldingButtons d->toolWidgetOpaqueOrTransparent = nullptr; initCreate (); initMove (); initResizeScale (); // It would be bad practice to have timers ticking even when this tool // is not in use. ::AssertAllTimersInactive (d); } //--------------------------------------------------------------------- kpAbstractSelectionTool::~kpAbstractSelectionTool () { uninitCreate (); uninitMove (); uninitResizeScale (); // (state must be after construction, or after some time after end()) Q_ASSERT (d->drawType == None); Q_ASSERT (!d->currentSelContentCommand); // d->dragAccepted // d->hadSelectionBeforeDraw // d->cancelledShapeButStillHoldingButtons // d->toolWidgetOpaqueOrTransparent delete d; } //--------------------------------------------------------------------- // protected kpAbstractSelectionTool::DrawType kpAbstractSelectionTool::drawType () const { return d->drawType; } //--------------------------------------------------------------------- // protected bool kpAbstractSelectionTool::hadSelectionBeforeDraw () const { return d->hadSelectionBeforeDraw; } //--------------------------------------------------------------------- // protected overrides [base kpTool] kpToolSelectionEnvironment *kpAbstractSelectionTool::environ () const { kpToolEnvironment *e = kpTool::environ (); Q_ASSERT (dynamic_cast (e)); - return static_cast (e); + return dynamic_cast (e); } //--------------------------------------------------------------------- // protected bool kpAbstractSelectionTool::controlOrShiftPressed () const { return (controlPressed () || shiftPressed ()); } //--------------------------------------------------------------------- // protected void kpAbstractSelectionTool::pushOntoDocument () { #if DEBUG_KP_TOOL_SELECTION && 1 qCDebug(kpLogTools) << "kpAbstractSelectionTool::pushOntoDocument() selection=" - << document ()->selection () << endl; + << document ()->selection (); #endif Q_ASSERT (document ()->selection ()); environ ()->deselectSelection (); } //--------------------------------------------------------------------- // protected void kpAbstractSelectionTool::giveContentIfNeeded () { kpAbstractSelection *sel = document ()->selection (); Q_ASSERT (sel); - if (sel->hasContent ()) + if (sel->hasContent ()) { return; + } - if (d->currentSelContentCommand) + if (d->currentSelContentCommand) { return; + } d->currentSelContentCommand = /*virtual*/newGiveContentCommand (); d->currentSelContentCommand->execute (); } //--------------------------------------------------------------------- // protected // REFACTOR: sync: Code dup with kpMainWindow::addImageOrSelectionCommand (). void kpAbstractSelectionTool::addNeedingContentCommand (kpCommand *cmd) { Q_ASSERT (cmd); // Did we fill the selection with content? if (d->currentSelContentCommand) { // Make the border creation a command. #if DEBUG_KP_TOOL_SELECTION qCDebug(kpLogTools) << "\thave currentSelContentCommand"; #endif commandHistory ()->addCreateSelectionCommand ( new kpToolSelectionCreateCommand ( /*virtual*/nameOfCreateCommand (), *d->currentSelContentCommand->originalSelection (), environ ()->commandEnvironment ()), false/*no exec - user already dragged out sel*/); } // Do we have a content setting command we need to commit? // (yes, this is the same check as the previous "if") if (d->currentSelContentCommand) { // Put the content command + given command (e.g. movement) together // as a macro command, in the command history. kpMacroCommand *macroCmd = new kpMacroCommand ( cmd->name (), environ ()->commandEnvironment ()); macroCmd->addCommand (d->currentSelContentCommand); d->currentSelContentCommand = nullptr; macroCmd->addCommand (cmd); commandHistory ()->addCommand (macroCmd, false/*no exec*/); } else { // Put the given command into the command history. commandHistory ()->addCommand (cmd, false/*no exec*/); } } //--------------------------------------------------------------------- // protected virtual void kpAbstractSelectionTool::setSelectionBorderForHaventBegunDraw () { viewManager ()->setQueueUpdates (); { viewManager ()->setSelectionBorderVisible (true); viewManager ()->setSelectionBorderFinished (true); } viewManager ()->restoreQueueUpdates (); } //--------------------------------------------------------------------- // private QString kpAbstractSelectionTool::haventBegunDrawUserMessage () { #if DEBUG_KP_TOOL_SELECTION && 0 qCDebug(kpLogTools) << "kpAbstractSelectionTool::haventBegunDrawUserMessage()" " cancelledShapeButStillHoldingButtons=" - << d->cancelledShapeButStillHoldingButtons - << endl; + << d->cancelledShapeButStillHoldingButtons; #endif - if (d->cancelledShapeButStillHoldingButtons) + if (d->cancelledShapeButStillHoldingButtons) { return i18n ("Let go of all the mouse buttons."); + } return operation (calculateDrawType (), HaventBegunDrawUserMessage).toString (); } //--------------------------------------------------------------------- // public virtual [base kpTool] void kpAbstractSelectionTool::begin () { #if DEBUG_KP_TOOL_SELECTION qCDebug(kpLogTools) << "kpAbstractSelectionTool<" << objectName () << ">::begin()"; #endif ::AssertAllTimersInactive (d); // (state must be after construction, or after some time after end()) Q_ASSERT (d->drawType == None); Q_ASSERT (!d->currentSelContentCommand); d->dragAccepted = false; // d->hadSelectionBeforeDraw d->cancelledShapeButStillHoldingButtons = false; kpToolToolBar *tb = toolToolBar (); Q_ASSERT (tb); d->toolWidgetOpaqueOrTransparent = tb->toolWidgetOpaqueOrTransparent (); Q_ASSERT (d->toolWidgetOpaqueOrTransparent); connect (d->toolWidgetOpaqueOrTransparent, &kpToolWidgetOpaqueOrTransparent::isOpaqueChanged, this, &kpAbstractSelectionTool::slotIsOpaqueChanged); d->toolWidgetOpaqueOrTransparent->show (); /*virtual*/setSelectionBorderForHaventBegunDraw (); beginCreate (); beginMove (); beginResizeScale (); setUserMessage (haventBegunDrawUserMessage ()); } //--------------------------------------------------------------------- // public virtual [base kpTool] void kpAbstractSelectionTool::end () { #if DEBUG_KP_TOOL_SELECTION qCDebug(kpLogTools) << "kpAbstractSelectionTool<" << objectName () << ">::end()"; #endif - if (document ()->selection ()) + if (document ()->selection ()) { pushOntoDocument (); + } endCreate (); endMove (); endResizeScale (); // (should have been killed by cancelShape() or endDraw()) Q_ASSERT (d->drawType == None); Q_ASSERT (!d->currentSelContentCommand); // d->dragAccepted // d->hadSelectionBeforeDraw // d->cancelledShapeButStillHoldingButtons Q_ASSERT (d->toolWidgetOpaqueOrTransparent); disconnect (d->toolWidgetOpaqueOrTransparent, &kpToolWidgetOpaqueOrTransparent::isOpaqueChanged, this, &kpAbstractSelectionTool::slotIsOpaqueChanged); d->toolWidgetOpaqueOrTransparent = nullptr; viewManager ()->unsetCursor (); ::AssertAllTimersInactive (d); } //--------------------------------------------------------------------- // public virtual [base kpTool] void kpAbstractSelectionTool::reselect () { #if DEBUG_KP_TOOL_SELECTION qCDebug(kpLogTools) << "kpAbstractSelectionTool::reselect()"; #endif - if (document ()->selection ()) + if (document ()->selection ()) { pushOntoDocument (); + } } //--------------------------------------------------------------------- // protected virtual kpAbstractSelectionTool::DrawType kpAbstractSelectionTool::calculateDrawTypeInsideSelection () const { #if DEBUG_KP_TOOL_SELECTION qCDebug(kpLogTools) << "\t\tis move"; #endif return kpAbstractSelectionTool::Move; } //--------------------------------------------------------------------- // protected virtual kpAbstractSelectionTool::DrawType kpAbstractSelectionTool::calculateDrawType () const { kpAbstractSelection *sel = document ()->selection (); - if (!sel) + if (!sel) { return Create; + } #if DEBUG_KP_TOOL_SELECTION qCDebug(kpLogTools) << "\thas sel region rect=" << sel->boundingRect (); #endif - if (onSelectionResizeHandle () && !controlOrShiftPressed ()) + if (onSelectionResizeHandle () && !controlOrShiftPressed ()) { return ResizeScale; - else if (sel->contains (currentPoint ())) + } + + if (sel->contains (currentPoint ())) { return /*virtual*/calculateDrawTypeInsideSelection (); - else - return Create; + } + + return Create; } //--------------------------------------------------------------------- // public virtual [base kpTool] void kpAbstractSelectionTool::beginDraw () { #if DEBUG_KP_TOOL_SELECTION qCDebug(kpLogTools) << "kpAbstractSelectionTool::beginDraw() startPoint ()=" << startPoint () << " QCursor::pos() view startPoint=" - << viewUnderStartPoint ()->mapFromGlobal (QCursor::pos ()) - << endl; + << viewUnderStartPoint ()->mapFromGlobal (QCursor::pos ()); #endif // endDraw() and cancelShape() should have taken care of these. ::AssertAllTimersInactive (d); // In case the cursor was wrong to start with // (forgot to call kpTool::somethingBelowTheCursorChanged()), // make sure it is correct during this operation. hover (currentPoint ()); // Currently used only to end the current text if (hasBegunShape ()) { endShape(currentPoint(), kpPainter::normalizedRect(startPoint()/* TODO: wrong */, currentPoint())); } d->drawType = calculateDrawType (); d->dragAccepted = false; kpAbstractSelection *sel = document ()->selection (); d->hadSelectionBeforeDraw = bool (sel); operation (d->drawType, BeginDraw); } //--------------------------------------------------------------------- // public virtual [base kpTool] void kpAbstractSelectionTool::hover (const QPoint &point) { #if DEBUG_KP_TOOL_SELECTION && 1 qCDebug(kpLogTools) << "kpAbstractSelectionTool::hover" << point; #endif operation (calculateDrawType (), SetCursor); setUserShapePoints (point, KP_INVALID_POINT, false/*don't set size*/); if (document () && document ()->selection ()) { setUserShapeSize (document ()->selection ()->width (), document ()->selection ()->height ()); } else { setUserShapeSize (KP_INVALID_SIZE); } QString mess = haventBegunDrawUserMessage (); - if (mess != userMessage ()) + if (mess != userMessage ()) { setUserMessage (mess); + } } //--------------------------------------------------------------------- // public virtual [base kpTool] void kpAbstractSelectionTool::draw (const QPoint &thisPoint, const QPoint & /*lastPoint*/, const QRect &normalizedRect) { #if DEBUG_KP_TOOL_SELECTION && 1 qCDebug(kpLogTools) << "kpAbstractSelectionTool::draw (" << thisPoint << ",startPoint=" << startPoint () - << ",normalizedRect=" << normalizedRect << ")" << endl; + << ",normalizedRect=" << normalizedRect << ")"; #else Q_UNUSED (thisPoint); Q_UNUSED (normalizedRect); #endif // OPT: return when thisPoint == lastPoint () so that e.g. when creating // Points sel, press modifiers doesn't add multiple points in same // place operation (d->drawType, Draw); } //--------------------------------------------------------------------- // public virtual [base kpTool] void kpAbstractSelectionTool::cancelShape () { #if DEBUG_KP_TOOL_SELECTION qCDebug(kpLogTools) << "kpAbstractSelectionTool::cancelShape() mouseButton=" - << mouseButton () << endl; + << mouseButton (); #endif const DrawType oldDrawType = d->drawType; // kpTool::hasBegunDraw() returns false in this method so be consistent // and clear "drawType" before dispatching the operation() below. d->drawType = None; viewManager ()->setQueueUpdates (); { operation (oldDrawType, Cancel); if (d->currentSelContentCommand) { #if DEBUG_KP_TOOL_SELECTION qCDebug(kpLogTools) << "\t\tundo sel content"; #endif d->currentSelContentCommand->unexecute (); delete d->currentSelContentCommand; d->currentSelContentCommand = nullptr; } /*virtual*/setSelectionBorderForHaventBegunDraw (); } viewManager ()->restoreQueueUpdates (); d->cancelledShapeButStillHoldingButtons = true; setUserMessage (i18n ("Let go of all the mouse buttons.")); ::AssertAllTimersInactive (d); } //--------------------------------------------------------------------- // public virtual [base kpTool] void kpAbstractSelectionTool::releasedAllButtons () { d->cancelledShapeButStillHoldingButtons = false; setUserMessage (haventBegunDrawUserMessage ()); } //--------------------------------------------------------------------- // protected void kpAbstractSelectionTool::popupRMBMenu () { #if DEBUG_KP_TOOL_SELECTION qCDebug(kpLogTools) << "CALL - exec'ing menu"; #endif QMenu *pop = environ ()->selectionToolRMBMenu (); Q_ASSERT (pop); // Blocks until the menu closes. // WARNING: Enters event loop - may re-enter view/tool event handlers. pop->exec (QCursor::pos ()); #if DEBUG_KP_TOOL_SELECTION qCDebug(kpLogTools) << "calling somethingBelowTheCursorChanged()"; #endif // Cursor may have moved while the menu was up, triggering QMouseMoveEvents // for the menu -- but not the view -- so we may have missed cursor moves. // Update cursor position now. somethingBelowTheCursorChanged (); #if DEBUG_KP_TOOL_SELECTION qCDebug(kpLogTools) << "DONE"; #endif } //--------------------------------------------------------------------- // public virtual [base kpTool] void kpAbstractSelectionTool::endDraw (const QPoint & /*thisPoint*/, const QRect & /*normalizedRect*/) { #if DEBUG_KP_TOOL_SELECTION qCDebug(kpLogTools) << "kpAbstractSelectionTool::endDraw()"; #endif const DrawType oldDrawType = d->drawType; // kpTool::hasBegunDraw() returns false in this method so be consistent // and clear "drawType" before dispatching the operation() below. d->drawType = None; viewManager ()->setQueueUpdates (); { operation (oldDrawType, EndDraw); /*virtual*/setSelectionBorderForHaventBegunDraw (); } viewManager ()->restoreQueueUpdates (); setUserMessage (haventBegunDrawUserMessage ()); ::AssertAllTimersInactive (d); - if (mouseButton () == 1/*right*/) + if (mouseButton () == 1/*right*/) { popupRMBMenu (); + } // WARNING: Do not place any code after the popupRMBMenu() call // (see the popupRMBMenu() API). } //--------------------------------------------------------------------- // protected virtual QVariant kpAbstractSelectionTool::operation (DrawType drawType, Operation op, const QVariant &data1, const QVariant &data2) { switch (drawType) { case None: // NOP. return QVariant (); case Create: return operationCreate (op, data1, data2); case Move: return operationMove (op, data1, data2); case ResizeScale: return operationResizeScale (op, data1, data2); default: Q_ASSERT (!"Unhandled draw type"); return QVariant (); } } //--------------------------------------------------------------------- diff --git a/tools/selection/kpAbstractSelectionTool_Create.cpp b/tools/selection/kpAbstractSelectionTool_Create.cpp index a9103694..08b01e00 100644 --- a/tools/selection/kpAbstractSelectionTool_Create.cpp +++ b/tools/selection/kpAbstractSelectionTool_Create.cpp @@ -1,299 +1,300 @@ /* Copyright (c) 2003-2007 Clarence Dang All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #define DEBUG_KP_TOOL_SELECTION 0 #include "kpAbstractSelectionTool.h" #include "kpAbstractSelectionToolPrivate.h" #include #include #include #include #include "kpLogCategories.h" #include "layers/selections/image/kpAbstractImageSelection.h" #include "layers/selections/kpAbstractSelection.h" #include "commands/kpCommandHistory.h" #include "kpDefs.h" #include "document/kpDocument.h" #include "commands/kpMacroCommand.h" #include "commands/tools/selection/kpToolSelectionCreateCommand.h" #include "commands/tools/selection/kpToolSelectionDestroyCommand.h" #include "environments/tools/selection/kpToolSelectionEnvironment.h" #include "commands/tools/selection/kpToolSelectionMoveCommand.h" #include "commands/tools/selection/kpToolSelectionResizeScaleCommand.h" #include "commands/tools/selection/kpToolImageSelectionTransparencyCommand.h" #include "widgets/toolbars/kpToolToolBar.h" #include "widgets/toolbars/options/kpToolWidgetOpaqueOrTransparent.h" #include "views/kpView.h" #include "views/manager/kpViewManager.h" // private void kpAbstractSelectionTool::initCreate () { d->createNOPTimer = new QTimer (this); d->createNOPTimer->setSingleShot (true); connect (d->createNOPTimer, &QTimer::timeout, this, &kpAbstractSelectionTool::delayedDrawCreate); } // private void kpAbstractSelectionTool::uninitCreate () { // d->createNOPTimer (deleted by QObject mechanism) } // private void kpAbstractSelectionTool::beginCreate () { // d->createNOPTimer } // private void kpAbstractSelectionTool::endCreate () { // d->createNOPTimer } //--------------------------------------------------------------------- // use a crosshair cursor which is really always exactly 1 pixel wide // to the contrary of the "themed" crosshair cursors which might look nice // but does not allow to exactly position the hot-spot. /* XPM */ static const char *crosshair[]={ "17 17 3 1", ". c None", "x c #FFFFFF", "# c #000000", ".......xxx.......", ".......x#x.......", ".......x#x.......", ".......x#x.......", ".......x#x.......", ".......x#x.......", ".......x#x.......", "xxxxxxxx#xxxxxxxx", "x#######.#######x", "xxxxxxxx#xxxxxxxx", ".......x#x.......", ".......x#x.......", ".......x#x.......", ".......x#x.......", ".......x#x.......", ".......x#x.......", ".......xxx......."}; // private void kpAbstractSelectionTool::setCursorCreate () { viewManager()->setCursor(QCursor(QPixmap(crosshair), 8, 8)); } //--------------------------------------------------------------------- // protected virtual void kpAbstractSelectionTool::setSelectionBorderForBeginDrawCreate () { viewManager ()->setQueueUpdates (); { // LOREFACTOR: I suspect some calls to viewManager() in this // file (including this) are redundant since any // code that tweaks such settings, returns them to // their original state, after the code is complete. viewManager ()->setSelectionBorderVisible (true); viewManager ()->setSelectionBorderFinished (false); } viewManager ()->restoreQueueUpdates (); } // private void kpAbstractSelectionTool::beginDrawCreate () { - if (document ()->selection ()) + if (document ()->selection ()) { pushOntoDocument (); + } /*virtual*/setSelectionBorderForBeginDrawCreate (); // (single shot) d->createNOPTimer->start (200/*ms*/); setUserMessage (cancelUserMessage ()); } // private void kpAbstractSelectionTool::drawCreate (const QPoint &thisPoint, const QRect &normalizedRect) { #if DEBUG_KP_TOOL_SELECTION && 1 - qCDebug(kpLogTools) << "\tnot moving - resizing rect to" << normalizedRect - << endl; + qCDebug(kpLogTools) << "\tnot moving - resizing rect to" << normalizedRect; qCDebug(kpLogTools) << "\t\tcreateNOPTimer->isActive()=" << d->createNOPTimer->isActive () << " viewManhattanLength from startPoint=" - << viewUnderStartPoint ()->transformDocToViewX ((thisPoint - startPoint ()).manhattanLength ()) - << endl; + << viewUnderStartPoint ()->transformDocToViewX ((thisPoint - startPoint ()).manhattanLength ()); #endif QPoint accidentalDragAdjustedPoint = thisPoint; if (d->createNOPTimer->isActive ()) { // See below "d->createNOPTimer->stop()". Q_ASSERT (!d->dragAccepted); if (viewUnderStartPoint ()->transformDocToViewX ( (accidentalDragAdjustedPoint - startPoint ()).manhattanLength ()) <= 6) { #if DEBUG_KP_TOOL_SELECTION && 1 qCDebug(kpLogTools) << "\t\tsuppress accidental movement"; #endif accidentalDragAdjustedPoint = startPoint (); } else { #if DEBUG_KP_TOOL_SELECTION && 1 qCDebug(kpLogTools) << "\t\tit's a \"big\" intended move - stop timer"; #endif d->createNOPTimer->stop (); } } const bool hadSelection = document ()->selection (); const bool oldDrawAcceptedAsDrag = d->dragAccepted; d->dragAccepted = /*virtual*/drawCreateMoreSelectionAndUpdateStatusBar ( d->dragAccepted, accidentalDragAdjustedPoint, normalizedRect); - if (oldDrawAcceptedAsDrag) + if (oldDrawAcceptedAsDrag) { Q_ASSERT (d->dragAccepted); + } if (d->dragAccepted) { #if DEBUG_KP_TOOL_SELECTION && 1 qCDebug(kpLogTools) << "\t\tdrawHasDoneSomething - kill create timer"; #endif // No longer a NOP. d->createNOPTimer->stop (); } // Did we just create a selection? - if (!hadSelection && document ()->selection ()) + if (!hadSelection && document ()->selection ()) { viewManager ()->setSelectionBorderVisible (true); + } } // private slot void kpAbstractSelectionTool::delayedDrawCreate () { #if DEBUG_KP_TOOL_SELECTION && 1 qCDebug(kpLogTools) << "kpAbstractSelectionTool::delayedDrawCreate() hasBegunDraw=" << hasBegunDraw () << " currentPoint=" << currentPoint () << " lastPoint=" << lastPoint () - << " startPoint=" << startPoint () - << endl; + << " startPoint=" << startPoint (); #endif // (just in case not called from single shot) d->createNOPTimer->stop (); if (hasBegunDraw ()) { draw (currentPoint (), lastPoint (), normalizedRect ()); } } // private void kpAbstractSelectionTool::cancelCreate () { #if DEBUG_KP_TOOL_SELECTION qCDebug(kpLogTools) << "\twas creating sel - kill"; #endif d->createNOPTimer->stop (); // TODO: should we give the user back the selection s/he had before (if any)? - if (document ()->selection ()) + if (document ()->selection ()) { document ()->selectionDelete (); + } } // private void kpAbstractSelectionTool::endDrawCreate () { d->createNOPTimer->stop (); } // private QVariant kpAbstractSelectionTool::operationCreate (Operation op, const QVariant &data1, const QVariant &data2) { (void) data1; (void) data2; switch (op) { case HaventBegunDrawUserMessage: return /*virtual*/haventBegunDrawUserMessageCreate (); case SetCursor: setCursorCreate (); break; case BeginDraw: beginDrawCreate (); break; case Draw: drawCreate (currentPoint (), normalizedRect ()); break; case Cancel: cancelCreate (); break; case EndDraw: endDrawCreate (); break; default: Q_ASSERT (!"Unhandled operation"); break; } return QVariant (); } diff --git a/tools/selection/kpAbstractSelectionTool_KeyboardEvents.cpp b/tools/selection/kpAbstractSelectionTool_KeyboardEvents.cpp index 4a974dfb..bd6c80f4 100644 --- a/tools/selection/kpAbstractSelectionTool_KeyboardEvents.cpp +++ b/tools/selection/kpAbstractSelectionTool_KeyboardEvents.cpp @@ -1,104 +1,102 @@ /* Copyright (c) 2003-2007 Clarence Dang All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #define DEBUG_KP_TOOL_SELECTION 0 #include "kpAbstractSelectionTool.h" #include "kpAbstractSelectionToolPrivate.h" #include "document/kpDocument.h" #include "environments/tools/selection/kpToolSelectionEnvironment.h" #include "commands/tools/selection/kpToolSelectionMoveCommand.h" #include "layers/selections/kpAbstractSelection.h" #include #include "kpLogCategories.h" //--------------------------------------------------------------------- // protected virtual [base kpTool] void kpAbstractSelectionTool::keyPressEvent (QKeyEvent *e) { #if DEBUG_KP_TOOL_SELECTION && 0 qCDebug(kpLogTools) << "kpAbstractSelectionTool::keyPressEvent(e->text='" - << e->text () << "')" << endl; + << e->text () << "')"; #endif e->ignore (); if (document ()->selection () && !hasBegunDraw () && e->key () == Qt::Key_Escape) { #if DEBUG_KP_TOOL_SELECTION && 0 - qCDebug(kpLogTools) << "\tescape pressed with sel when not begun draw - deselecting" - << endl; + qCDebug(kpLogTools) << "\tescape pressed with sel when not begun draw - deselecting"; #endif pushOntoDocument (); e->accept (); } else { #if DEBUG_KP_TOOL_SELECTION && 0 qCDebug(kpLogTools) << "\tkey processing did not accept (text was '" << e->text () - << "') - passing on event to kpTool" - << endl; + << "') - passing on event to kpTool"; #endif if ( document()->selection() && !hasBegunDraw() && ((e->key() == Qt::Key_Left) || (e->key() == Qt::Key_Right) || (e->key() == Qt::Key_Up) || (e->key() == Qt::Key_Down)) ) { // move selection with cursor keys pixel-wise giveContentIfNeeded(); if ( !d->currentMoveCommand ) { d->currentMoveCommand = new kpToolSelectionMoveCommand( QString()/*uninteresting child of macro cmd*/, environ()->commandEnvironment()); d->currentMoveCommandIsSmear = false; } int dx, dy; arrowKeyPressDirection(e, &dx, &dy); d->currentMoveCommand->moveTo(document()->selection()->topLeft() + QPoint(dx, dy)); endDrawMove(); } else kpTool::keyPressEvent(e); } } //--------------------------------------------------------------------- diff --git a/tools/selection/kpAbstractSelectionTool_Move.cpp b/tools/selection/kpAbstractSelectionTool_Move.cpp index 97e8f8e2..0517bb6e 100644 --- a/tools/selection/kpAbstractSelectionTool_Move.cpp +++ b/tools/selection/kpAbstractSelectionTool_Move.cpp @@ -1,398 +1,407 @@ /* Copyright (c) 2003-2007 Clarence Dang All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #define DEBUG_KP_TOOL_SELECTION 0 #include "kpAbstractSelectionTool.h" #include "kpAbstractSelectionToolPrivate.h" #include "kpLogCategories.h" #include "layers/selections/image/kpAbstractImageSelection.h" #include "layers/selections/kpAbstractSelection.h" #include "commands/kpCommandHistory.h" #include "kpDefs.h" #include "document/kpDocument.h" #include "commands/kpMacroCommand.h" #include "commands/tools/selection/kpToolSelectionCreateCommand.h" #include "commands/tools/selection/kpToolSelectionDestroyCommand.h" #include "environments/tools/selection/kpToolSelectionEnvironment.h" #include "commands/tools/selection/kpToolSelectionMoveCommand.h" #include "commands/tools/selection/kpToolSelectionResizeScaleCommand.h" #include "commands/tools/selection/kpToolImageSelectionTransparencyCommand.h" #include "widgets/toolbars/kpToolToolBar.h" #include "widgets/toolbars/options/kpToolWidgetOpaqueOrTransparent.h" #include "views/kpView.h" #include "views/manager/kpViewManager.h" #include #include //--------------------------------------------------------------------- // private void kpAbstractSelectionTool::initMove () { d->currentMoveCommand = nullptr; // d->currentMoveCommandIsSmear // d->startMoveDragFromSelectionTopLeft d->RMBMoveUpdateGUITimer = new QTimer (this); d->RMBMoveUpdateGUITimer->setSingleShot (true); connect (d->RMBMoveUpdateGUITimer, &QTimer::timeout, this, &kpAbstractSelectionTool::slotRMBMoveUpdateGUI); } //--------------------------------------------------------------------- // private void kpAbstractSelectionTool::uninitMove () { // (state must be after construction, or after some time after endMove()) Q_ASSERT (!d->currentMoveCommand); // d->currentMoveCommandIsSmear // d->startMoveDragFromSelectionTopLeft // d->RMBMoveUpdateGUITimer (deleted by QObject mechanism) } //--------------------------------------------------------------------- // private void kpAbstractSelectionTool::beginMove () { // (state must be after construction, or after some time after endMove()) Q_ASSERT (!d->currentMoveCommand); // d->currentMoveCommandIsSmear // d->startMoveDragFromSelectionTopLeft; // d->RMBMoveUpdateGUITimer } //--------------------------------------------------------------------- // private void kpAbstractSelectionTool::endMove () { // (should have been killed by cancelMove() or endDrawMove()) Q_ASSERT (!d->currentMoveCommand); // d->currentMoveCommandIsSmear // d->startMoveDragFromSelectionTopLeft // d->RMBMoveUpdateGUITimer } //--------------------------------------------------------------------- // private void kpAbstractSelectionTool::setCursorMove () { viewManager ()->setCursor (Qt::SizeAllCursor); } //--------------------------------------------------------------------- // protected virtual void kpAbstractSelectionTool::setSelectionBorderForBeginDrawMove () { // don't show border while moving viewManager ()->setQueueUpdates (); { viewManager ()->setSelectionBorderVisible (false); viewManager ()->setSelectionBorderFinished (true); } viewManager ()->restoreQueueUpdates (); } //--------------------------------------------------------------------- // private void kpAbstractSelectionTool::beginDrawMove () { d->startMoveDragFromSelectionTopLeft = currentPoint () - document ()->selection ()->topLeft (); if (mouseButton () == 0) { /*virtual*/setSelectionBorderForBeginDrawMove (); } else { // Don't hide sel border momentarily if user is just // right _clicking_ selection. // (single shot timer) d->RMBMoveUpdateGUITimer->start (100/*ms*/); } setUserMessage (cancelUserMessage ()); } //--------------------------------------------------------------------- // private slot void kpAbstractSelectionTool::slotRMBMoveUpdateGUI () { // (just in case not called from single shot) d->RMBMoveUpdateGUITimer->stop (); /*virtual*/setSelectionBorderForBeginDrawMove (); kpAbstractSelection * const sel = document ()->selection (); - if (sel) + if (sel) { setUserShapePoints (sel->topLeft ()); + } } //--------------------------------------------------------------------- // private void kpAbstractSelectionTool::drawMove (const QPoint &thisPoint, const QRect &/*normalizedRect*/) { #if DEBUG_KP_TOOL_SELECTION && 1 qCDebug(kpLogTools) << "\tmoving selection"; #endif kpAbstractSelection *sel = document ()->selection (); QRect targetSelRect (thisPoint.x () - d->startMoveDragFromSelectionTopLeft.x (), thisPoint.y () - d->startMoveDragFromSelectionTopLeft.y (), sel->width (), sel->height ()); #if DEBUG_KP_TOOL_SELECTION && 1 qCDebug(kpLogTools) << "\t\tstartPoint=" << startPoint () << " thisPoint=" << thisPoint << " startDragFromSel=" << d->startMoveDragFromSelectionTopLeft - << " targetSelRect=" << targetSelRect - << endl; + << " targetSelRect=" << targetSelRect; #endif // Try to make sure selection still intersects document so that it's // reachable. - if (targetSelRect.right () < 0) + if (targetSelRect.right () < 0) { targetSelRect.translate (-targetSelRect.right (), 0); - else if (targetSelRect.left () >= document ()->width ()) + } + else if (targetSelRect.left () >= document ()->width ()) { targetSelRect.translate (document ()->width () - targetSelRect.left () - 1, 0); + } - if (targetSelRect.bottom () < 0) + if (targetSelRect.bottom () < 0) { targetSelRect.translate (0, -targetSelRect.bottom ()); - else if (targetSelRect.top () >= document ()->height ()) + } + else if (targetSelRect.top () >= document ()->height ()) { targetSelRect.translate (0, document ()->height () - targetSelRect.top () - 1); + } #if DEBUG_KP_TOOL_SELECTION && 1 qCDebug(kpLogTools) << "\t\t\tafter ensure sel rect clickable=" << targetSelRect; #endif if (!d->dragAccepted && targetSelRect.topLeft () + d->startMoveDragFromSelectionTopLeft == startPoint ()) { #if DEBUG_KP_TOOL_SELECTION && 1 qCDebug(kpLogTools) << "\t\t\t\tnop"; #endif if (!d->RMBMoveUpdateGUITimer->isActive ()) { // (slotRMBMoveUpdateGUI() calls similar line) setUserShapePoints (sel->topLeft ()); } // Prevent both NOP drag-moves return; } if (d->RMBMoveUpdateGUITimer->isActive ()) { d->RMBMoveUpdateGUITimer->stop (); slotRMBMoveUpdateGUI (); } giveContentIfNeeded (); if (!d->currentMoveCommand) { d->currentMoveCommand = new kpToolSelectionMoveCommand ( QString()/*uninteresting child of macro cmd*/, environ ()->commandEnvironment ()); d->currentMoveCommandIsSmear = false; } //viewManager ()->setQueueUpdates (); //viewManager ()->setFastUpdates (); - if (shiftPressed ()) + if (shiftPressed ()) { d->currentMoveCommandIsSmear = true; + } - if (!d->dragAccepted && (controlPressed () || shiftPressed ())) + if (!d->dragAccepted && (controlPressed () || shiftPressed ())) { d->currentMoveCommand->copyOntoDocument (); + } d->currentMoveCommand->moveTo (targetSelRect.topLeft ()); - if (shiftPressed ()) + if (shiftPressed ()) { d->currentMoveCommand->copyOntoDocument (); + } //viewManager ()->restoreFastUpdates (); //viewManager ()->restoreQueueUpdates (); // REFACTOR: yuck, yuck kpAbstractSelection *orgSel = d->currentMoveCommand->originalSelectionClone (); QPoint start = orgSel->topLeft (); delete orgSel; QPoint end = targetSelRect.topLeft (); setUserShapePoints (start, end, false/*don't set size*/); setUserShapeSize (end.x () - start.x (), end.y () - start.y ()); d->dragAccepted = true; } //--------------------------------------------------------------------- // private void kpAbstractSelectionTool::cancelMove () { #if DEBUG_KP_TOOL_SELECTION qCDebug(kpLogTools) << "\twas drag moving - undo drag and undo acquire"; #endif d->RMBMoveUpdateGUITimer->stop (); // NOP drag? - if (!d->currentMoveCommand) + if (!d->currentMoveCommand) { return; + } #if DEBUG_KP_TOOL_SELECTION qCDebug(kpLogTools) << "\t\tundo currentMoveCommand"; #endif d->currentMoveCommand->finalize (); d->currentMoveCommand->unexecute (); delete d->currentMoveCommand; d->currentMoveCommand = nullptr; } //--------------------------------------------------------------------- // protected virtual QString kpAbstractSelectionTool::nonSmearMoveCommandName () const { return i18n ("Selection: Move"); } //--------------------------------------------------------------------- // private void kpAbstractSelectionTool::endDrawMove () { d->RMBMoveUpdateGUITimer->stop (); // NOP drag? - if (!d->currentMoveCommand) + if (!d->currentMoveCommand) { return; + } d->currentMoveCommand->finalize (); kpMacroCommand *renamedCmd = nullptr; #if DEBUG_KP_TOOL_SELECTION qCDebug(kpLogTools) << "\thave moveCommand"; #endif if (d->currentMoveCommandIsSmear) { renamedCmd = new kpMacroCommand (i18n ("%1: Smear", document ()->selection ()->name ()), environ ()->commandEnvironment ()); } else { renamedCmd = new kpMacroCommand ( /*virtual*/nonSmearMoveCommandName (), environ ()->commandEnvironment ()); } renamedCmd->addCommand (d->currentMoveCommand); d->currentMoveCommand = nullptr; addNeedingContentCommand (renamedCmd); } //--------------------------------------------------------------------- // private QVariant kpAbstractSelectionTool::operationMove (Operation op, const QVariant &data1, const QVariant &data2) { (void) data1; (void) data2; switch (op) { case HaventBegunDrawUserMessage: return /*virtual*/haventBegunDrawUserMessageMove (); case SetCursor: setCursorMove (); break; case BeginDraw: beginDrawMove (); break; case Draw: drawMove (currentPoint (), normalizedRect ()); break; case Cancel: cancelMove (); break; case EndDraw: endDrawMove (); break; default: Q_ASSERT (!"Unhandled operation"); break; } return QVariant (); } //--------------------------------------------------------------------- diff --git a/tools/selection/kpAbstractSelectionTool_ResizeScale.cpp b/tools/selection/kpAbstractSelectionTool_ResizeScale.cpp index 244936e0..13055c15 100644 --- a/tools/selection/kpAbstractSelectionTool_ResizeScale.cpp +++ b/tools/selection/kpAbstractSelectionTool_ResizeScale.cpp @@ -1,444 +1,450 @@ /* Copyright (c) 2003-2007 Clarence Dang All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #define DEBUG_KP_TOOL_SELECTION 0 #include "kpAbstractSelectionTool.h" #include "kpAbstractSelectionToolPrivate.h" #include "kpLogCategories.h" #include #include "layers/selections/image/kpAbstractImageSelection.h" #include "layers/selections/kpAbstractSelection.h" #include "commands/kpCommandHistory.h" #include "kpDefs.h" #include "document/kpDocument.h" #include "commands/kpMacroCommand.h" #include "commands/tools/selection/kpToolSelectionCreateCommand.h" #include "commands/tools/selection/kpToolSelectionDestroyCommand.h" #include "environments/tools/selection/kpToolSelectionEnvironment.h" #include "commands/tools/selection/kpToolSelectionMoveCommand.h" #include "commands/tools/selection/kpToolSelectionResizeScaleCommand.h" #include "commands/tools/selection/kpToolImageSelectionTransparencyCommand.h" #include "widgets/toolbars/kpToolToolBar.h" #include "widgets/toolbars/options/kpToolWidgetOpaqueOrTransparent.h" #include "views/kpView.h" #include "views/manager/kpViewManager.h" // private int kpAbstractSelectionTool::onSelectionResizeHandle () const { kpView *v = viewManager ()->viewUnderCursor (); - if (!v) + if (!v) { return 0; + } return v->mouseOnSelectionResizeHandle (currentViewPoint ()); } //--------------------------------------------------------------------- // private void kpAbstractSelectionTool::initResizeScale () { d->currentResizeScaleCommand = nullptr; // d->resizeScaleType } // private void kpAbstractSelectionTool::uninitResizeScale () { // (state must be after construction, or after some time after endResizeScale()) Q_ASSERT (!d->currentResizeScaleCommand); // d->resizeScaleType } // private void kpAbstractSelectionTool::beginResizeScale () { // (state must be after construction, or after some time after endResizeScale()) Q_ASSERT (!d->currentResizeScaleCommand); // d->resizeScaleType } // private void kpAbstractSelectionTool::endResizeScale () { // (should have been killed by cancelResizeScale() or endResizeScale()) Q_ASSERT (!d->currentResizeScaleCommand); // d->resizeScaleType } //--------------------------------------------------------------------- // private void kpAbstractSelectionTool::setCursorResizeScale () { #if DEBUG_KP_TOOL_SELECTION && 0 qCDebug(kpLogTools) << "\tonSelectionResizeHandle=" - << onSelectionResizeHandle () << endl; + << onSelectionResizeHandle (); #endif Qt::CursorShape shape = Qt::ArrowCursor; switch (onSelectionResizeHandle ()) { case (kpView::Top | kpView::Left): case (kpView::Bottom | kpView::Right): shape = Qt::SizeFDiagCursor; break; case (kpView::Bottom | kpView::Left): case (kpView::Top | kpView::Right): shape = Qt::SizeBDiagCursor; break; case kpView::Top: case kpView::Bottom: shape = Qt::SizeVerCursor; break; case kpView::Left: case kpView::Right: shape = Qt::SizeHorCursor; break; } viewManager ()->setCursor (shape); } //--------------------------------------------------------------------- // protected virtual void kpAbstractSelectionTool::setSelectionBorderForBeginDrawResizeScale () { viewManager ()->setQueueUpdates (); { viewManager ()->setSelectionBorderVisible (true); viewManager ()->setSelectionBorderFinished (true); } viewManager ()->restoreQueueUpdates (); } //--------------------------------------------------------------------- // private void kpAbstractSelectionTool::beginDrawResizeScale () { d->resizeScaleType = onSelectionResizeHandle (); /*virtual*/setSelectionBorderForBeginDrawResizeScale (); setUserMessage (cancelUserMessage ()); } //--------------------------------------------------------------------- // private void kpAbstractSelectionTool::drawResizeScaleTryKeepAspect ( int newWidth, int newHeight, bool horizontalGripDragged, bool verticalGripDragged, const kpAbstractSelection &originalSelection, int *newWidthOut, int *newHeightOut) { const int oldWidth = originalSelection.width (), oldHeight = originalSelection.height (); // Width changed more than height? At equality, favor width. // Fix width, change height. // // We use and to prevent // e.g. the situation where we've dragged such that newWidth < oldWidth but // we're not dragging a vertical grip. We certainly don't want this // code to modify the width - we want to fix the width and change the // height. if ((horizontalGripDragged ? double (newWidth) / oldWidth : 0) >= (verticalGripDragged ? double (newHeight) / oldHeight : 0)) { *newHeightOut = newWidth * oldHeight / oldWidth; *newHeightOut = qMax (originalSelection.minimumHeight (), *newHeightOut); } // Height changed more than width? // Fix height, change width. else { *newWidthOut = newHeight * oldWidth / oldHeight; *newWidthOut = qMax (originalSelection.minimumWidth (), *newWidthOut); } } //--------------------------------------------------------------------- // private void kpAbstractSelectionTool::drawResizeScaleCalculateNewSelectionPosSize ( const kpAbstractSelection &originalSelection, int *newX, int *newY, int *newWidth, int *newHeight) { // // Determine new width. // // Dragging left or right grip? // If left, positive X drags decrease width. // If right, positive X drags increase width. int userXSign = 0; - if (d->resizeScaleType & kpView::Left) + if (d->resizeScaleType & kpView::Left) { userXSign = -1; - else if (d->resizeScaleType & kpView::Right) + } + else if (d->resizeScaleType & kpView::Right) { userXSign = +1; + } // Calcluate new width. *newWidth = originalSelection.width () + userXSign * (currentPoint ().x () - startPoint ().x ()); // Don't allow new width to be less than that kind of selection type's // minimum. *newWidth = qMax (originalSelection.minimumWidth (), *newWidth); // // Determine new height. // // Dragging top or bottom grip? // If top, positive Y drags decrease height. // If bottom, positive Y drags increase height. int userYSign = 0; - if (d->resizeScaleType & kpView::Top) + if (d->resizeScaleType & kpView::Top) { userYSign = -1; - else if (d->resizeScaleType & kpView::Bottom) + } + else if (d->resizeScaleType & kpView::Bottom) { userYSign = +1; + } // Calcluate new height. *newHeight = originalSelection.height () + userYSign * (currentPoint ().y () - startPoint ().y ()); // Don't allow new height to be less than that kind of selection type's // minimum. *newHeight = qMax (originalSelection.minimumHeight (), *newHeight); // Keep aspect ratio? if (shiftPressed ()) { drawResizeScaleTryKeepAspect (*newWidth, *newHeight, (userXSign != 0)/*X or XY grip dragged*/, (userYSign != 0)/*Y or XY grip dragged*/, originalSelection, newWidth/*ptr*/, newHeight/*ptr*/); } *newX = originalSelection.x (); *newY = originalSelection.y (); // // Adjust x/y to new width/height for left/top resizes. // if (d->resizeScaleType & kpView::Left) { *newX -= (*newWidth - originalSelection.width ()); } if (d->resizeScaleType & kpView::Top) { *newY -= (*newHeight - originalSelection.height ()); } #if DEBUG_KP_TOOL_SELECTION && 1 qCDebug(kpLogTools) << "\t\tnewX=" << *newX << " newY=" << *newY << " newWidth=" << *newWidth - << " newHeight=" << *newHeight - << endl; + << " newHeight=" << *newHeight; #endif } //--------------------------------------------------------------------- // private void kpAbstractSelectionTool::drawResizeScale ( const QPoint &thisPoint, const QRect &/*normalizedRect*/) { #if DEBUG_KP_TOOL_SELECTION && 1 qCDebug(kpLogTools) << "\tresize/scale"; #endif kpAbstractSelection *sel = document ()->selection (); if (!d->dragAccepted && thisPoint == startPoint ()) { #if DEBUG_KP_TOOL_SELECTION && 1 qCDebug(kpLogTools) << "\t\tnop"; #endif setUserShapePoints (QPoint (sel->width (), sel->height ())); return; } giveContentIfNeeded (); if (!d->currentResizeScaleCommand) { d->currentResizeScaleCommand = new kpToolSelectionResizeScaleCommand (environ ()->commandEnvironment ()); } const kpAbstractSelection *originalSelection = d->currentResizeScaleCommand->originalSelection (); // There is nothing illegal about position (-1,-1) but why not. int newX = -1, newY = -1, newWidth = 0, newHeight = 0; // This should change all of the above values. drawResizeScaleCalculateNewSelectionPosSize ( *originalSelection, &newX, &newY, &newWidth, &newHeight); viewManager ()->setFastUpdates (); { d->currentResizeScaleCommand->resizeAndMoveTo ( newWidth, newHeight, QPoint (newX, newY), true/*smooth scale delayed*/); } viewManager ()->restoreFastUpdates (); setUserShapePoints (QPoint (originalSelection->width (), originalSelection->height ()), QPoint (newWidth, newHeight), false/*don't set size*/); setUserShapeSize (newWidth - originalSelection->width (), newHeight - originalSelection->height ()); d->dragAccepted = true; } //--------------------------------------------------------------------- // private void kpAbstractSelectionTool::cancelResizeScale () { #if DEBUG_KP_TOOL_SELECTION qCDebug(kpLogTools) << "\twas resize/scale sel - kill"; #endif // NOP drag? - if (!d->currentResizeScaleCommand) + if (!d->currentResizeScaleCommand) { return; + } #if DEBUG_KP_TOOL_SELECTION qCDebug(kpLogTools) << "\t\tundo currentResizeScaleCommand"; #endif d->currentResizeScaleCommand->finalize (); // (unneeded but let's be safe) d->currentResizeScaleCommand->unexecute (); delete d->currentResizeScaleCommand; d->currentResizeScaleCommand = nullptr; } //--------------------------------------------------------------------- // private void kpAbstractSelectionTool::endDrawResizeScale () { // NOP drag? - if (!d->currentResizeScaleCommand) + if (!d->currentResizeScaleCommand) { return; + } d->currentResizeScaleCommand->finalize (); addNeedingContentCommand (d->currentResizeScaleCommand); d->currentResizeScaleCommand = nullptr; } //--------------------------------------------------------------------- // private QVariant kpAbstractSelectionTool::operationResizeScale (Operation op, const QVariant &data1, const QVariant &data2) { (void) data1; (void) data2; switch (op) { case HaventBegunDrawUserMessage: return /*virtual*/haventBegunDrawUserMessageResizeScale (); case SetCursor: setCursorResizeScale (); break; case BeginDraw: beginDrawResizeScale (); break; case Draw: drawResizeScale (currentPoint (), normalizedRect ()); break; case Cancel: cancelResizeScale (); break; case EndDraw: endDrawResizeScale (); break; default: Q_ASSERT (!"Unhandled operation"); break; } return QVariant (); } //--------------------------------------------------------------------- diff --git a/tools/selection/text/kpToolText.cpp b/tools/selection/text/kpToolText.cpp index a0ee455b..c1c6966a 100644 --- a/tools/selection/text/kpToolText.cpp +++ b/tools/selection/text/kpToolText.cpp @@ -1,216 +1,222 @@ // REFACTOR: For all files involved in the class, refactor remaining bits and pieces and add APIDoc /* Copyright (c) 2003-2007 Clarence Dang All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #define DEBUG_KP_TOOL_TEXT 0 #include "tools/selection/text/kpToolText.h" #include "kpToolTextPrivate.h" #include "kpLogCategories.h" #include "commands/kpCommandHistory.h" #include "document/kpDocument.h" #include "layers/selections/text/kpTextSelection.h" #include "commands/tools/selection/text/kpToolTextBackspaceCommand.h" #include "commands/tools/selection/text/kpToolTextChangeStyleCommand.h" #include "commands/tools/selection/text/kpToolTextGiveContentCommand.h" #include "commands/tools/selection/kpToolSelectionCreateCommand.h" #include "environments/tools/selection/kpToolSelectionEnvironment.h" #include "commands/tools/selection/text/kpToolTextDeleteCommand.h" #include "commands/tools/selection/text/kpToolTextEnterCommand.h" #include "commands/tools/selection/text/kpToolTextInsertCommand.h" #include "widgets/toolbars/options/kpToolWidgetOpaqueOrTransparent.h" #include "views/kpView.h" #include "views/manager/kpViewManager.h" #include kpToolText::kpToolText (kpToolSelectionEnvironment *environ, QObject *parent) : kpAbstractSelectionTool (i18n ("Text"), i18n ("Writes text"), Qt::Key_T, environ, parent, "tool_text"), d (new kpToolTextPrivate ()) { } kpToolText::~kpToolText () { delete d; } // protected virtual [kpAbstractSelectionTool] kpAbstractSelectionContentCommand *kpToolText::newGiveContentCommand () const { kpTextSelection *textSel = document ()->textSelection (); #if DEBUG_KP_TOOL_TEXT qCDebug(kpLogTools) << "kpToolText::newGiveContentCommand()" << " textSel=" << textSel - << "; hasContent=" << textSel->hasContent () << endl; + << "; hasContent=" << textSel->hasContent (); #endif Q_ASSERT (textSel && !textSel->hasContent ()); return new kpToolTextGiveContentCommand ( *textSel, QString()/*uninteresting child of macro cmd*/, environ ()->commandEnvironment ()); } // protected virtual [kpAbstractSelectionTool] QString kpToolText::nameOfCreateCommand () const { return i18n ("Text: Create Box"); } // protected virtual [base kpAbstractSelectionTool] void kpToolText::setSelectionBorderForHaventBegunDraw () { viewManager ()->setQueueUpdates (); { kpAbstractSelectionTool::setSelectionBorderForHaventBegunDraw (); viewManager ()->setTextCursorEnabled (true); } viewManager ()->restoreQueueUpdates (); } // public virtual [base kpAbstractSelectionTool] void kpToolText::begin () { #if DEBUG_KP_TOOL_TEXT && 1 qCDebug(kpLogTools) << "kpToolText::begin()"; #endif environ ()->enableTextToolBarActions (true); // We don't actually need this since begin() already calls it via // setSelectionBorderForHaventBegunDraw(). We leave this in for // consistency with end(). viewManager ()->setTextCursorEnabled (true); viewManager()->setInputMethodEnabled (true); endTypingCommands (); kpAbstractSelectionTool::begin (); } // public virtual [base kpAbstractSelectionTool] void kpToolText::end () { #if DEBUG_KP_TOOL_TEXT && 1 qCDebug(kpLogTools) << "kpToolText::end()"; #endif kpAbstractSelectionTool::end (); viewManager()->setInputMethodEnabled (false); viewManager ()->setTextCursorEnabled (false); environ ()->enableTextToolBarActions (false); } // public bool kpToolText::hasBegunText () const { return (d->insertCommand || d->enterCommand || d->backspaceCommand || d->backspaceWordCommand || d->deleteCommand || d->deleteWordCommand); } // public virtual [base kpTool] bool kpToolText::hasBegunShape () const { return (hasBegunDraw () || hasBegunText ()); } // protected virtual [base kpAbstractSelectionTool] kpAbstractSelectionTool::DrawType kpToolText::calculateDrawTypeInsideSelection () const { if (onSelectionToSelectText () && !controlOrShiftPressed ()) { return kpAbstractSelectionTool::SelectText; } return kpAbstractSelectionTool::calculateDrawTypeInsideSelection (); } // public virtual [base kpAbstractSelectionTool] void kpToolText::cancelShape () { #if DEBUG_KP_TOOL_TEXT qCDebug(kpLogTools) << "kpToolText::cancelShape()"; #endif - if (drawType () != None) + if (drawType () != None) { kpAbstractSelectionTool::cancelShape (); + } else if (hasBegunText ()) { endTypingCommands (); commandHistory ()->undo (); } - else + else { kpAbstractSelectionTool::cancelShape (); + } } // public virtual [base kpTool] void kpToolText::endShape (const QPoint &thisPoint, const QRect &normalizedRect) { #if DEBUG_KP_TOOL_TEXT qCDebug(kpLogTools) << "kpToolText::endShape()"; #endif - if (drawType () != None) + if (drawType () != None) { kpAbstractSelectionTool::endDraw (thisPoint, normalizedRect); - else if (hasBegunText ()) + } + else if (hasBegunText ()) { endTypingCommands (); - else + } + else { kpAbstractSelectionTool::endDraw (thisPoint, normalizedRect); + } } // protected virtual [base kpAbstractSelectionTool] QVariant kpToolText::operation (DrawType drawType, Operation op, const QVariant &data1, const QVariant &data2) { - if (drawType == SelectText) + if (drawType == SelectText) { return selectTextOperation (op, data1, data2); - else - return kpAbstractSelectionTool::operation (drawType, op, data1, data2); + } + + return kpAbstractSelectionTool::operation (drawType, op, data1, data2); } diff --git a/tools/selection/text/kpToolText_Create.cpp b/tools/selection/text/kpToolText_Create.cpp index eebf148a..0e2feb75 100644 --- a/tools/selection/text/kpToolText_Create.cpp +++ b/tools/selection/text/kpToolText_Create.cpp @@ -1,288 +1,293 @@ /* Copyright (c) 2003-2007 Clarence Dang All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #define DEBUG_KP_TOOL_TEXT 0 #include "tools/selection/text/kpToolText.h" #include "kpToolTextPrivate.h" #include #include #include "kpLogCategories.h" #include "document/kpDocument.h" #include "layers/selections/text/kpTextSelection.h" #include "environments/tools/selection/kpToolSelectionEnvironment.h" #include "views/manager/kpViewManager.h" // protected virtual [kpAbstractSelectionTool] QString kpToolText::haventBegunDrawUserMessageCreate () const { return i18n ("Left drag to create text box."); } // protected virtual [base kpAbstractSelectionTool] void kpToolText::setSelectionBorderForBeginDrawCreate () { viewManager ()->setQueueUpdates (); { kpAbstractSelectionTool::setSelectionBorderForBeginDrawCreate (); viewManager ()->setTextCursorEnabled (false); } viewManager ()->restoreQueueUpdates (); } // private int kpToolText::calcClickCreateDimension (int mouseStart, int mouseEnd, int preferredMin, int smallestMin, int docSize) { Q_ASSERT (preferredMin >= smallestMin); Q_ASSERT (docSize > 0); // Get reasonable width/height for a text box. int ret = preferredMin; // X or Y increasing? if (mouseEnd >= mouseStart) { // Text box extends past document width/height? if (mouseStart + ret - 1 >= docSize) { // Cap width/height to not extend past but not below smallest // possible selection width/height ret = qMax (smallestMin, docSize - mouseStart); } } // X or Y decreasing else { // Text box extends past document start? // TODO: I doubt this code can be invoked for a click. // Maybe very tricky interplay with accidental drag detection? if (mouseStart - ret + 1 < 0) { // Cap width/height to not extend past but not below smallest // possible selection width/height. ret = qMax (smallestMin, mouseStart + 1); } } return ret; } // private bool kpToolText::shouldCreate (bool dragAccepted, const QPoint &accidentalDragAdjustedPoint, const kpTextStyle &textStyle, int *minimumWidthOut, int *minimumHeightOut, bool *newDragAccepted) { #if DEBUG_KP_TOOL_TEXT && 1 qCDebug(kpLogTools) << "CALL(dragAccepted=" << dragAccepted << ",accidentalDragAdjustedPoint=" << accidentalDragAdjustedPoint << ")"; #endif *newDragAccepted = dragAccepted; // Is the drag so short that we're essentially just clicking? // Basically, we're trying to prevent unintentional creation of 1-pixel // selections. if (!dragAccepted && accidentalDragAdjustedPoint == startPoint ()) { // We had an existing text box before the click? if (hadSelectionBeforeDraw ()) { #if DEBUG_KP_TOOL_TEXT && 1 qCDebug(kpLogTools) << "\ttext box deselect - NOP - return"; #endif // We must be attempting to deselect the text box. // This deselection has already been done by kpAbstractSelectionTool::beginDraw(). // Therefore, we are not doing a drag. return false; } // We are probably creating a new box. - else - { - // This drag is currently a click -- not a drag. - // As a special case, allow user to create a text box, - // of reasonable ("preferred minimum") size, using a single - // click. - // - // If the user drags further, the normal drag-to-create-a-textbox - // branch [x] will execute and the size will be determined based on - // the size of the drag instead. - #if DEBUG_KP_TOOL_TEXT && 1 - qCDebug(kpLogTools) << "\tclick creating text box"; - #endif - // (Click creating text box with RMB would not be obvious - // since RMB menu most likely hides text box immediately - // afterwards) - // TODO: I suspect this logic is simply too late - // TODO: We setUserShapePoints() on return but didn't before. - if (mouseButton () == 1) - return false/*do not create text box*/; + // This drag is currently a click -- not a drag. + // As a special case, allow user to create a text box, + // of reasonable ("preferred minimum") size, using a single + // click. + // + // If the user drags further, the normal drag-to-create-a-textbox + // branch [x] will execute and the size will be determined based on + // the size of the drag instead. +#if DEBUG_KP_TOOL_TEXT && 1 + qCDebug(kpLogTools) << "\tclick creating text box"; +#endif + + // (Click creating text box with RMB would not be obvious + // since RMB menu most likely hides text box immediately + // afterwards) + // TODO: I suspect this logic is simply too late + // TODO: We setUserShapePoints() on return but didn't before. + if (mouseButton () == 1) { + return false/*do not create text box*/; + } - // Calculate suggested width. - *minimumWidthOut = calcClickCreateDimension ( - startPoint ().x (), + + // Calculate suggested width. + *minimumWidthOut = calcClickCreateDimension ( + startPoint ().x (), accidentalDragAdjustedPoint.x (), - kpTextSelection::PreferredMinimumWidthForTextStyle (textStyle), + kpTextSelection::PreferredMinimumWidthForTextStyle (textStyle), kpTextSelection::MinimumWidthForTextStyle (textStyle), - document ()->width ()); + document ()->width ()); - // Calculate suggested height. - *minimumHeightOut = calcClickCreateDimension ( - startPoint ().y (), + // Calculate suggested height. + *minimumHeightOut = calcClickCreateDimension ( + startPoint ().y (), accidentalDragAdjustedPoint.y (), - kpTextSelection::PreferredMinimumHeightForTextStyle (textStyle), + kpTextSelection::PreferredMinimumHeightForTextStyle (textStyle), kpTextSelection::MinimumHeightForTextStyle (textStyle), - document ()->height ()); + document ()->height ()); - // Do _not_ set "newDragAccepted" to true as we want - // this text box to remain at the click-given size, in the absence - // of any dragging. In other words, if draw() is called again - // and therefore, we are called again, but the mouse has not - // moved, we do want this branch to execute again, not - // Branch [x]. - return true/*do create text box*/; - } + // Do _not_ set "newDragAccepted" to true as we want + // this text box to remain at the click-given size, in the absence + // of any dragging. In other words, if draw() is called again + // and therefore, we are called again, but the mouse has not + // moved, we do want this branch to execute again, not + // Branch [x]. + return true/*do create text box*/; } // Dragging to create a text box [x]. // // The size will be determined based on the size of the drag. - else - { - #if DEBUG_KP_TOOL_TEXT && 1 - qCDebug(kpLogTools) << "\tdrag creating text box"; - #endif - *minimumWidthOut = kpTextSelection::MinimumWidthForTextStyle (textStyle); - *minimumHeightOut = kpTextSelection::MinimumHeightForTextStyle (textStyle); - *newDragAccepted = true; - return true/*do create text box*/; - } +#if DEBUG_KP_TOOL_TEXT && 1 + qCDebug(kpLogTools) << "\tdrag creating text box"; +#endif + *minimumWidthOut = kpTextSelection::MinimumWidthForTextStyle (textStyle); + *minimumHeightOut = kpTextSelection::MinimumHeightForTextStyle (textStyle); + + *newDragAccepted = true; + return true/*do create text box*/; } // protected virtual [kpAbstractSelectionTool] bool kpToolText::drawCreateMoreSelectionAndUpdateStatusBar ( bool dragAccepted, const QPoint &accidentalDragAdjustedPoint, const QRect &normalizedRectIn) { // (will mutate this) QRect normalizedRect = normalizedRectIn; const kpTextStyle textStyle = environ ()->textStyle (); // // Calculate Text Box Rectangle. // bool newDragAccepted = dragAccepted; // (will set both variables) int minimumWidth = 0, minimumHeight = 0; if (!shouldCreate (dragAccepted, accidentalDragAdjustedPoint, textStyle, &minimumWidth, &minimumHeight, &newDragAccepted)) { setUserShapePoints (accidentalDragAdjustedPoint); return newDragAccepted; } // Make sure the dragged out rectangle is of the minimum width we just // calculated. if (normalizedRect.width () < minimumWidth) { - if (accidentalDragAdjustedPoint.x () >= startPoint ().x ()) + if (accidentalDragAdjustedPoint.x () >= startPoint ().x ()) { normalizedRect.setWidth (minimumWidth); - else + } + else { normalizedRect.setX (normalizedRect.right () - minimumWidth + 1); + } } // Make sure the dragged out rectangle is of the minimum height we just // calculated. if (normalizedRect.height () < minimumHeight) { - if (accidentalDragAdjustedPoint.y () >= startPoint ().y ()) + if (accidentalDragAdjustedPoint.y () >= startPoint ().y ()) { normalizedRect.setHeight (minimumHeight); - else + } + else { normalizedRect.setY (normalizedRect.bottom () - minimumHeight + 1); + } } #if DEBUG_KP_TOOL_TEXT && 1 qCDebug(kpLogTools) << "\t\tnormalizedRect=" << normalizedRect << " kpTextSelection::preferredMinimumSize=" - << QSize (minimumWidth, minimumHeight) - << endl; + << QSize (minimumWidth, minimumHeight); #endif // // Construct and Deploy Text Box. // // Create empty text box. QList textLines; kpTextSelection textSel (normalizedRect, textLines, textStyle); // Render. viewManager ()->setTextCursorPosition (0, 0); document ()->setSelection (textSel); // // Update Status Bar. // QPoint actualEndPoint = KP_INVALID_POINT; - if (startPoint () == normalizedRect.topLeft ()) + if (startPoint () == normalizedRect.topLeft ()) { actualEndPoint = normalizedRect.bottomRight (); - else if (startPoint () == normalizedRect.bottomRight ()) + } + else if (startPoint () == normalizedRect.bottomRight ()) { actualEndPoint = normalizedRect.topLeft (); - else if (startPoint () == normalizedRect.topRight ()) + } + else if (startPoint () == normalizedRect.topRight ()) { actualEndPoint = normalizedRect.bottomLeft (); - else if (startPoint () == normalizedRect.bottomLeft ()) + } + else if (startPoint () == normalizedRect.bottomLeft ()) { actualEndPoint = normalizedRect.topRight (); + } setUserShapePoints (startPoint (), actualEndPoint); return newDragAccepted; } diff --git a/tools/selection/text/kpToolText_CursorCalc.cpp b/tools/selection/text/kpToolText_CursorCalc.cpp index 198f395b..5813b1d0 100644 --- a/tools/selection/text/kpToolText_CursorCalc.cpp +++ b/tools/selection/text/kpToolText_CursorCalc.cpp @@ -1,212 +1,220 @@ /* Copyright (c) 2003-2007 Clarence Dang All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #define DEBUG_KP_TOOL_TEXT 0 #include "tools/selection/text/kpToolText.h" #include "kpLogCategories.h" #include "document/kpDocument.h" #include "layers/selections/text/kpTextSelection.h" #include "commands/tools/selection/text/kpToolTextBackspaceCommand.h" #include "commands/tools/selection/text/kpToolTextChangeStyleCommand.h" #include "commands/tools/selection/kpToolSelectionCreateCommand.h" #include "environments/tools/selection/kpToolSelectionEnvironment.h" #include "commands/tools/selection/text/kpToolTextDeleteCommand.h" #include "commands/tools/selection/text/kpToolTextEnterCommand.h" #include "commands/tools/selection/text/kpToolTextInsertCommand.h" #include "widgets/toolbars/options/kpToolWidgetOpaqueOrTransparent.h" #include "views/kpView.h" #include "views/manager/kpViewManager.h" #include #include // protected static bool kpToolText::CursorIsOnWordChar (const QList &textLines, int cursorRow, int cursorCol) { return (cursorRow >= 0 && cursorRow < textLines.size () && cursorCol >= 0 && cursorCol < textLines [cursorRow].length () && !textLines [cursorRow][cursorCol].isSpace ()); } // protected static bool kpToolText::CursorIsAtStart (const QList &, int cursorRow, int cursorCol) { return (cursorRow == 0 && cursorCol == 0); } // protected static bool kpToolText::CursorIsAtEnd (const QList &textLines, int cursorRow, int cursorCol) { - if (textLines.isEmpty ()) + if (textLines.isEmpty ()) { return (cursorRow == 0 && cursorCol == 0); + } return (cursorRow == textLines.size () - 1 && cursorCol == textLines [cursorRow].length ()); } // protected static void kpToolText::MoveCursorLeft (const QList &textLines, int *cursorRow, int *cursorCol) { - if (textLines.isEmpty ()) + if (textLines.isEmpty ()) { return; + } (*cursorCol)--; if (*cursorCol < 0) { (*cursorRow)--; if (*cursorRow < 0) { *cursorRow = 0; *cursorCol = 0; } - else + else { *cursorCol = textLines [*cursorRow].length (); + } } } // protected static void kpToolText::MoveCursorRight (const QList &textLines, int *cursorRow, int *cursorCol) { - if (textLines.isEmpty ()) + if (textLines.isEmpty ()) { return; + } (*cursorCol)++; if (*cursorCol > textLines [*cursorRow].length ()) { (*cursorRow)++; if (*cursorRow > textLines.size () - 1) { *cursorRow = textLines.size () - 1; *cursorCol = textLines [*cursorRow].length (); } - else + else { *cursorCol = 0; + } } } #define IS_ON_SPACE_OR_EOL() !CursorIsOnWordChar (textLines, *cursorRow, *cursorCol) // protected static int kpToolText::MoveCursorToWordStart (const QList &textLines, int *cursorRow, int *cursorCol) { - if (textLines.isEmpty ()) + if (textLines.isEmpty ()) { return 0; + } int numMoves = 0; #define IS_ON_ANCHOR() \ (CursorIsOnWordChar (textLines, *cursorRow, *cursorCol) && \ (cursorCol == 0 || \ !CursorIsOnWordChar (textLines, *cursorRow, *cursorCol - 1))) #define MOVE_CURSOR_LEFT() \ (MoveCursorLeft (textLines, cursorRow, cursorCol), ++numMoves) // (these comments will exclude the row=0,col=0 boundary case) - if (IS_ON_ANCHOR ()) + if (IS_ON_ANCHOR ()) { MOVE_CURSOR_LEFT (); + } // --- now we're not on an anchor point (start of word) --- // End up on a letter... while (!(*cursorRow == 0 && *cursorCol == 0) && (IS_ON_SPACE_OR_EOL ())) { MOVE_CURSOR_LEFT (); } // --- now we're on a letter --- // Find anchor point while (!(*cursorRow == 0 && *cursorCol == 0) && !IS_ON_ANCHOR ()) { MOVE_CURSOR_LEFT (); } #undef IS_ON_ANCHOR #undef MOVE_CURSOR_LEFT return numMoves; } // protected static int kpToolText::MoveCursorToNextWordStart (const QList &textLines, int *cursorRow, int *cursorCol) { - if (textLines.isEmpty ()) + if (textLines.isEmpty ()) { return 0; + } int numMoves = 0; #define IS_AT_END() CursorIsAtEnd (textLines, *cursorRow, *cursorCol) #define MOVE_CURSOR_RIGHT() \ (MoveCursorRight (textLines, cursorRow, cursorCol), ++numMoves) // (these comments will exclude the last row,end col boundary case) // Find space while (!IS_AT_END () && !IS_ON_SPACE_OR_EOL ()) { MOVE_CURSOR_RIGHT (); } // --- now we're on a space --- // Find letter while (!IS_AT_END () && IS_ON_SPACE_OR_EOL ()) { MOVE_CURSOR_RIGHT (); } // --- now we're on a letter --- #undef IS_AT_END #undef MOVE_CURSOR_RIGHT return numMoves; } #undef IS_ON_SPACE_OR_EOL diff --git a/tools/selection/text/kpToolText_InputMethodEvents.cpp b/tools/selection/text/kpToolText_InputMethodEvents.cpp index 9f0d4f13..878d2d1d 100644 --- a/tools/selection/text/kpToolText_InputMethodEvents.cpp +++ b/tools/selection/text/kpToolText_InputMethodEvents.cpp @@ -1,96 +1,96 @@ /* Copyright (c) 2003-2007 Clarence Dang Copyright (c) 2005 Kazuki Ohta Copyright (c) 2010 Tasuku Suzuki All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #define DEBUG_KP_TOOL_TEXT 0 #include "tools/selection/text/kpToolText.h" #include "kpToolTextPrivate.h" #include "commands/tools/selection/text/kpToolTextInsertCommand.h" #include #include "kpLogCategories.h" #include "document/kpDocument.h" #include "layers/selections/text/kpTextSelection.h" #include "views/kpView.h" #include "views/manager/kpViewManager.h" //--------------------------------------------------------------------- void kpToolText::inputMethodEvent (QInputMethodEvent *e) { #if DEBUG_KP_TOOL_TEXT && 1 qCDebug(kpLogTools) << "kpToolText::inputMethodEvent() preeditString='" << e->preeditString () << "commitString = " << e->commitString () << " replacementStart=" << e->replacementStart () - << " replacementLength=" << e->replacementLength () - << endl; + << " replacementLength=" << e->replacementLength (); #endif kpTextSelection *textSel = document ()->textSelection (); if (hasBegunDraw() || !textSel) { e->ignore(); return; } kpPreeditText previous = textSel->preeditText (); kpPreeditText next (e); int textCursorRow = viewManager ()->textCursorRow (); int textCursorCol = viewManager ()->textCursorCol (); if (!next.isEmpty ()) { if (previous.position().x () < 0 && previous.position().y () < 0) { next.setPosition (QPoint(textCursorCol, textCursorRow)); } else { next.setPosition(previous.position ()); } } textSel->setPreeditText (next); textCursorCol = textCursorCol - previous.cursorPosition () + next.cursorPosition (); viewManager ()->setTextCursorPosition (textCursorRow, textCursorCol); QString commitString = e->commitString (); if (!commitString.isEmpty ()) { // commit string - if (!d->insertCommand) + if (!d->insertCommand) { addNewInsertCommand (&d->insertCommand); + } d->insertCommand->addText (commitString); } e->accept (); } //--------------------------------------------------------------------- diff --git a/tools/selection/text/kpToolText_KeyboardEvents.cpp b/tools/selection/text/kpToolText_KeyboardEvents.cpp index ef958925..246fee8f 100644 --- a/tools/selection/text/kpToolText_KeyboardEvents.cpp +++ b/tools/selection/text/kpToolText_KeyboardEvents.cpp @@ -1,214 +1,212 @@ /* Copyright (c) 2003-2007 Clarence Dang All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #define DEBUG_KP_TOOL_TEXT 0 #include "tools/selection/text/kpToolText.h" #include "kpToolTextPrivate.h" #include #include #include "kpLogCategories.h" #include "commands/kpCommandHistory.h" #include "document/kpDocument.h" #include "layers/selections/text/kpTextSelection.h" #include "commands/tools/selection/text/kpToolTextBackspaceCommand.h" #include "commands/tools/selection/text/kpToolTextChangeStyleCommand.h" #include "commands/tools/selection/kpToolSelectionCreateCommand.h" #include "environments/tools/selection/kpToolSelectionEnvironment.h" #include "commands/tools/selection/text/kpToolTextDeleteCommand.h" #include "commands/tools/selection/text/kpToolTextEnterCommand.h" #include "commands/tools/selection/text/kpToolTextInsertCommand.h" #include "widgets/toolbars/options/kpToolWidgetOpaqueOrTransparent.h" #include "views/kpView.h" #include "views/manager/kpViewManager.h" #include // protected virtual [base kpTool] bool kpToolText::viewEvent (QEvent *e) { const bool isShortcutOverrideEvent = (e->type () == QEvent::ShortcutOverride); const bool haveTextSelection = document ()->textSelection (); #if DEBUG_KP_TOOL_TEXT && 0 qCDebug(kpLogTools) << "kpToolText::viewEvent() type=" << e->type () << " isShortcutOverrideEvent=" << isShortcutOverrideEvent - << " haveTextSel=" << haveTextSelection - << endl; + << " haveTextSel=" << haveTextSelection; #endif - if (!isShortcutOverrideEvent || !haveTextSelection) + if (!isShortcutOverrideEvent || !haveTextSelection) { return kpAbstractSelectionTool::viewEvent (e); + } - QKeyEvent *ke = static_cast (e); + auto *ke = dynamic_cast (e); #if DEBUG_KP_TOOL_TEXT qCDebug(kpLogTools) << "kpToolText::viewEvent() key=" << ke->key () << " modifiers=" << ke->modifiers () - << " QChar.isPrint()=" << QChar (ke->key ()).isPrint () - << endl; + << " QChar.isPrint()=" << QChar (ke->key ()).isPrint (); #endif // Can't be shortcut? if (ke->key () == 0 && ke->key () == Qt::Key_unknown) { #if DEBUG_KP_TOOL_TEXT qCDebug(kpLogTools) << "\tcan't be shortcut - safe to not react"; #endif } // Normal letter (w/ or w/o shift, keypad button ok)? // TODO: don't like this check else if ((ke->modifiers () & (Qt::ControlModifier | Qt::AltModifier | Qt::MetaModifier)) == 0 && !( ke->text ().isEmpty ())) { #if DEBUG_KP_TOOL_TEXT qCDebug(kpLogTools) << "\tis text - grab"; #endif e->accept (); } else { // Strickly speaking, we should grab stuff like the arrow keys // and enter. In any case, should be done down in kpTool (as that // uses arrow keys too). } return kpAbstractSelectionTool::event (e); } // protected virtual [base kpAbstractSelectionTool] void kpToolText::keyPressEvent (QKeyEvent *e) { #if DEBUG_KP_TOOL_TEXT qCDebug(kpLogTools) << "kpToolText::keyPressEvent(e->text='" << e->text () << "')"; #endif e->ignore (); if (hasBegunDraw ()) { #if DEBUG_KP_TOOL_TEXT qCDebug(kpLogTools) << "\talready began draw with mouse - passing on event to kpTool"; #endif kpAbstractSelectionTool::keyPressEvent (e); return; } kpTextSelection * const textSel = document ()->textSelection (); if (!textSel) { #if DEBUG_KP_TOOL_TEXT qCDebug(kpLogTools) << "\tno text sel - passing on event to kpTool"; #endif //if (hasBegunShape ()) // endShape (currentPoint (), normalizedRect ()); kpAbstractSelectionTool::keyPressEvent (e); return; } // (All handle.+()'s require this info) const QList textLines = textSel->textLines (); const int cursorRow = viewManager ()->textCursorRow (); const int cursorCol = viewManager ()->textCursorCol (); // TODO: KTextEdit::keyPressEvent() uses KStandardShortcut instead of hardcoding; same fix for kpTool? switch (e->key ()) { case Qt::Key_Up: handleUpKeyPress (e, textLines, cursorRow, cursorCol); break; case Qt::Key_Down: handleDownKeyPress (e, textLines, cursorRow, cursorCol); break; case Qt::Key_Left: handleLeftKeyPress (e, textLines, cursorRow, cursorCol); break; case Qt::Key_Right: handleRightKeyPress (e, textLines, cursorRow, cursorCol); break; case Qt::Key_Home: handleHomeKeyPress (e, textLines, cursorRow, cursorCol); break; case Qt::Key_End: handleEndKeyPress (e, textLines, cursorRow, cursorCol); break; case Qt::Key_Backspace: handleBackspaceKeyPress (e, textLines, cursorRow, cursorCol); break; case Qt::Key_Delete: handleDeleteKeyPress (e, textLines, cursorRow, cursorCol); break; case Qt::Key_Enter: case Qt::Key_Return: handleEnterKeyPress (e, textLines, cursorRow, cursorCol); break; default: handleTextTyped (e, textLines, cursorRow, cursorCol); break; } if (!e->isAccepted ()) { #if DEBUG_KP_TOOL_TEXT qCDebug(kpLogTools) << "\tkey processing did not accept (text was '" << e->text () - << "') - passing on event to kpAbstractSelectionTool" - << endl; + << "') - passing on event to kpAbstractSelectionTool"; #endif //if (hasBegunShape ()) // endShape (currentPoint (), normalizedRect ()); kpAbstractSelectionTool::keyPressEvent (e); return; } } diff --git a/tools/selection/text/kpToolText_KeyboardEvents_HandleArrowKeys.cpp b/tools/selection/text/kpToolText_KeyboardEvents_HandleArrowKeys.cpp index 4fb4969b..2eaefeb3 100644 --- a/tools/selection/text/kpToolText_KeyboardEvents_HandleArrowKeys.cpp +++ b/tools/selection/text/kpToolText_KeyboardEvents_HandleArrowKeys.cpp @@ -1,213 +1,221 @@ /* Copyright (c) 2003-2007 Clarence Dang All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #define DEBUG_KP_TOOL_TEXT 0 #include "tools/selection/text/kpToolText.h" #include "kpToolTextPrivate.h" #include #include #include "kpLogCategories.h" #include "commands/kpCommandHistory.h" #include "document/kpDocument.h" #include "layers/selections/text/kpTextSelection.h" #include "commands/tools/selection/text/kpToolTextBackspaceCommand.h" #include "commands/tools/selection/text/kpToolTextChangeStyleCommand.h" #include "commands/tools/selection/kpToolSelectionCreateCommand.h" #include "environments/tools/selection/kpToolSelectionEnvironment.h" #include "commands/tools/selection/text/kpToolTextDeleteCommand.h" #include "commands/tools/selection/text/kpToolTextEnterCommand.h" #include "commands/tools/selection/text/kpToolTextInsertCommand.h" #include "widgets/toolbars/options/kpToolWidgetOpaqueOrTransparent.h" #include "views/kpView.h" #include "views/manager/kpViewManager.h" // protected void kpToolText::handleUpKeyPress (QKeyEvent *e, const QList &textLines, int cursorRow, int cursorCol) { #if DEBUG_KP_TOOL_TEXT qCDebug(kpLogTools) << "\tup pressed"; #endif - if (hasBegunShape ()) + if (hasBegunShape ()) { endShape (currentPoint (), normalizedRect ()); + } if (!textLines.isEmpty () && cursorRow > 0) { cursorRow--; cursorCol = qMin (cursorCol, textLines [cursorRow].length ()); viewManager ()->setTextCursorPosition (cursorRow, cursorCol); } e->accept (); } // protected void kpToolText::handleDownKeyPress (QKeyEvent *e, const QList &textLines, int cursorRow, int cursorCol) { #if DEBUG_KP_TOOL_TEXT qCDebug(kpLogTools) << "\tdown pressed"; #endif - if (hasBegunShape ()) + if (hasBegunShape ()) { endShape (currentPoint (), normalizedRect ()); + } if (!textLines.isEmpty () && cursorRow < textLines.size () - 1) { cursorRow++; cursorCol = qMin (cursorCol, textLines [cursorRow].length ()); viewManager ()->setTextCursorPosition (cursorRow, cursorCol); } e->accept (); } // protected void kpToolText::handleLeftKeyPress (QKeyEvent *e, const QList &textLines, int cursorRow, int cursorCol) { #if DEBUG_KP_TOOL_TEXT qCDebug(kpLogTools) << "\tleft pressed"; #endif - if (hasBegunShape ()) + if (hasBegunShape ()) { endShape (currentPoint (), normalizedRect ()); + } if (!textLines.isEmpty ()) { if ((e->modifiers () & Qt::ControlModifier) == 0) { #if DEBUG_KP_TOOL_TEXT qCDebug(kpLogTools) << "\tmove single char"; #endif MoveCursorLeft (textLines, &cursorRow, &cursorCol); viewManager ()->setTextCursorPosition (cursorRow, cursorCol); } else { #if DEBUG_KP_TOOL_TEXT qCDebug(kpLogTools) << "\tmove to start of word"; #endif MoveCursorToWordStart (textLines, &cursorRow, &cursorCol); viewManager ()->setTextCursorPosition (cursorRow, cursorCol); } } e->accept (); } // protected void kpToolText::handleRightKeyPress (QKeyEvent *e, const QList &textLines, int cursorRow, int cursorCol) { #if DEBUG_KP_TOOL_TEXT qCDebug(kpLogTools) << "\tright pressed"; #endif - if (hasBegunShape ()) + if (hasBegunShape ()) { endShape (currentPoint (), normalizedRect ()); + } if (!textLines.isEmpty ()) { if ((e->modifiers () & Qt::ControlModifier) == 0) { #if DEBUG_KP_TOOL_TEXT qCDebug(kpLogTools) << "\tmove single char"; #endif MoveCursorRight (textLines, &cursorRow, &cursorCol); viewManager ()->setTextCursorPosition (cursorRow, cursorCol); } else { #if DEBUG_KP_TOOL_TEXT qCDebug(kpLogTools) << "\tmove to start of next word"; #endif MoveCursorToNextWordStart (textLines, &cursorRow, &cursorCol); viewManager ()->setTextCursorPosition (cursorRow, cursorCol); } } e->accept (); } // protected void kpToolText::handleHomeKeyPress (QKeyEvent *e, const QList &textLines, int cursorRow, int cursorCol) { #if DEBUG_KP_TOOL_TEXT qCDebug(kpLogTools) << "\thome pressed"; #endif - if (hasBegunShape ()) + if (hasBegunShape ()) { endShape (currentPoint (), normalizedRect ()); + } if (!textLines.isEmpty ()) { - if (e->modifiers () & Qt::ControlModifier) + if (e->modifiers () & Qt::ControlModifier) { cursorRow = 0; + } cursorCol = 0; viewManager ()->setTextCursorPosition (cursorRow, cursorCol); } e->accept (); } // protected void kpToolText::handleEndKeyPress (QKeyEvent *e, const QList &textLines, int cursorRow, int cursorCol) { #if DEBUG_KP_TOOL_TEXT qCDebug(kpLogTools) << "\tend pressed"; #endif - if (hasBegunShape ()) + if (hasBegunShape ()) { endShape (currentPoint (), normalizedRect ()); + } if (!textLines.isEmpty ()) { - if (e->modifiers () & Qt::ControlModifier) + if (e->modifiers () & Qt::ControlModifier) { cursorRow = textLines.size () - 1; + } cursorCol = textLines [cursorRow].length (); viewManager ()->setTextCursorPosition (cursorRow, cursorCol); } e->accept (); } diff --git a/tools/selection/text/kpToolText_KeyboardEvents_HandleTypingKeys.cpp b/tools/selection/text/kpToolText_KeyboardEvents_HandleTypingKeys.cpp index 2c75e629..a6e12762 100644 --- a/tools/selection/text/kpToolText_KeyboardEvents_HandleTypingKeys.cpp +++ b/tools/selection/text/kpToolText_KeyboardEvents_HandleTypingKeys.cpp @@ -1,193 +1,202 @@ /* Copyright (c) 2003-2007 Clarence Dang All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #define DEBUG_KP_TOOL_TEXT 0 #include "tools/selection/text/kpToolText.h" #include "kpToolTextPrivate.h" #include "kpLogCategories.h" #include "commands/kpCommandHistory.h" #include "document/kpDocument.h" #include "layers/selections/text/kpTextSelection.h" #include "commands/tools/selection/text/kpToolTextBackspaceCommand.h" #include "commands/tools/selection/text/kpToolTextChangeStyleCommand.h" #include "commands/tools/selection/kpToolSelectionCreateCommand.h" #include "environments/tools/selection/kpToolSelectionEnvironment.h" #include "commands/tools/selection/text/kpToolTextDeleteCommand.h" #include "commands/tools/selection/text/kpToolTextEnterCommand.h" #include "commands/tools/selection/text/kpToolTextInsertCommand.h" #include "widgets/toolbars/options/kpToolWidgetOpaqueOrTransparent.h" #include "views/kpView.h" #include "views/manager/kpViewManager.h" #include //--------------------------------------------------------------------- // protected void kpToolText::handleBackspaceKeyPress (QKeyEvent *e, const QList &textLines, int cursorRow, int cursorCol) { #if DEBUG_KP_TOOL_TEXT qCDebug(kpLogTools) << "\tbackspace pressed"; #endif if (!textLines.isEmpty ()) { if ((e->modifiers () & Qt::ControlModifier) == 0) { - if (!d->backspaceCommand) + if (!d->backspaceCommand) { addNewBackspaceCommand (&d->backspaceCommand); + } d->backspaceCommand->addBackspace (); } else { - if (!d->backspaceWordCommand) + if (!d->backspaceWordCommand) { addNewBackspaceCommand (&d->backspaceWordCommand); + } const int numMoves = MoveCursorToWordStart (textLines, &cursorRow, &cursorCol); viewManager ()->setQueueUpdates (); { - for (int i = 0; i < numMoves; i++) + for (int i = 0; i < numMoves; i++) { d->backspaceWordCommand->addBackspace (); + } } viewManager ()->restoreQueueUpdates (); Q_ASSERT (cursorRow == viewManager ()->textCursorRow ()); Q_ASSERT (cursorCol == viewManager ()->textCursorCol ()); } } e->accept (); } //--------------------------------------------------------------------- // protected void kpToolText::handleDeleteKeyPress (QKeyEvent *e, const QList & textLines, int cursorRow, int cursorCol) { #if DEBUG_KP_TOOL_TEXT qCDebug(kpLogTools) << "\tdelete pressed"; #endif if (!textLines.isEmpty ()) { if ((e->modifiers () & Qt::ControlModifier) == 0) { - if (!d->deleteCommand) + if (!d->deleteCommand) { addNewDeleteCommand (&d->deleteCommand); + } d->deleteCommand->addDelete (); } else { - if (!d->deleteWordCommand) + if (!d->deleteWordCommand) { addNewDeleteCommand (&d->deleteWordCommand); + } // We don't want to know the cursor pos of the next word start // as delete should keep cursor in same pos. int cursorRowThrowAway = cursorRow, cursorColThrowAway = cursorCol; const int numMoves = MoveCursorToNextWordStart (textLines, &cursorRowThrowAway, &cursorColThrowAway); viewManager ()->setQueueUpdates (); { - for (int i = 0; i < numMoves; i++) + for (int i = 0; i < numMoves; i++) { d->deleteWordCommand->addDelete (); + } } viewManager ()->restoreQueueUpdates (); // Assert unchanged as delete should keep cursor in same pos. Q_ASSERT (cursorRow == viewManager ()->textCursorRow ()); Q_ASSERT (cursorCol == viewManager ()->textCursorCol ()); } } e->accept (); } //--------------------------------------------------------------------- // protected void kpToolText::handleEnterKeyPress (QKeyEvent *e, const QList & /*textLines*/, int /*cursorRow*/, int /*cursorCol*/) { #if DEBUG_KP_TOOL_TEXT qCDebug(kpLogTools) << "\tenter pressed"; #endif // It's OK for to be empty. - if (!d->enterCommand) + if (!d->enterCommand) { addNewEnterCommand (&d->enterCommand); + } d->enterCommand->addEnter (); e->accept (); } //--------------------------------------------------------------------- // protected void kpToolText::handleTextTyped (QKeyEvent *e, const QList & /*textLines*/, int /*cursorRow*/, int /*cursorCol*/) { #if DEBUG_KP_TOOL_TEXT qCDebug(kpLogTools) << "\ttext=" << e->text(); #endif QString usableText; for (int i = 0; i < e->text ().length (); i++) { - if (e->text ().at (i).isPrint ()) + if (e->text ().at (i).isPrint ()) { usableText += e->text ().at (i); + } } #if DEBUG_KP_TOOL_TEXT qCDebug(kpLogTools) << "\tusableText=" << usableText; #endif if (usableText.isEmpty ()) { // Don't end the current shape nor accept the event -- the event // wasn't for us. return; } // --- It's OK for to be empty. --- - if (!d->insertCommand) + if (!d->insertCommand) { addNewInsertCommand (&d->insertCommand); + } d->insertCommand->addText (usableText); e->accept (); } diff --git a/tools/selection/text/kpToolText_SelectText.cpp b/tools/selection/text/kpToolText_SelectText.cpp index 7e081bce..6375791d 100644 --- a/tools/selection/text/kpToolText_SelectText.cpp +++ b/tools/selection/text/kpToolText_SelectText.cpp @@ -1,136 +1,137 @@ /* Copyright (c) 2003-2007 Clarence Dang All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #define DEBUG_KP_TOOL_TEXT 0 #include "tools/selection/text/kpToolText.h" #include "kpToolTextPrivate.h" #include "kpLogCategories.h" #include "document/kpDocument.h" #include "layers/selections/text/kpTextSelection.h" #include "views/kpView.h" #include "views/manager/kpViewManager.h" // private bool kpToolText::onSelectionToSelectText () const { kpView *v = viewManager ()->viewUnderCursor (); - if (!v) - return 0; + if (!v) { + return false; + } return v->mouseOnSelectionToSelectText (currentViewPoint ()); } // private QString kpToolText::haventBegunDrawUserMessageSelectText () const { return i18n ("Left click to change cursor position."); } // private void kpToolText::setCursorSelectText () { viewManager ()->setCursor (Qt::IBeamCursor); } // private void kpToolText::beginDrawSelectText () { #if DEBUG_KP_TOOL_TEXT qCDebug(kpLogTools) << "\t\tis select cursor pos"; #endif kpTextSelection *textSel = document ()->textSelection (); Q_ASSERT (textSel); int newRow, newCol; if (textSel->hasContent ()) { newRow = textSel->closestTextRowForPoint (currentPoint ()); newCol = textSel->closestTextColForPoint (currentPoint ()); } else { newRow = newCol = 0; } #if DEBUG_KP_TOOL_TEXT qCDebug(kpLogTools) << "\t\t\told: row=" << viewManager ()->textCursorRow () << "col=" << viewManager ()->textCursorCol (); qCDebug(kpLogTools) << "\t\t\tnew: row=" << newRow << "col=" << newCol; #endif viewManager ()->setTextCursorPosition (newRow, newCol); } // protected virtual QVariant kpToolText::selectTextOperation (Operation op, const QVariant &data1, const QVariant &data2) { (void) data1; (void) data2; switch (op) { case HaventBegunDrawUserMessage: return haventBegunDrawUserMessageSelectText (); case SetCursor: setCursorSelectText (); break; case BeginDraw: beginDrawSelectText (); break; case Draw: // Do nothing. break; case Cancel: // Not called. REFACTOR: Change this? break; case EndDraw: // Do nothing. break; default: Q_ASSERT (!"Unhandled operation"); break; } return QVariant (); } diff --git a/tools/selection/text/kpToolText_TextStyle.cpp b/tools/selection/text/kpToolText_TextStyle.cpp index 38c86287..ef1fcaef 100644 --- a/tools/selection/text/kpToolText_TextStyle.cpp +++ b/tools/selection/text/kpToolText_TextStyle.cpp @@ -1,326 +1,334 @@ /* Copyright (c) 2003-2007 Clarence Dang All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #define DEBUG_KP_TOOL_TEXT 0 #include "tools/selection/text/kpToolText.h" #include "kpToolTextPrivate.h" #include "kpLogCategories.h" #include "commands/kpCommandHistory.h" #include "document/kpDocument.h" #include "layers/selections/text/kpTextSelection.h" #include "commands/tools/selection/text/kpToolTextBackspaceCommand.h" #include "commands/tools/selection/text/kpToolTextChangeStyleCommand.h" #include "commands/tools/selection/text/kpToolTextGiveContentCommand.h" #include "commands/tools/selection/kpToolSelectionCreateCommand.h" #include "environments/tools/selection/kpToolSelectionEnvironment.h" #include "commands/tools/selection/text/kpToolTextDeleteCommand.h" #include "commands/tools/selection/text/kpToolTextEnterCommand.h" #include "commands/tools/selection/text/kpToolTextInsertCommand.h" #include "widgets/toolbars/options/kpToolWidgetOpaqueOrTransparent.h" #include "views/kpView.h" #include "views/manager/kpViewManager.h" #include // protected bool kpToolText::shouldChangeTextStyle () const { if (environ ()->settingTextStyle ()) { #if DEBUG_KP_TOOL_TEXT qCDebug(kpLogTools) << "\trecursion - abort setting text style: " - << environ ()->settingTextStyle () - << endl; + << environ ()->settingTextStyle (); #endif return false; } if (!document ()->textSelection ()) { #if DEBUG_KP_TOOL_TEXT qCDebug(kpLogTools) << "\tno text selection - abort setting text style"; #endif return false; } return true; } // protected void kpToolText::changeTextStyle (const QString &name, const kpTextStyle &newTextStyle, const kpTextStyle &oldTextStyle) { #if DEBUG_KP_TOOL_TEXT qCDebug(kpLogTools) << "kpToolText::changeTextStyle(" << name << ")"; #endif - if (hasBegunShape ()) + if (hasBegunShape ()) { endShape (currentPoint (), normalizedRect ()); + } commandHistory ()->addCommand ( new kpToolTextChangeStyleCommand ( name, newTextStyle, oldTextStyle, environ ()->commandEnvironment ())); } // protected slot virtual [base kpAbstractSelectionTool] void kpToolText::slotIsOpaqueChanged (bool isOpaque) { #if DEBUG_KP_TOOL_TEXT qCDebug(kpLogTools) << "kpToolText::slotIsOpaqueChanged()"; #endif - if (!shouldChangeTextStyle ()) + if (!shouldChangeTextStyle ()) { return; + } kpTextStyle newTextStyle = environ ()->textStyle (); kpTextStyle oldTextStyle = newTextStyle; oldTextStyle.setBackgroundOpaque (!isOpaque); changeTextStyle (newTextStyle.isBackgroundOpaque () ? i18n ("Text: Opaque Background") : i18n ("Text: Transparent Background"), newTextStyle, oldTextStyle); } // protected slot virtual [base kpTool] void kpToolText::slotColorsSwapped (const kpColor &newForegroundColor, const kpColor &newBackgroundColor) { #if DEBUG_KP_TOOL_TEXT qCDebug(kpLogTools) << "kpToolText::slotColorsSwapped()"; #endif - if (!shouldChangeTextStyle ()) + if (!shouldChangeTextStyle ()) { return; + } kpTextStyle newTextStyle = environ ()->textStyle (); kpTextStyle oldTextStyle = newTextStyle; oldTextStyle.setForegroundColor (newBackgroundColor); oldTextStyle.setBackgroundColor (newForegroundColor); changeTextStyle (i18n ("Text: Swap Colors"), newTextStyle, oldTextStyle); } // protected slot virtual [base kpTool] void kpToolText::slotForegroundColorChanged (const kpColor & /*color*/) { #if DEBUG_KP_TOOL_TEXT qCDebug(kpLogTools) << "kpToolText::slotForegroundColorChanged()"; #endif - if (!shouldChangeTextStyle ()) + if (!shouldChangeTextStyle ()) { return; + } kpTextStyle newTextStyle = environ ()->textStyle (); kpTextStyle oldTextStyle = newTextStyle; oldTextStyle.setForegroundColor (oldForegroundColor ()); changeTextStyle (i18n ("Text: Foreground Color"), newTextStyle, oldTextStyle); } // protected slot virtual [base kpAbstractSelectionTool] void kpToolText::slotBackgroundColorChanged (const kpColor & /*color*/) { #if DEBUG_KP_TOOL_TEXT qCDebug(kpLogTools) << "kpToolText::slotBackgroundColorChanged()"; #endif - if (!shouldChangeTextStyle ()) + if (!shouldChangeTextStyle ()) { return; + } kpTextStyle newTextStyle = environ ()->textStyle (); kpTextStyle oldTextStyle = newTextStyle; oldTextStyle.setBackgroundColor (oldBackgroundColor ()); changeTextStyle (i18n ("Text: Background Color"), newTextStyle, oldTextStyle); } // protected slot virtual [base kpAbstractSelectionTool] void kpToolText::slotColorSimilarityChanged (double, int) { // --- don't pass on event to kpAbstractSelectionTool which would have set the // SelectionTransparency - not relevant to the Text Tool --- } // public slot void kpToolText::slotFontFamilyChanged (const QString &fontFamily, const QString &oldFontFamily) { #if DEBUG_KP_TOOL_TEXT qCDebug(kpLogTools) << "kpToolText::slotFontFamilyChanged() new=" << fontFamily << " old=" - << oldFontFamily - << endl; + << oldFontFamily; #else (void) fontFamily; #endif - if (!shouldChangeTextStyle ()) + if (!shouldChangeTextStyle ()) { return; + } kpTextStyle newTextStyle = environ ()->textStyle (); // Figure out old text style. kpTextStyle oldTextStyle = newTextStyle; oldTextStyle.setFontFamily (oldFontFamily); changeTextStyle (i18n ("Text: Font"), newTextStyle, oldTextStyle); } // public slot void kpToolText::slotFontSizeChanged (int fontSize, int oldFontSize) { #if DEBUG_KP_TOOL_TEXT qCDebug(kpLogTools) << "kpToolText::slotFontSizeChanged() new=" << fontSize << " old=" - << oldFontSize - << endl; + << oldFontSize; #else (void) fontSize; #endif - if (!shouldChangeTextStyle ()) + if (!shouldChangeTextStyle ()) { return; + } kpTextStyle newTextStyle = environ ()->textStyle (); // Figure out old text style. kpTextStyle oldTextStyle = newTextStyle; oldTextStyle.setFontSize (oldFontSize); changeTextStyle (i18n ("Text: Font Size"), newTextStyle, oldTextStyle); } // public slot void kpToolText::slotBoldChanged (bool isBold) { #if DEBUG_KP_TOOL_TEXT qCDebug(kpLogTools) << "kpToolText::slotBoldChanged(" << isBold << ")"; #endif - if (!shouldChangeTextStyle ()) + if (!shouldChangeTextStyle ()) { return; + } kpTextStyle newTextStyle = environ ()->textStyle (); // Figure out old text style. kpTextStyle oldTextStyle = newTextStyle; oldTextStyle.setBold (!isBold); changeTextStyle (i18n ("Text: Bold"), newTextStyle, oldTextStyle); } // public slot void kpToolText::slotItalicChanged (bool isItalic) { #if DEBUG_KP_TOOL_TEXT qCDebug(kpLogTools) << "kpToolText::slotItalicChanged(" << isItalic << ")"; #endif - if (!shouldChangeTextStyle ()) + if (!shouldChangeTextStyle ()) { return; + } kpTextStyle newTextStyle = environ ()->textStyle (); // Figure out old text style. kpTextStyle oldTextStyle = newTextStyle; oldTextStyle.setItalic (!isItalic); changeTextStyle (i18n ("Text: Italic"), newTextStyle, oldTextStyle); } // public slot void kpToolText::slotUnderlineChanged (bool isUnderline) { #if DEBUG_KP_TOOL_TEXT qCDebug(kpLogTools) << "kpToolText::slotUnderlineChanged(" << isUnderline << ")"; #endif - if (!shouldChangeTextStyle ()) + if (!shouldChangeTextStyle ()) { return; + } kpTextStyle newTextStyle = environ ()->textStyle (); // Figure out old text style. kpTextStyle oldTextStyle = newTextStyle; oldTextStyle.setUnderline (!isUnderline); changeTextStyle (i18n ("Text: Underline"), newTextStyle, oldTextStyle); } // public slot void kpToolText::slotStrikeThruChanged (bool isStrikeThru) { #if DEBUG_KP_TOOL_TEXT qCDebug(kpLogTools) << "kpToolText::slotStrikeThruChanged(" << isStrikeThru << ")"; #endif - if (!shouldChangeTextStyle ()) + if (!shouldChangeTextStyle ()) { return; + } kpTextStyle newTextStyle = environ ()->textStyle (); // Figure out old text style. kpTextStyle oldTextStyle = newTextStyle; oldTextStyle.setStrikeThru (!isStrikeThru); changeTextStyle (i18n ("Text: Strike Through"), newTextStyle, oldTextStyle); } diff --git a/views/kpThumbnailView.cpp b/views/kpThumbnailView.cpp index 3f36897f..f459cf54 100644 --- a/views/kpThumbnailView.cpp +++ b/views/kpThumbnailView.cpp @@ -1,90 +1,88 @@ /* Copyright (c) 2003-2007 Clarence Dang All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #define DEBUG_KP_THUMBNAIL_VIEW 0 #include "views/kpThumbnailView.h" #include "kpLogCategories.h" kpThumbnailView::kpThumbnailView (kpDocument *document, kpToolToolBar *toolToolBar, kpViewManager *viewManager, kpView *buddyView, kpViewScrollableContainer *scrollableContainer, QWidget *parent) : kpView (document, toolToolBar, viewManager, buddyView, scrollableContainer, parent) { } -kpThumbnailView::~kpThumbnailView () -{ -} +kpThumbnailView::~kpThumbnailView () = default; // protected void kpThumbnailView::setMaskToCoverDocument () { qCDebug(kpLogViews) << "kpThumbnailView::setMaskToCoverDocument()" << " origin=" << origin () << " zoomedDoc: width=" << zoomedDocWidth () << " height=" << zoomedDocHeight (); setMask (QRegion (QRect (origin ().x (), origin ().y (), zoomedDocWidth (), zoomedDocHeight ()))); } // protected virtual [base kpView] void kpThumbnailView::resizeEvent (QResizeEvent *e) { // For QResizeEvent's, Qt already throws an entire widget repaint into // the event loop. So eat useless update() calls that can only slow // things down. // TODO: this doesn't seem to work. // Later: In Qt4, setUpdatesEnabled(true) calls update(). const bool oldIsUpdatesEnabled = updatesEnabled (); setUpdatesEnabled (false); { kpView::resizeEvent (e); adjustToEnvironment (); } setUpdatesEnabled (oldIsUpdatesEnabled); } diff --git a/views/kpUnzoomedThumbnailView.cpp b/views/kpUnzoomedThumbnailView.cpp index 32567734..740c758d 100644 --- a/views/kpUnzoomedThumbnailView.cpp +++ b/views/kpUnzoomedThumbnailView.cpp @@ -1,197 +1,204 @@ /* Copyright (c) 2003-2007 Clarence Dang All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #define DEBUG_KP_UNZOOMED_THUMBNAIL_VIEW 0 #include "views/kpUnzoomedThumbnailView.h" #include "kpLogCategories.h" #include "document/kpDocument.h" #include "views/manager/kpViewManager.h" #include "kpViewScrollableContainer.h" #include #include //--------------------------------------------------------------------- struct kpUnzoomedThumbnailViewPrivate { }; kpUnzoomedThumbnailView::kpUnzoomedThumbnailView ( kpDocument *document, kpToolToolBar *toolToolBar, kpViewManager *viewManager, kpView *buddyView, kpViewScrollableContainer *scrollableContainer, QWidget *parent) : kpThumbnailView (document, toolToolBar, viewManager, buddyView, scrollableContainer, parent), d (new kpUnzoomedThumbnailViewPrivate ()) { if (buddyViewScrollableContainer ()) { connect (buddyViewScrollableContainer(), &kpViewScrollableContainer::contentsMoved, this, &kpUnzoomedThumbnailView::adjustToEnvironment); } // Call to virtual function - this is why the class is sealed adjustToEnvironment (); } //--------------------------------------------------------------------- kpUnzoomedThumbnailView::~kpUnzoomedThumbnailView () { delete d; } //--------------------------------------------------------------------- // public virtual [base kpThumbnailView] QString kpUnzoomedThumbnailView::caption () const { return i18n ("Unzoomed Mode - Thumbnail"); } //--------------------------------------------------------------------- // public slot virtual [base kpView] void kpUnzoomedThumbnailView::adjustToEnvironment () { - if (!buddyView () || !buddyViewScrollableContainer () || !document ()) + if (!buddyView () || !buddyViewScrollableContainer () || !document ()) { return; + } const int scrollViewContentsX = buddyViewScrollableContainer()->horizontalScrollBar()->value(); const int scrollViewContentsY = buddyViewScrollableContainer ()->verticalScrollBar()->value(); #if 1 int x; if (document ()->width () > width ()) { x = static_cast (buddyView ()->transformViewToDocX (scrollViewContentsX)); const int rightMostAllowedX = qMax (0, document ()->width () - width ()); qCDebug(kpLogViews) << "\tdocX=" << x << " docWidth=" << document ()->width () - << " rightMostAllowedX=" << rightMostAllowedX - << endl; - if (x > rightMostAllowedX) + << " rightMostAllowedX=" << rightMostAllowedX; + if (x > rightMostAllowedX) { x = rightMostAllowedX; + } } // Thumbnail width <= doc width else { // Center X (rather than flush left to be consistent with // kpZoomedThumbnailView) x = -(width () - document ()->width ()) / 2; } int y; if (document ()->height () > height ()) { y = static_cast (buddyView ()->transformViewToDocY (scrollViewContentsY)); const int bottomMostAllowedY = qMax (0, document ()->height () - height ()); qCDebug(kpLogViews) << "\tdocY=" << y << " docHeight=" << document ()->height () - << " bottomMostAllowedY=" << bottomMostAllowedY - << endl; - if (y > bottomMostAllowedY) + << " bottomMostAllowedY=" << bottomMostAllowedY; + if (y > bottomMostAllowedY) { y = bottomMostAllowedY; + } } // Thumbnail height <= doc height else { // Center Y (rather than flush top to be consistent with // kpZoomedThumbnailView) y = -(height () - document ()->height ()) / 2; } // Prefer to keep visible area centred in thumbnail instead of flushed left. // Gives more editing context to the left and top. // But feels awkward for left-to-right users. So disabled for now. // Not totally tested. #else - if (!buddyViewScrollableContainer ()) + if (!buddyViewScrollableContainer ()) { return; + } QRect docRect = buddyView ()->transformViewToDoc ( QRect (buddyViewScrollableContainer ()->horizontalScrollBar()->value(), buddyViewScrollableContainer ()->verticalScrollBar()->value(), qMin (buddyView ()->width (), buddyViewScrollableContainer ()->viewport()->width ()), qMin (buddyView ()->height (), buddyViewScrollableContainer ()->viewport()->height ()))); x = docRect.x () - (width () - docRect.width ()) / 2; qCDebug(kpLogViews) << "\tnew suggest x=" << x; const int rightMostAllowedX = qMax (0, document ()->width () - width ()); - if (x < 0) + if (x < 0) { x = 0; - if (x > rightMostAllowedX) + } + if (x > rightMostAllowedX) { x = rightMostAllowedX; + } y = docRect.y () - (height () - docRect.height ()) / 2; qCDebug(kpLogViews) << "\tnew suggest y=" << y; const int bottomMostAllowedY = qMax (0, document ()->height () - height ()); - if (y < 0) + if (y < 0) { y = 0; - if (y > bottomMostAllowedY) + } + if (y > bottomMostAllowedY) { y = bottomMostAllowedY; + } #endif if (viewManager ()) { viewManager ()->setFastUpdates (); viewManager ()->setQueueUpdates (); } { // OPT: scrollView impl would be much, much faster setOrigin (QPoint (-x, -y)); setMaskToCoverDocument (); // Above might be a NOP even if e.g. doc size changed so force // update - if (viewManager ()) + if (viewManager ()) { viewManager ()->updateView (this); + } } if (viewManager ()) { viewManager ()->restoreQueueUpdates (); viewManager ()->restoreFastUpdates (); } } diff --git a/views/kpView.cpp b/views/kpView.cpp index 570f498e..872cb607 100644 --- a/views/kpView.cpp +++ b/views/kpView.cpp @@ -1,662 +1,669 @@ /* Copyright (c) 2003-2007 Clarence Dang Copyright (c) 2005 Kazuki Ohta Copyright (c) 2010 Tasuku Suzuki All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #define DEBUG_KP_VIEW 0 #define DEBUG_KP_VIEW_RENDERER ((DEBUG_KP_VIEW && 1) || 0) #include "kpView.h" #include "kpViewPrivate.h" #include #include #include #include #include #include #include "kpLogCategories.h" #include "kpDefs.h" #include "document/kpDocument.h" #include "layers/selections/text/kpTextSelection.h" #include "tools/kpTool.h" #include "widgets/toolbars/kpToolToolBar.h" #include "views/manager/kpViewManager.h" #include "kpViewScrollableContainer.h" //--------------------------------------------------------------------- // public static const int kpView::MinZoomLevel = 1; const int kpView::MaxZoomLevel = 3200; //--------------------------------------------------------------------- kpView::kpView (kpDocument *document, kpToolToolBar *toolToolBar, kpViewManager *viewManager, kpView *buddyView, kpViewScrollableContainer *scrollableContainer, QWidget *parent) : QWidget (parent), d (new kpViewPrivate ()) { d->document = document; d->toolToolBar = toolToolBar; d->viewManager = viewManager; d->buddyView = buddyView; d->scrollableContainer = scrollableContainer; d->hzoom = 100; d->vzoom = 100; d->origin = QPoint (0, 0); d->showGrid = false; d->isBuddyViewScrollableContainerRectangleShown = false; // Don't waste CPU drawing default background since its overridden by // our fully opaque drawing. In reality, this seems to make no // difference in performance. setAttribute(Qt::WA_OpaquePaintEvent, true); setFocusPolicy (Qt::WheelFocus); setMouseTracking (true); // mouseMoveEvent's even when no mousebtn down setAttribute (Qt::WA_KeyCompression, true); } //--------------------------------------------------------------------- kpView::~kpView () { setHasMouse (false); delete d; } //--------------------------------------------------------------------- // public kpDocument *kpView::document () const { return d->document; } //--------------------------------------------------------------------- // protected kpAbstractSelection *kpView::selection () const { return document () ? document ()->selection () : nullptr; } //--------------------------------------------------------------------- // protected kpTextSelection *kpView::textSelection () const { return document () ? document ()->textSelection () : nullptr; } //--------------------------------------------------------------------- // public kpToolToolBar *kpView::toolToolBar () const { return d->toolToolBar; } // protected kpTool *kpView::tool () const { return toolToolBar () ? toolToolBar ()->tool () : nullptr; } // public kpViewManager *kpView::viewManager () const { return d->viewManager; } // public kpView *kpView::buddyView () const { return d->buddyView; } // public kpViewScrollableContainer *kpView::buddyViewScrollableContainer () const { return (buddyView () ? buddyView ()->scrollableContainer () : nullptr); } // public kpViewScrollableContainer *kpView::scrollableContainer () const { return d->scrollableContainer; } // public -int kpView::zoomLevelX (void) const +int kpView::zoomLevelX () const { return d->hzoom; } // public -int kpView::zoomLevelY (void) const +int kpView::zoomLevelY () const { return d->vzoom; } // public virtual void kpView::setZoomLevel (int hzoom, int vzoom) { hzoom = qBound (MinZoomLevel, hzoom, MaxZoomLevel); vzoom = qBound (MinZoomLevel, vzoom, MaxZoomLevel); - if (hzoom == d->hzoom && vzoom == d->vzoom) + if (hzoom == d->hzoom && vzoom == d->vzoom) { return; + } d->hzoom = hzoom; d->vzoom = vzoom; - if (viewManager ()) + if (viewManager ()) { viewManager ()->updateView (this); + } emit zoomLevelChanged (hzoom, vzoom); } // public QPoint kpView::origin () const { return d->origin; } // public virtual void kpView::setOrigin (const QPoint &origin) { qCDebug(kpLogViews) << "kpView(" << objectName () << ")::setOrigin" << origin; if (origin == d->origin) { qCDebug(kpLogViews) << "\tNOP"; return; } d->origin = origin; - if (viewManager ()) + if (viewManager ()) { viewManager ()->updateView (this); + } emit originChanged (origin); } // public bool kpView::canShowGrid () const { // (minimum zoom level < 400% would probably be reported as a bug by // users who thought that the grid was a part of the image!) return ((zoomLevelX () >= 400 && zoomLevelX () % 100 == 0) && (zoomLevelY () >= 400 && zoomLevelY () % 100 == 0)); } // public bool kpView::isGridShown () const { return d->showGrid; } // public void kpView::showGrid (bool yes) { - if (d->showGrid == yes) + if (d->showGrid == yes) { return; + } - if (yes && !canShowGrid ()) + if (yes && !canShowGrid ()) { return; + } d->showGrid = yes; - if (viewManager ()) + if (viewManager ()) { viewManager ()->updateView (this); + } } // public bool kpView::isBuddyViewScrollableContainerRectangleShown () const { return d->isBuddyViewScrollableContainerRectangleShown; } // public void kpView::showBuddyViewScrollableContainerRectangle (bool yes) { - if (yes == d->isBuddyViewScrollableContainerRectangleShown) + if (yes == d->isBuddyViewScrollableContainerRectangleShown) { return; + } d->isBuddyViewScrollableContainerRectangleShown = yes; if (d->isBuddyViewScrollableContainerRectangleShown) { // Got these connect statements by analysing deps of // updateBuddyViewScrollableContainerRectangle() rect update code. connect (this, &kpView::zoomLevelChanged, this, &kpView::updateBuddyViewScrollableContainerRectangle); connect (this, &kpView::originChanged, this, &kpView::updateBuddyViewScrollableContainerRectangle); if (buddyViewScrollableContainer ()) { connect (buddyViewScrollableContainer (), &kpViewScrollableContainer::contentsMoved, this, &kpView::updateBuddyViewScrollableContainerRectangle); connect (buddyViewScrollableContainer (), &kpViewScrollableContainer::resized, this, &kpView::updateBuddyViewScrollableContainerRectangle); } if (buddyView ()) { connect (buddyView (), &kpView::zoomLevelChanged, this, &kpView::updateBuddyViewScrollableContainerRectangle); connect (buddyView (), &kpView::originChanged, this, &kpView::updateBuddyViewScrollableContainerRectangle); connect (buddyView (), static_cast(&kpView::sizeChanged), this, &kpView::updateBuddyViewScrollableContainerRectangle); } } else { disconnect (this, &kpView::zoomLevelChanged, this, &kpView::updateBuddyViewScrollableContainerRectangle); disconnect (this, &kpView::originChanged, this, &kpView::updateBuddyViewScrollableContainerRectangle); if (buddyViewScrollableContainer ()) { disconnect (buddyViewScrollableContainer (), &kpViewScrollableContainer::contentsMoved, this, &kpView::updateBuddyViewScrollableContainerRectangle); disconnect (buddyViewScrollableContainer (), &kpViewScrollableContainer::resized, this, &kpView::updateBuddyViewScrollableContainerRectangle); } if (buddyView ()) { disconnect (buddyView (), &kpView::zoomLevelChanged, this, &kpView::updateBuddyViewScrollableContainerRectangle); disconnect (buddyView (), &kpView::originChanged, this, &kpView::updateBuddyViewScrollableContainerRectangle); disconnect (buddyView (), static_cast(&kpView::sizeChanged), this, &kpView::updateBuddyViewScrollableContainerRectangle); } } updateBuddyViewScrollableContainerRectangle (); } // protected QRect kpView::buddyViewScrollableContainerRectangle () const { return d->buddyViewScrollableContainerRectangle; } // protected slot void kpView::updateBuddyViewScrollableContainerRectangle () { - if (viewManager ()) + if (viewManager ()) { viewManager ()->setQueueUpdates (); + } { if (d->buddyViewScrollableContainerRectangle.isValid ()) { if (viewManager ()) { // Erase last viewManager ()->updateViewRectangleEdges (this, d->buddyViewScrollableContainerRectangle); } } QRect newRect; if (isBuddyViewScrollableContainerRectangleShown () && buddyViewScrollableContainer () && buddyView ()) { QRect docRect = buddyView ()->transformViewToDoc ( QRect (buddyViewScrollableContainer ()->horizontalScrollBar()->value(), buddyViewScrollableContainer ()->verticalScrollBar()->value(), qMin (buddyView ()->width (), buddyViewScrollableContainer ()->viewport()->width ()), qMin (buddyView ()->height (), buddyViewScrollableContainer ()->viewport()->height ()))); QRect viewRect = this->transformDocToView (docRect); // (Surround the area of interest by moving outwards by 1 pixel in each // direction - don't overlap area) newRect = QRect (viewRect.x () - 1, viewRect.y () - 1, viewRect.width () + 2, viewRect.height () + 2); } else { newRect = QRect (); } if (newRect != d->buddyViewScrollableContainerRectangle) { // (must set before updateView() for paintEvent() to see new // rect) d->buddyViewScrollableContainerRectangle = newRect; if (newRect.isValid ()) { if (viewManager ()) { viewManager ()->updateViewRectangleEdges (this, d->buddyViewScrollableContainerRectangle); } } } } - if (viewManager ()) + if (viewManager ()) { viewManager ()->restoreQueueUpdates (); + } } //--------------------------------------------------------------------- // public double kpView::transformViewToDocX (double viewX) const { return (viewX - origin ().x ()) * 100.0 / zoomLevelX (); } //--------------------------------------------------------------------- // public double kpView::transformViewToDocY (double viewY) const { return (viewY - origin ().y ()) * 100.0 / zoomLevelY (); } //--------------------------------------------------------------------- // public QPoint kpView::transformViewToDoc (const QPoint &viewPoint) const { - return QPoint (static_cast (transformViewToDocX (viewPoint.x ())), - static_cast (transformViewToDocY (viewPoint.y ()))); + return {static_cast (transformViewToDocX (viewPoint.x ())), + static_cast (transformViewToDocY (viewPoint.y ()))}; } //--------------------------------------------------------------------- // public QRect kpView::transformViewToDoc (const QRect &viewRect) const { if (zoomLevelX () == 100 && zoomLevelY () == 100) { - return QRect (viewRect.x () - origin ().x (), - viewRect.y () - origin ().y (), - viewRect.width (), - viewRect.height ()); + return {viewRect.x () - origin ().x (), viewRect.y () - origin ().y (), + viewRect.width (), viewRect.height ()}; } - else - { - const QPoint docTopLeft = transformViewToDoc (viewRect.topLeft ()); - // (don't call transformViewToDoc[XY]() - need to round up dimensions) - const int docWidth = qRound (double (viewRect.width ()) * 100.0 / double (zoomLevelX ())); - const int docHeight = qRound (double (viewRect.height ()) * 100.0 / double (zoomLevelY ())); + const QPoint docTopLeft = transformViewToDoc (viewRect.topLeft ()); + + // (don't call transformViewToDoc[XY]() - need to round up dimensions) + const auto docWidth = qRound (double (viewRect.width ()) * 100.0 / double (zoomLevelX ())); + const auto docHeight = qRound (double (viewRect.height ()) * 100.0 / double (zoomLevelY ())); + + // (like QWMatrix::Areas) + return {docTopLeft.x (), docTopLeft.y (), docWidth, docHeight}; - // (like QWMatrix::Areas) - return QRect (docTopLeft.x (), docTopLeft.y (), docWidth, docHeight); - } } //--------------------------------------------------------------------- // public double kpView::transformDocToViewX (double docX) const { return (docX * zoomLevelX () / 100.0) + origin ().x (); } // public double kpView::transformDocToViewY (double docY) const { return (docY * zoomLevelY () / 100.0) + origin ().y (); } // public QPoint kpView::transformDocToView (const QPoint &docPoint) const { - return QPoint (static_cast (transformDocToViewX (docPoint.x ())), - static_cast (transformDocToViewY (docPoint.y ()))); + return {static_cast (transformDocToViewX (docPoint.x ())), + static_cast (transformDocToViewY (docPoint.y ()))}; } // public QRect kpView::transformDocToView (const QRect &docRect) const { if (zoomLevelX () == 100 && zoomLevelY () == 100) { - return QRect (docRect.x () + origin ().x (), - docRect.y () + origin ().y (), - docRect.width (), - docRect.height ()); + return {docRect.x () + origin ().x (), docRect.y () + origin ().y (), + docRect.width (), docRect.height ()}; } - else - { - const QPoint viewTopLeft = transformDocToView (docRect.topLeft ()); - // (don't call transformDocToView[XY]() - need to round up dimensions) - const int viewWidth = qRound (double (docRect.width ()) * double (zoomLevelX ()) / 100.0); - const int viewHeight = qRound (double (docRect.height ()) * double (zoomLevelY ()) / 100.0); + const QPoint viewTopLeft = transformDocToView (docRect.topLeft ()); - // (like QWMatrix::Areas) - return QRect (viewTopLeft.x (), viewTopLeft.y (), viewWidth, viewHeight); - } + // (don't call transformDocToView[XY]() - need to round up dimensions) + const int viewWidth = qRound (double (docRect.width ()) * double (zoomLevelX ()) / 100.0); + const int viewHeight = qRound (double (docRect.height ()) * double (zoomLevelY ()) / 100.0); + + // (like QWMatrix::Areas) + return QRect (viewTopLeft.x (), viewTopLeft.y (), viewWidth, viewHeight); } // public QPoint kpView::transformViewToOtherView (const QPoint &viewPoint, const kpView *otherView) { - if (this == otherView) + if (this == otherView) { return viewPoint; + } const double docX = transformViewToDocX (viewPoint.x ()); const double docY = transformViewToDocY (viewPoint.y ()); const double otherViewX = otherView->transformDocToViewX (docX); const double otherViewY = otherView->transformDocToViewY (docY); - return QPoint (static_cast (otherViewX), static_cast (otherViewY)); + return {static_cast (otherViewX), static_cast (otherViewY)}; } // public int kpView::zoomedDocWidth () const { return document () ? document ()->width () * zoomLevelX () / 100 : 0; } // public int kpView::zoomedDocHeight () const { return document () ? document ()->height () * zoomLevelY () / 100 : 0; } // public void kpView::setHasMouse (bool yes) { kpViewManager *vm = viewManager (); - if (!vm) + if (!vm) { return; + } qCDebug(kpLogViews) << "kpView(" << objectName () << ")::setHasMouse(" << yes << ") existing viewUnderCursor=" - << (vm->viewUnderCursor () ? vm->viewUnderCursor ()->objectName () : "(none)") - << endl; - if (yes && vm->viewUnderCursor () != this) + << (vm->viewUnderCursor () ? vm->viewUnderCursor ()->objectName () : "(none)"); + if (yes && vm->viewUnderCursor () != this) { vm->setViewUnderCursor (this); - else if (!yes && vm->viewUnderCursor () == this) + } + else if (!yes && vm->viewUnderCursor () == this) { vm->setViewUnderCursor (nullptr); + } } //--------------------------------------------------------------------- // public void kpView::addToQueuedArea (const QRegion ®ion) { qCDebug(kpLogViews) << "kpView(" << objectName () << ")::addToQueuedArea() already=" << d->queuedUpdateArea << " - plus - " << region; d->queuedUpdateArea += region; } //--------------------------------------------------------------------- // public void kpView::addToQueuedArea (const QRect &rect) { qCDebug(kpLogViews) << "kpView(" << objectName () << ")::addToQueuedArea() already=" << d->queuedUpdateArea << " - plus - " << rect; d->queuedUpdateArea += rect; } //--------------------------------------------------------------------- // public void kpView::invalidateQueuedArea () { qCDebug(kpLogViews) << "kpView::invalidateQueuedArea()"; d->queuedUpdateArea = QRegion (); } //--------------------------------------------------------------------- // public void kpView::updateQueuedArea () { kpViewManager *vm = viewManager (); qCDebug(kpLogViews) << "kpView(" << objectName () << ")::updateQueuedArea() vm=" << (bool) vm << " queueUpdates=" << (vm && vm->queueUpdates ()) << " fastUpdates=" << (vm && vm->fastUpdates ()) << " area=" << d->queuedUpdateArea; - if (!vm) + if (!vm) { return; + } - if (vm->queueUpdates ()) + if (vm->queueUpdates ()) { return; + } - if (!d->queuedUpdateArea.isEmpty ()) + if (!d->queuedUpdateArea.isEmpty ()) { vm->updateView (this, d->queuedUpdateArea); + } invalidateQueuedArea (); } //--------------------------------------------------------------------- // public QPoint kpView::mouseViewPoint (const QPoint &returnViewPoint) const { - if (returnViewPoint != KP_INVALID_POINT) + if (returnViewPoint != KP_INVALID_POINT) { return returnViewPoint; - else - { - // TODO: I don't think this is right for the main view since that's - // inside the scrollview (which can scroll). - return mapFromGlobal (QCursor::pos ()); } + + // TODO: I don't think this is right for the main view since that's + // inside the scrollview (which can scroll). + return mapFromGlobal (QCursor::pos ()); } //--------------------------------------------------------------------- // public virtual QVariant kpView::inputMethodQuery (Qt::InputMethodQuery query) const { qCDebug(kpLogViews) << "kpView(" << objectName () << ")::inputMethodQuery()"; QVariant ret; switch (query) { case Qt::ImMicroFocus: { QRect r = d->viewManager->textCursorRect (); r.setTopLeft (r.topLeft () + origin ()); r.setHeight (r.height() + 2); r = transformDocToView (r); ret = r; break; } case Qt::ImFont: { if (textSelection ()) { ret = textSelection ()->textStyle ().font (); } break; } default: break; } return ret; } //--------------------------------------------------------------------- diff --git a/views/kpView_Events.cpp b/views/kpView_Events.cpp index 51e421c4..8c3b9376 100644 --- a/views/kpView_Events.cpp +++ b/views/kpView_Events.cpp @@ -1,228 +1,239 @@ /* Copyright (c) 2003-2007 Clarence Dang Copyright (c) 2005 Kazuki Ohta Copyright (c) 2010 Tasuku Suzuki All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include "views/kpView.h" #include "kpViewPrivate.h" #include "kpLogCategories.h" #include #include #include "tools/kpTool.h" //--------------------------------------------------------------------- // protected virtual [base QWidget] void kpView::mouseMoveEvent (QMouseEvent *e) { qCDebug(kpLogViews) << "kpView(" << objectName () << ")::mouseMoveEvent (" << e->x () << "," << e->y () << ")"; // TODO: This is wrong if you leaveEvent the mainView by mouseMoving on the // mainView, landing on top of the thumbnailView cleverly put on top // of the mainView. setHasMouse (rect ().contains (e->pos ())); - if (tool ()) + if (tool ()) { tool ()->mouseMoveEvent (e); + } e->accept (); } // protected virtual [base QWidget] void kpView::mousePressEvent (QMouseEvent *e) { qCDebug(kpLogViews) << "kpView(" << objectName () << ")::mousePressEvent (" << e->x () << "," << e->y () << ")"; setHasMouse (true); - if (tool ()) + if (tool ()) { tool ()->mousePressEvent (e); + } e->accept (); } //--------------------------------------------------------------------- // protected virtual [base QWidget] void kpView::mouseReleaseEvent (QMouseEvent *e) { qCDebug(kpLogViews) << "kpView(" << objectName () << ")::mouseReleaseEvent (" << e->x () << "," << e->y () << ")"; setHasMouse (rect ().contains (e->pos ())); - if (tool ()) + if (tool ()) { tool ()->mouseReleaseEvent (e); + } e->accept (); } //--------------------------------------------------------------------- // public virtual [base QWidget] void kpView::wheelEvent (QWheelEvent *e) { - if (tool ()) + if (tool ()) { tool ()->wheelEvent (e); + } } //--------------------------------------------------------------------- // protected virtual [base QWidget] void kpView::keyPressEvent (QKeyEvent *e) { qCDebug(kpLogViews) << "kpView(" << objectName () << ")::keyPressEvent()" << e->text(); - if (tool ()) + if (tool ()) { tool ()->keyPressEvent (e); + } e->accept (); } //--------------------------------------------------------------------- // protected virtual [base QWidget] void kpView::keyReleaseEvent (QKeyEvent *e) { qCDebug(kpLogViews) << "kpView(" << objectName () << ")::keyReleaseEvent()"; - if (tool ()) + if (tool ()) { tool ()->keyReleaseEvent (e); + } e->accept (); } //--------------------------------------------------------------------- // protected virtual [base QWidget] void kpView::inputMethodEvent (QInputMethodEvent *e) { qCDebug(kpLogViews) << "kpView(" << objectName () << ")::inputMethodEvent()"; - if (tool ()) + if (tool ()) { tool ()->inputMethodEvent (e); + } e->accept (); } // protected virtual [base QWidget] bool kpView::event (QEvent *e) { qCDebug(kpLogViews) << "kpView::event() invoking kpTool::event()"; if (tool () && tool ()->viewEvent (e)) { qCDebug(kpLogViews) << "\tkpView::event() - tool said eat event, ret true"; return true; } qCDebug(kpLogViews) << "\tkpView::event() - no tool or said false, call QWidget::event()"; return QWidget::event (e); } // protected virtual [base QWidget] void kpView::focusInEvent (QFocusEvent *e) { qCDebug(kpLogViews) << "kpView(" << objectName () << ")::focusInEvent()"; - if (tool ()) + if (tool ()) { tool ()->focusInEvent (e); + } } // protected virtual [base QWidget] void kpView::focusOutEvent (QFocusEvent *e) { qCDebug(kpLogViews) << "kpView(" << objectName () << ")::focusOutEvent()"; - if (tool ()) + if (tool ()) { tool ()->focusOutEvent (e); + } } // protected virtual [base QWidget] void kpView::enterEvent (QEvent *e) { qCDebug(kpLogViews) << "kpView(" << objectName () << ")::enterEvent()"; // Don't call setHasMouse(true) as it displays the brush cursor (if // active) when dragging open a menu and then dragging // past the extents of the menu due to Qt sending us an EnterEvent. // We're already covered by MouseMoveEvent anyway. // // But disabling this causes a more serious problem: RMB on a text // box and Esc. We have no other reliable way to determine if the // mouse is still above the view (user could have moved mouse out // while RMB menu was up) and hence the cursor is not updated. setHasMouse (true); - if (tool ()) + if (tool ()) { tool ()->enterEvent (e); + } } // protected virtual [base QWidget] void kpView::leaveEvent (QEvent *e) { qCDebug(kpLogViews) << "kpView(" << objectName () << ")::leaveEvent()"; setHasMouse (false); - if (tool ()) + if (tool ()) { tool ()->leaveEvent (e); + } } // protected virtual [base QWidget] void kpView::dragEnterEvent (QDragEnterEvent *) { qCDebug(kpLogViews) << "kpView(" << objectName () << ")::dragEnterEvent()"; setHasMouse (true); } // protected virtual [base QWidget] void kpView::dragLeaveEvent (QDragLeaveEvent *) { qCDebug(kpLogViews) << "kpView(" << objectName () << ")::dragLeaveEvent"; setHasMouse (false); } // protected virtual [base QWidget] void kpView::resizeEvent (QResizeEvent *e) { qCDebug(kpLogViews) << "kpView(" << objectName () << ")::resizeEvent(" << e->size () << " vs actual=" << size () << ") old=" << e->oldSize (); QWidget::resizeEvent (e); emit sizeChanged (width (), height ()); emit sizeChanged (size ()); } diff --git a/views/kpView_Paint.cpp b/views/kpView_Paint.cpp index 4420dc0d..70704951 100644 --- a/views/kpView_Paint.cpp +++ b/views/kpView_Paint.cpp @@ -1,558 +1,574 @@ /* Copyright (c) 2003-2007 Clarence Dang All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #define DEBUG_KP_VIEW 0 #define DEBUG_KP_VIEW_RENDERER ((DEBUG_KP_VIEW && 1) || 0) #include "views/kpView.h" #include "kpViewPrivate.h" #include #include #include #include #include "kpLogCategories.h" #include "layers/selections/kpAbstractSelection.h" #include "imagelib/kpColor.h" #include "document/kpDocument.h" #include "layers/tempImage/kpTempImage.h" #include "layers/selections/text/kpTextSelection.h" #include "views/manager/kpViewManager.h" #include "kpViewScrollableContainer.h" //--------------------------------------------------------------------- // protected QRect kpView::paintEventGetDocRect (const QRect &viewRect) const { qCDebug(kpLogViews) << "kpView::paintEventGetDocRect(" << viewRect << ")"; QRect docRect; // From the "we aren't sure whether to round up or round down" department: - if (zoomLevelX () < 100 || zoomLevelY () < 100) + if (zoomLevelX () < 100 || zoomLevelY () < 100) { docRect = transformViewToDoc (viewRect); + } else { // think of a grid - you need to fully cover the zoomed-in pixels // when docRect is zoomed back to the view later docRect = QRect (transformViewToDoc (viewRect.topLeft ()), // round down transformViewToDoc (viewRect.bottomRight ())); // round down } if (zoomLevelX () % 100 || zoomLevelY () % 100) { // at least round up the bottom-right point and deal with matrix weirdness: // - helpful because it ensures we at least cover the required area // at e.g. 67% or 573% docRect.setBottomRight (docRect.bottomRight () + QPoint (2, 2)); } qCDebug(kpLogViews) << "\tdocRect=" << docRect; kpDocument *doc = document (); if (doc) { docRect = docRect.intersected (doc->rect ()); #if DEBUG_KP_VIEW_RENDERER && 1 qCDebug(kpLogViews) << "\tintersected with doc=" << docRect; #endif } return docRect; } //--------------------------------------------------------------------- // public static void kpView::drawTransparentBackground (QPainter *painter, const QPoint &patternOrigin, const QRect &viewRect, bool isPreview) { qCDebug(kpLogViews) << "kpView::drawTransparentBackground() patternOrigin=" << patternOrigin << " viewRect=" << viewRect << " isPreview=" << isPreview; const int cellSize = !isPreview ? 16 : 10; // TODO: % is unpredictable with negatives. int starty = viewRect.y (); - if ((starty - patternOrigin.y ()) % cellSize) + if ((starty - patternOrigin.y ()) % cellSize) { starty -= ((starty - patternOrigin.y ()) % cellSize); + } int startx = viewRect.x (); - if ((startx - patternOrigin.x ()) % cellSize) + if ((startx - patternOrigin.x ()) % cellSize) { startx -= ((startx - patternOrigin.x ()) % cellSize); + } qCDebug(kpLogViews) << "\tstartXY=" << QPoint (startx, starty); painter->save (); // Clip to as we may draw outside it on all sides. painter->setClipRect (viewRect, Qt::IntersectClip/*honor existing clip*/); for (int y = starty; y <= viewRect.bottom (); y += cellSize) { for (int x = startx; x <= viewRect.right (); x += cellSize) { bool parity = ((x - patternOrigin.x ()) / cellSize + (y - patternOrigin.y ()) / cellSize) % 2; QColor col; if (parity) { - if (!isPreview) + if (!isPreview) { col = QColor (213, 213, 213); - else + } + else { col = QColor (224, 224, 224); + } } - else + else { col = Qt::white; + } painter->fillRect (x, y, cellSize, cellSize, col); } } painter->restore (); } //--------------------------------------------------------------------- // protected void kpView::paintEventDrawCheckerBoard (QPainter *painter, const QRect &viewRect) { qCDebug(kpLogViews) << "kpView(" << objectName () << ")::paintEventDrawCheckerBoard(viewRect=" << viewRect - << ") origin=" << origin () << endl; + << ") origin=" << origin (); kpDocument *doc = document (); - if (!doc) + if (!doc) { return; + } QPoint patternOrigin = origin (); if (scrollableContainer ()) { qCDebug(kpLogViews) << "\tscrollableContainer: contents[XY]=" << QPoint (scrollableContainer ()->horizontalScrollBar()->value (), scrollableContainer ()->verticalScrollBar()->value ()); // Make checkerboard appear static relative to the scroll view. // This makes it more obvious that any visible bits of the // checkboard represent transparent pixels and not gray and white // squares. patternOrigin = QPoint (scrollableContainer ()->horizontalScrollBar()->value(), scrollableContainer ()->verticalScrollBar()->value()); qCDebug(kpLogViews) << "\t\tpatternOrigin=" << patternOrigin; } // TODO: this static business doesn't work yet patternOrigin = QPoint (0, 0); drawTransparentBackground (painter, patternOrigin, viewRect); } //--------------------------------------------------------------------- // protected void kpView::paintEventDrawSelection (QImage *destPixmap, const QRect &docRect) { qCDebug(kpLogViews) << "kpView::paintEventDrawSelection() docRect=" << docRect; kpDocument *doc = document (); if (!doc) { qCDebug(kpLogViews) << "\tno doc - abort"; return; } kpAbstractSelection *sel = doc->selection (); if (!sel) { qCDebug(kpLogViews) << "\tno sel - abort"; return; } // // Draw selection pixmap (if there is one) // qCDebug(kpLogViews) << "\tdraw sel pixmap @ " << sel->topLeft (); sel->paint (destPixmap, docRect); // // Draw selection border // kpViewManager *vm = viewManager (); qCDebug(kpLogViews) << "\tsel border visible=" - << vm->selectionBorderVisible () - << endl; + << vm->selectionBorderVisible (); if (vm->selectionBorderVisible ()) { sel->paintBorder (destPixmap, docRect, vm->selectionBorderFinished ()); } // // Draw text cursor // // TODO: It would be nice to display the text cursor even if it's not // within the text box (this can happen if the text box is too // small for the text it contains). // // However, too much selection repaint code assumes that it // only paints inside its kpAbstractSelection::boundingRect(). - kpTextSelection *textSel = dynamic_cast (sel); + auto *textSel = dynamic_cast (sel); if (textSel && vm->textCursorEnabled () && (vm->textCursorBlinkState () || // For the current main window: // As long as _any_ view has focus, blink _all_ views not just the // one with focus. !vm->hasAViewWithFocus ())) // sync: call will break when vm is not held by 1 mainWindow { QRect rect = vm->textCursorRect (); rect = rect.intersected (textSel->textAreaRect ()); if (!rect.isEmpty ()) { kpPixmapFX::fillRect(destPixmap, rect.x () - docRect.x (), rect.y () - docRect.y (), rect.width (), rect.height (), kpColor::LightGray, kpColor::DarkGray); } } } //--------------------------------------------------------------------- // protected void kpView::paintEventDrawSelectionResizeHandles (const QRect &clipRect) { qCDebug(kpLogViews) << "kpView::paintEventDrawSelectionResizeHandles(" - << clipRect << ")" << endl; + << clipRect << ")"; if (!selectionLargeEnoughToHaveResizeHandles ()) { qCDebug(kpLogViews) << "\tsel not large enough to have resize handles"; return; } kpViewManager *vm = viewManager (); if (!vm || !vm->selectionBorderVisible () || !vm->selectionBorderFinished ()) { qCDebug(kpLogViews) << "\tsel border not visible or not finished"; return; } const QRect selViewRect = selectionViewRect (); qCDebug(kpLogViews) << "\tselViewRect=" << selViewRect; if (!selViewRect.intersects (clipRect)) { qCDebug(kpLogViews) << "\tdoesn't intersect viewRect"; return; } QRegion selResizeHandlesRegion = selectionResizeHandlesViewRegion (true/*for renderer*/); qCDebug(kpLogViews) << "\tsel resize handles view region=" << selResizeHandlesRegion; QPainter painter(this); painter.setPen(Qt::black); painter.setBrush(Qt::cyan); - foreach (const QRect &r, selResizeHandlesRegion.rects()) + for (const auto &r : selResizeHandlesRegion.rects()) { painter.drawRect(r); + } } //--------------------------------------------------------------------- // protected void kpView::paintEventDrawTempImage (QImage *destPixmap, const QRect &docRect) { kpViewManager *vm = viewManager (); - if (!vm) + if (!vm) { return; + } const kpTempImage *tpi = vm->tempImage (); qCDebug(kpLogViews) << "kpView::paintEventDrawTempImage() tempImage=" << tpi << " isVisible=" << (tpi ? tpi->isVisible (vm) : false); - if (!tpi || !tpi->isVisible (vm)) + if (!tpi || !tpi->isVisible (vm)) { return; + } tpi->paint (destPixmap, docRect); } //--------------------------------------------------------------------- // protected void kpView::paintEventDrawGridLines (QPainter *painter, const QRect &viewRect) { int hzoomMultiple = zoomLevelX () / 100; int vzoomMultiple = zoomLevelY () / 100; painter->setPen(Qt::gray); // horizontal lines int starty = viewRect.top(); - if (starty % vzoomMultiple) + if (starty % vzoomMultiple) { starty = (starty + vzoomMultiple) / vzoomMultiple * vzoomMultiple; + } - for (int y = starty; y <= viewRect.bottom(); y += vzoomMultiple) + for (int y = starty; y <= viewRect.bottom(); y += vzoomMultiple) { painter->drawLine(viewRect.left(), y, viewRect.right(), y); + } // vertical lines int startx = viewRect.left(); - if (startx % hzoomMultiple) + if (startx % hzoomMultiple) { startx = (startx + hzoomMultiple) / hzoomMultiple * hzoomMultiple; + } - for (int x = startx; x <= viewRect.right(); x += hzoomMultiple) + for (int x = startx; x <= viewRect.right(); x += hzoomMultiple) { painter->drawLine(x, viewRect.top (), x, viewRect.bottom()); + } } //--------------------------------------------------------------------- // This is called "_Unclipped" because it may draw outside of // . // // There are 2 reasons for doing so: // // A. If, for instance: // // 1. = QRect (0, 0, 2, 3) [top-left of the view] // 2. zoomLevelX() == 800 // 3. zoomLevelY() == 800 // // Then, the local variable will be QRect (0, 0, 1, 1). // When the part of the document corresponding to // (a single document pixel) is drawn with QPainter::scale(), the // view rectangle QRect (0, 0, 7, 7) will be overwritten due to the // 8x zoom. This view rectangle is bigger than . // // We can't use QPainter::setClipRect() since it is buggy in Qt 4.3.1 // and clips too many pixels when used in combination with scale() // [qt-bugs@trolltech.com issue N181038]. ==> MK 10.2.2011 - fixed since Qt-4.4.4 // // B. paintEventGetDocRect() may, by design, return a larger document // rectangle than what corresponds to, if the zoom levels // are not perfectly divisible by 100. // // This over-drawing is dangerous -- see the comments in paintEvent(). // This over-drawing is only safe from Qt's perspective since Qt // automatically clips all drawing in paintEvent() (which calls us) to // QPaintEvent::region(). void kpView::paintEventDrawDoc_Unclipped (const QRect &viewRect) { QTime timer; timer.start (); qCDebug(kpLogViews) << "\tviewRect=" << viewRect; kpViewManager *vm = viewManager (); const kpDocument *doc = document (); Q_ASSERT (vm); Q_ASSERT (doc); - if (viewRect.isEmpty ()) + if (viewRect.isEmpty ()) { return; + } QRect docRect = paintEventGetDocRect (viewRect); qCDebug(kpLogViews) << "\tdocRect=" << docRect; QPainter painter (this); //painter.setCompositionMode(QPainter::CompositionMode_Source); QImage docPixmap; bool tempImageWillBeRendered = false; // LOTODO: I think being empty would be a bug. if (!docRect.isEmpty ()) { docPixmap = doc->getImageAt (docRect); qCDebug(kpLogViews) << "\tdocPixmap.hasAlphaChannel()=" - << docPixmap.hasAlphaChannel () << endl; + << docPixmap.hasAlphaChannel (); tempImageWillBeRendered = (!doc->selection () && vm->tempImage () && vm->tempImage ()->isVisible (vm) && docRect.intersects (vm->tempImage ()->rect ())); qCDebug(kpLogViews) << "\ttempImageWillBeRendered=" << tempImageWillBeRendered << " (sel=" << doc->selection () << " tempImage=" << vm->tempImage () << " tempImage.isVisible=" << (vm->tempImage () ? vm->tempImage ()->isVisible (vm) : false) << " docRect.intersects(tempImage.rect)=" << (vm->tempImage () ? docRect.intersects (vm->tempImage ()->rect ()) : false) << ")"; } // // Draw checkboard for transparent images and/or views with borders // if (docPixmap.hasAlphaChannel() || (tempImageWillBeRendered && vm->tempImage ()->paintMayAddMask ())) { paintEventDrawCheckerBoard (&painter, viewRect); } if (!docRect.isEmpty ()) { // // Draw docPixmap + tempImage // if (doc->selection ()) { paintEventDrawSelection (&docPixmap, docRect); } else if (tempImageWillBeRendered) { paintEventDrawTempImage (&docPixmap, docRect); } qCDebug(kpLogViews) << "\torigin=" << origin (); // Blit scaled version of docPixmap + tempImage. QTime scaleTimer; scaleTimer.start (); // This is the only troublesome part of the method that draws unclipped. painter.translate (origin ().x (), origin ().y ()); painter.scale (double (zoomLevelX ()) / 100.0, double (zoomLevelY ()) / 100.0); painter.drawImage (docRect, docPixmap); //painter.resetMatrix (); // back to 1-1 scaling qCDebug(kpLogViews) << "\tscale time=" << scaleTimer.elapsed (); } // if (!docRect.isEmpty ()) { qCDebug(kpLogViews) << "\tdrawDocRect done in: " << timer.restart () << "ms"; } //--------------------------------------------------------------------- // protected virtual [base QWidget] void kpView::paintEvent (QPaintEvent *e) { // sync: kpViewPrivate // WARNING: document(), viewManager() and friends might be 0 in this method. // TODO: I'm not 100% convinced that we always check if their friends are 0. QTime timer; timer.start (); kpViewManager *vm = viewManager (); qCDebug(kpLogViews) << "kpView(" << objectName () << ")::paintEvent() vm=" << (bool) vm << " queueUpdates=" << (vm && vm->queueUpdates ()) << " fastUpdates=" << (vm && vm->fastUpdates ()) << " viewRect=" << e->rect () << " topLeft=" << QPoint (x (), y ()); - if (!vm) + if (!vm) { return; + } if (vm->queueUpdates ()) { // OPT: if this update was due to the document, // use document coordinates (in case of a zoom change in // which view coordinates become out of date) addToQueuedArea (e->region ()); return; } kpDocument *doc = document (); - if (!doc) + if (!doc) { return; + } // It seems that e->region() is already clipped by Qt to the visible // part of the view (which could be quite small inside a scrollview). - QRegion viewRegion = e->region (); + const auto& viewRegion = e->region (); QVector rects = viewRegion.rects (); qCDebug(kpLogViews) << "\t#rects = " << rects.count (); // Draw all of the requested regions of the document _before_ drawing // the grid lines, buddy rectangle and selection resize handles. // This ordering is important since paintEventDrawDoc_Unclipped() // may draw outside of the view rectangle passed to it. // // To illustrate this, suppose we changed each iteration of the loop // to call paintEventDrawDoc_Unclipped() _and_ then, // paintEventDrawGridLines(). If there are 2 or more iterations of this // loop, paintEventDrawDoc_Unclipped() in one iteration may draw over // parts of nearby grid lines (which were drawn in a previous iteration) // with document pixels. Those grid line parts are probably not going to // be redrawn, so will appear to be missing. - foreach (const QRect &r, rects) + for (const auto &r : rects) { paintEventDrawDoc_Unclipped (r); } // // Draw Grid Lines // if ( isGridShown() ) { QPainter painter(this); - foreach (const QRect &r, rects) + for (const auto &r : rects) paintEventDrawGridLines(&painter, r); } const QRect r = buddyViewScrollableContainerRectangle(); if ( !r.isEmpty() ) { QPainter painter(this); painter.setPen(QPen(Qt::lightGray, 1/*width*/, Qt::DotLine)); painter.setBackground(Qt::darkGray); painter.setBackgroundMode(Qt::OpaqueMode); painter.drawRect(r.x(), r.y(), r.width() - 1, r.height() - 1); } if (doc->selection ()) { // Draw resize handles on top of possible grid lines paintEventDrawSelectionResizeHandles (e->rect ()); } qCDebug(kpLogViews) << "\tall done in: " << timer.restart () << "ms"; } diff --git a/views/kpView_Selections.cpp b/views/kpView_Selections.cpp index b829e175..ce28d399 100644 --- a/views/kpView_Selections.cpp +++ b/views/kpView_Selections.cpp @@ -1,335 +1,353 @@ /* Copyright (c) 2003-2007 Clarence Dang All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include "views/kpView.h" #include "kpViewPrivate.h" #include "layers/selections/kpAbstractSelection.h" #include "layers/selections/text/kpTextSelection.h" #include "tools/kpTool.h" #include "kpLogCategories.h" // public QRect kpView::selectionViewRect () const { return selection () ? transformDocToView (selection ()->boundingRect ()) : QRect (); } // public QPoint kpView::mouseViewPointRelativeToSelection (const QPoint &viewPoint) const { - if (!selection ()) + if (!selection ()) { return KP_INVALID_POINT; + } return mouseViewPoint (viewPoint) - transformDocToView (selection ()->topLeft ()); } // public bool kpView::mouseOnSelection (const QPoint &viewPoint) const { const QRect selViewRect = selectionViewRect (); - if (!selViewRect.isValid ()) + if (!selViewRect.isValid ()) { return false; + } return selViewRect.contains (mouseViewPoint (viewPoint)); } // public int kpView::textSelectionMoveBorderAtomicSize () const { - if (!textSelection ()) + if (!textSelection ()) { return 0; + } return qMax (4, zoomLevelX () / 100); } // public bool kpView::mouseOnSelectionToMove (const QPoint &viewPoint) const { - if (!mouseOnSelection (viewPoint)) + if (!mouseOnSelection (viewPoint)) { return false; + } - if (!textSelection ()) + if (!textSelection ()) { return true; + } - if (mouseOnSelectionResizeHandle (viewPoint)) + if (mouseOnSelectionResizeHandle (viewPoint)) { return false; + } const QPoint viewPointRelSel = mouseViewPointRelativeToSelection (viewPoint); // Middle point should always be selectable const QPoint selCenterDocPoint = selection ()->boundingRect ().center (); if (tool () && tool ()->calculateCurrentPoint () == selCenterDocPoint) { return false; } const int atomicSize = textSelectionMoveBorderAtomicSize (); const QRect selViewRect = selectionViewRect (); return (viewPointRelSel.x () < atomicSize || viewPointRelSel.x () >= selViewRect.width () - atomicSize || viewPointRelSel.y () < atomicSize || viewPointRelSel.y () >= selViewRect.height () - atomicSize); } //--------------------------------------------------------------------- // protected bool kpView::selectionLargeEnoughToHaveResizeHandlesIfAtomicSize (int atomicSize) const { - if (!selection ()) + if (!selection ()) { return false; + } const QRect selViewRect = selectionViewRect (); return (selViewRect.width () >= atomicSize * 5 || selViewRect.height () >= atomicSize * 5); } //--------------------------------------------------------------------- // public int kpView::selectionResizeHandleAtomicSize () const { int atomicSize = qMin (13, qMax (9, zoomLevelX () / 100)); while (atomicSize > 0 && !selectionLargeEnoughToHaveResizeHandlesIfAtomicSize (atomicSize)) { atomicSize--; } return atomicSize; } //--------------------------------------------------------------------- // public bool kpView::selectionLargeEnoughToHaveResizeHandles () const { return (selectionResizeHandleAtomicSize () > 0); } //--------------------------------------------------------------------- // public QRegion kpView::selectionResizeHandlesViewRegion (bool forRenderer) const { const int atomicLength = selectionResizeHandleAtomicSize (); - if (atomicLength <= 0) + if (atomicLength <= 0) { return QRegion (); + } // HACK: At low zoom (e.g. 100%), resize handles will probably be too // big and overlap text / cursor / too much of selection. // // So limit the _visual_ size of handles at low zoom. The // handles' grab area remains the same for usability; so yes, // there are a few pixels that don't look grabable but they are. // // The real solution is to be able to partially render the // handles outside of the selection view rect. If not possible, // at least for text boxes, render text on top of handles. int normalAtomicLength = atomicLength; int vertEdgeAtomicLength = atomicLength; if (forRenderer && selection ()) { if (zoomLevelX () <= 150) { - if (normalAtomicLength > 1) + if (normalAtomicLength > 1) { normalAtomicLength--; + } - if (vertEdgeAtomicLength > 1) + if (vertEdgeAtomicLength > 1) { vertEdgeAtomicLength--; + } } // 1 line of text? if (textSelection () && textSelection ()->textLines ().size () == 1) { - if (zoomLevelX () <= 150) + if (zoomLevelX () <= 150) { vertEdgeAtomicLength = qMin (vertEdgeAtomicLength, qMax (2, zoomLevelX () / 100)); - else if (zoomLevelX () <= 250) + } + else if (zoomLevelX () <= 250) { vertEdgeAtomicLength = qMin (vertEdgeAtomicLength, qMax (3, zoomLevelX () / 100)); + } } } const QRect selViewRect = selectionViewRect (); QRegion ret; // top left ret += QRect(0, 0, normalAtomicLength, normalAtomicLength); // top middle ret += QRect((selViewRect.width() - normalAtomicLength) / 2, 0, normalAtomicLength, normalAtomicLength); // top right ret += QRect(selViewRect.width() - normalAtomicLength - 1, 0, normalAtomicLength, normalAtomicLength); // left middle ret += QRect(0, (selViewRect.height() - vertEdgeAtomicLength) / 2, vertEdgeAtomicLength, vertEdgeAtomicLength); // right middle ret += QRect(selViewRect.width() - vertEdgeAtomicLength - 1, (selViewRect.height() - vertEdgeAtomicLength) / 2, vertEdgeAtomicLength, vertEdgeAtomicLength); // bottom left ret += QRect(0, selViewRect.height() - normalAtomicLength - 1, normalAtomicLength, normalAtomicLength); // bottom middle ret += QRect((selViewRect.width() - normalAtomicLength) / 2, selViewRect.height() - normalAtomicLength - 1, normalAtomicLength, normalAtomicLength); // bottom right ret += QRect(selViewRect.width() - normalAtomicLength - 1, selViewRect.height() - normalAtomicLength - 1, normalAtomicLength, normalAtomicLength); ret.translate (selViewRect.x (), selViewRect.y ()); ret = ret.intersected (selViewRect); return ret; } //--------------------------------------------------------------------- // public // REFACTOR: use QFlags as the return type for better type safety. int kpView::mouseOnSelectionResizeHandle (const QPoint &viewPoint) const { qCDebug(kpLogViews) << "kpView::mouseOnSelectionResizeHandle(viewPoint=" << viewPoint << ")"; if (!mouseOnSelection (viewPoint)) { qCDebug(kpLogViews) << "\tmouse not on sel"; return 0; } const QRect selViewRect = selectionViewRect (); qCDebug(kpLogViews) << "\tselViewRect=" << selViewRect; const int atomicLength = selectionResizeHandleAtomicSize (); qCDebug(kpLogViews) << "\tatomicLength=" << atomicLength; if (atomicLength <= 0) { qCDebug(kpLogViews) << "\tsel not large enough to have resize handles"; // Want to make it possible to move a small selection return 0; } const QPoint viewPointRelSel = mouseViewPointRelativeToSelection (viewPoint); qCDebug(kpLogViews) << "\tviewPointRelSel=" << viewPointRelSel; #define LOCAL_POINT_IN_BOX_AT(x,y) \ QRect ((x), (y), atomicLength, atomicLength).contains (viewPointRelSel) // Favour the bottom & right and the corners. if (LOCAL_POINT_IN_BOX_AT (selViewRect.width () - atomicLength, selViewRect.height () - atomicLength)) { return kpView::Bottom | kpView::Right; } - else if (LOCAL_POINT_IN_BOX_AT (selViewRect.width () - atomicLength, 0)) + + if (LOCAL_POINT_IN_BOX_AT (selViewRect.width () - atomicLength, 0)) { return kpView::Top | kpView::Right; } - else if (LOCAL_POINT_IN_BOX_AT (0, selViewRect.height () - atomicLength)) + + if (LOCAL_POINT_IN_BOX_AT (0, selViewRect.height () - atomicLength)) { return kpView::Bottom | kpView::Left; } - else if (LOCAL_POINT_IN_BOX_AT (0, 0)) + + if (LOCAL_POINT_IN_BOX_AT (0, 0)) { return kpView::Top | kpView::Left; } - else if (LOCAL_POINT_IN_BOX_AT (selViewRect.width () - atomicLength, + + if (LOCAL_POINT_IN_BOX_AT (selViewRect.width () - atomicLength, (selViewRect.height () - atomicLength) / 2)) { return kpView::Right; } - else if (LOCAL_POINT_IN_BOX_AT ((selViewRect.width () - atomicLength) / 2, + + if (LOCAL_POINT_IN_BOX_AT ((selViewRect.width () - atomicLength) / 2, selViewRect.height () - atomicLength)) { return kpView::Bottom; } - else if (LOCAL_POINT_IN_BOX_AT ((selViewRect.width () - atomicLength) / 2, 0)) + + if (LOCAL_POINT_IN_BOX_AT ((selViewRect.width () - atomicLength) / 2, 0)) { return kpView::Top; } - else if (LOCAL_POINT_IN_BOX_AT (0, (selViewRect.height () - atomicLength) / 2)) + + if (LOCAL_POINT_IN_BOX_AT (0, (selViewRect.height () - atomicLength) / 2)) { return kpView::Left; } - else - { - qCDebug(kpLogViews) << "\tnot on sel resize handle"; - return 0; - } + + qCDebug(kpLogViews) << "\tnot on sel resize handle"; + return 0; + #undef LOCAL_POINT_IN_BOX_AT } // public bool kpView::mouseOnSelectionToSelectText (const QPoint &viewPoint) const { qCDebug(kpLogViews) << "kpView::mouseOnSelectionToSelectText(viewPoint=" << viewPoint << ")"; if (!mouseOnSelection (viewPoint)) { qCDebug(kpLogViews) << "\tmouse non on sel"; return false; } if (!textSelection ()) { qCDebug(kpLogViews) << "\tsel not text"; return false; } qCDebug(kpLogViews) << "\tmouse on sel: to move=" << mouseOnSelectionToMove () << " to resize=" << mouseOnSelectionResizeHandle (); return (!mouseOnSelectionToMove (viewPoint) && !mouseOnSelectionResizeHandle (viewPoint)); } diff --git a/views/kpZoomedThumbnailView.cpp b/views/kpZoomedThumbnailView.cpp index ce7218dd..7f5dcf59 100644 --- a/views/kpZoomedThumbnailView.cpp +++ b/views/kpZoomedThumbnailView.cpp @@ -1,123 +1,126 @@ /* Copyright (c) 2003-2007 Clarence Dang All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include "views/kpZoomedThumbnailView.h" #include "kpLogCategories.h" #include "document/kpDocument.h" #include "views/manager/kpViewManager.h" #include "kpLogCategories.h" #include //-------------------------------------------------------------------------------- kpZoomedThumbnailView::kpZoomedThumbnailView (kpDocument *document, kpToolToolBar *toolToolBar, kpViewManager *viewManager, kpView *buddyView, kpViewScrollableContainer *scrollableContainer, QWidget *parent ) : kpThumbnailView (document, toolToolBar, viewManager, buddyView, scrollableContainer, parent) { // Call to virtual function - this is why the class is sealed adjustToEnvironment (); } -kpZoomedThumbnailView::~kpZoomedThumbnailView () -{ -} +kpZoomedThumbnailView::~kpZoomedThumbnailView () = default; // public virtual [base kpThumbnailView] QString kpZoomedThumbnailView::caption () const { return i18n ("%1% - Thumbnail", zoomLevelX ()); } // public slot virtual [base kpView] void kpZoomedThumbnailView::adjustToEnvironment () { - if (!document ()) + if (!document ()) { return; + } qCDebug(kpLogViews) << "\tdoc: width=" << document ()->width () << " height=" << document ()->height (); if (document ()->width () <= 0 || document ()->height () <= 0) { qCCritical(kpLogViews) << "kpZoomedThumbnailView::adjustToEnvironment() doc:" << " width=" << document ()->width () - << " height=" << document ()->height () - << endl; + << " height=" << document ()->height (); return; } int hzoom = qMax (1, width () * 100 / document ()->width ()); int vzoom = qMax (1, height () * 100 / document ()->height ()); // keep aspect ratio - if (hzoom < vzoom) + if (hzoom < vzoom) { vzoom = hzoom; - else + } + else { hzoom = vzoom; + } qCDebug(kpLogViews) << "\tproposed zoom=" << hzoom; if (hzoom > 100 || vzoom > 100) { qCDebug(kpLogViews) << "\twon't magnify - setting zoom to 100%"; hzoom = 100; vzoom = 100; } - if (viewManager ()) + if (viewManager ()) { viewManager ()->setQueueUpdates (); + } { setZoomLevel (hzoom, vzoom); setOrigin (QPoint ((width () - zoomedDocWidth ()) / 2, (height () - zoomedDocHeight ()) / 2)); setMaskToCoverDocument (); - if (viewManager ()) + if (viewManager ()) { viewManager ()->updateView (this); + } } - if (viewManager ()) + if (viewManager ()) { viewManager ()->restoreQueueUpdates (); + } } diff --git a/views/kpZoomedView.cpp b/views/kpZoomedView.cpp index 704010aa..4c471a3f 100644 --- a/views/kpZoomedView.cpp +++ b/views/kpZoomedView.cpp @@ -1,90 +1,90 @@ /* Copyright (c) 2003-2007 Clarence Dang All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #define DEBUG_KP_ZOOMED_VIEW 0 #include "views/kpZoomedView.h" #include "kpLogCategories.h" #include "document/kpDocument.h" #include "views/kpView.h" #include "views/manager/kpViewManager.h" kpZoomedView::kpZoomedView (kpDocument *document, kpToolToolBar *toolToolBar, kpViewManager *viewManager, kpView *buddyView, kpViewScrollableContainer *scrollableContainer, QWidget *parent) : kpView (document, toolToolBar, viewManager, buddyView, scrollableContainer, parent) { // Call to virtual function - this is why the class is sealed adjustToEnvironment (); } -kpZoomedView::~kpZoomedView () -{ -} +kpZoomedView::~kpZoomedView () = default; // public virtual [base kpView] void kpZoomedView::setZoomLevel (int hzoom, int vzoom) { - if (viewManager ()) + if (viewManager ()) { viewManager ()->setQueueUpdates (); + } { kpView::setZoomLevel (hzoom, vzoom); adjustToEnvironment (); } - if (viewManager ()) + if (viewManager ()) { viewManager ()->restoreQueueUpdates (); + } } // public slot virtual [base kpView] void kpZoomedView::adjustToEnvironment () { if (document ()) { // TODO: use zoomedDocWidth() & zoomedDocHeight()? resize (static_cast (transformDocToViewX (document ()->width ())), static_cast (transformDocToViewY (document ()->height ()))); } } diff --git a/views/manager/kpViewManager.cpp b/views/manager/kpViewManager.cpp index adf19315..c81fafdf 100644 --- a/views/manager/kpViewManager.cpp +++ b/views/manager/kpViewManager.cpp @@ -1,349 +1,359 @@ /* Copyright (c) 2003-2007 Clarence Dang All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #define DEBUG_KP_VIEW_MANAGER 0 #include "views/manager/kpViewManager.h" #include "kpViewManagerPrivate.h" #include #include #include #include "kpLogCategories.h" #include "kpDefs.h" #include "document/kpDocument.h" #include "mainWindow/kpMainWindow.h" #include "layers/tempImage/kpTempImage.h" #include "layers/selections/text/kpTextSelection.h" #include "tools/kpTool.h" #include "views/kpView.h" //--------------------------------------------------------------------- kpViewManager::kpViewManager (kpMainWindow *mainWindow) : d (new kpViewManagerPrivate ()) { Q_ASSERT (mainWindow); d->mainWindow = mainWindow; // d->views d->viewUnderCursor = nullptr; // d->cursor d->tempImage = nullptr; d->selectionBorderVisible = false; d->selectionBorderFinished = false; d->textCursorBlinkTimer = nullptr; d->textCursorRow = -1; d->textCursorCol = -1; d->textCursorBlinkState = true; d->queueUpdatesCounter = d->fastUpdatesCounter = 0; d->inputMethodEnabled = false; } //--------------------------------------------------------------------- kpViewManager::~kpViewManager () { unregisterAllViews (); delete d->tempImage; delete d; } //--------------------------------------------------------------------- // private kpDocument *kpViewManager::document () const { return d->mainWindow->document (); } //--------------------------------------------------------------------- // public void kpViewManager::registerView (kpView *view) { qCDebug(kpLogViews) << "kpViewManager::registerView (" << view << ")"; Q_ASSERT (view); Q_ASSERT (!d->views.contains (view)); qCDebug(kpLogViews) << "\tadded view"; view->setCursor (d->cursor); d->views.append (view); } //--------------------------------------------------------------------- // public void kpViewManager::unregisterView (kpView *view) { Q_ASSERT (view); Q_ASSERT (d->views.contains (view)); - if (view == d->viewUnderCursor) + if (view == d->viewUnderCursor) { d->viewUnderCursor = nullptr; + } view->unsetCursor (); d->views.removeAll (view); } //--------------------------------------------------------------------- // public void kpViewManager::unregisterAllViews () { d->views.clear (); } //--------------------------------------------------------------------- // public kpView *kpViewManager::viewUnderCursor (bool usingQt) const { if (!usingQt) { Q_ASSERT (!d->viewUnderCursor || d->views.contains (d->viewUnderCursor)); return d->viewUnderCursor; } - else + + + for (QLinkedList ::const_iterator it = d->views.begin (); + it != d->views.end (); + ++it) { - for (QLinkedList ::const_iterator it = d->views.begin (); - it != d->views.end (); - ++it) - { - if ((*it)->underMouse ()) - return (*it); + if ((*it)->underMouse ()) { + return (*it); } - - return nullptr; } + + return nullptr; } //--------------------------------------------------------------------- // public void kpViewManager::setViewUnderCursor (kpView *view) { qCDebug(kpLogViews) << "kpViewManager::setViewUnderCursor (" << (view ? view->objectName () : "(none)") << ")" - << " old=" << (d->viewUnderCursor ? d->viewUnderCursor->objectName () : "(none)") - << endl; - if (view == d->viewUnderCursor) + << " old=" << (d->viewUnderCursor ? d->viewUnderCursor->objectName () : "(none)"); + if (view == d->viewUnderCursor) { return; + } d->viewUnderCursor = view; - if (d->viewUnderCursor) + if (d->viewUnderCursor) { d->viewUnderCursor->setAttribute (Qt::WA_InputMethodEnabled, d->inputMethodEnabled); + } if (!d->viewUnderCursor) { // Hide the brush if the mouse cursor just left the view. if (d->tempImage && d->tempImage->isBrush ()) { qCDebug(kpLogViews) << "\thiding brush pixmap since cursor left view"; updateViews (d->tempImage->rect ()); } } else { if (d->mainWindow->tool ()) { qCDebug(kpLogViews) << "\tnotify tool that something changed below cursor"; d->mainWindow->tool ()->somethingBelowTheCursorChanged (); } } } //--------------------------------------------------------------------- // public bool kpViewManager::hasAViewWithFocus () const { for (QLinkedList ::const_iterator it = d->views.begin (); it != d->views.end (); ++it) { - if ((*it)->isActiveWindow ()) + if ((*it)->isActiveWindow ()) { return true; + } } return false; } //--------------------------------------------------------------------- // public void kpViewManager::setCursor (const QCursor &cursor) { for (QLinkedList ::const_iterator it = d->views.begin (); it != d->views.end (); ++it) { (*it)->setCursor (cursor); } d->cursor = cursor; } //--------------------------------------------------------------------- // public void kpViewManager::unsetCursor () { for (QLinkedList ::const_iterator it = d->views.begin (); it != d->views.end (); ++it) { (*it)->unsetCursor (); } d->cursor = QCursor (); } //--------------------------------------------------------------------- // public const kpTempImage *kpViewManager::tempImage () const { return d->tempImage; } //--------------------------------------------------------------------- // public void kpViewManager::setTempImage (const kpTempImage &tempImage) { qCDebug(kpLogViews) << "kpViewManager::setTempImage(isBrush=" << tempImage.isBrush () << ",topLeft=" << tempImage.topLeft () << ",image.rect=" << tempImage.image ().rect () - << ")" << endl; + << ")"; QRect oldRect; if (d->tempImage) { oldRect = d->tempImage->rect (); delete d->tempImage; d->tempImage = nullptr; } d->tempImage = new kpTempImage (tempImage); setQueueUpdates (); { - if (oldRect.isValid ()) + if (oldRect.isValid ()) { updateViews (oldRect); + } updateViews (d->tempImage->rect ()); } restoreQueueUpdates (); } //--------------------------------------------------------------------- // public void kpViewManager::invalidateTempImage () { - if (!d->tempImage) + if (!d->tempImage) { return; + } QRect oldRect = d->tempImage->rect (); delete d->tempImage; d->tempImage = nullptr; updateViews (oldRect); } //--------------------------------------------------------------------- // public bool kpViewManager::selectionBorderVisible () const { return d->selectionBorderVisible; } //--------------------------------------------------------------------- // public void kpViewManager::setSelectionBorderVisible (bool yes) { - if (d->selectionBorderVisible == yes) + if (d->selectionBorderVisible == yes) { return; + } d->selectionBorderVisible = yes; - if (document ()->selection ()) + if (document ()->selection ()) { updateViews (document ()->selection ()->boundingRect ()); + } } //--------------------------------------------------------------------- // public bool kpViewManager::selectionBorderFinished () const { return d->selectionBorderFinished; } //--------------------------------------------------------------------- // public void kpViewManager::setSelectionBorderFinished (bool yes) { - if (d->selectionBorderFinished == yes) + if (d->selectionBorderFinished == yes) { return; + } d->selectionBorderFinished = yes; - if (document ()->selection ()) + if (document ()->selection ()) { updateViews (document ()->selection ()->boundingRect ()); + } } //--------------------------------------------------------------------- void kpViewManager::setInputMethodEnabled (bool inputMethodEnabled) { d->inputMethodEnabled = inputMethodEnabled; - if (d->viewUnderCursor) + if (d->viewUnderCursor) { d->viewUnderCursor->setAttribute (Qt::WA_InputMethodEnabled, inputMethodEnabled); + } } diff --git a/views/manager/kpViewManager_TextCursor.cpp b/views/manager/kpViewManager_TextCursor.cpp index dccc9293..91230644 100644 --- a/views/manager/kpViewManager_TextCursor.cpp +++ b/views/manager/kpViewManager_TextCursor.cpp @@ -1,224 +1,230 @@ // TODO: This is bad design as it's easy to get out of sync with the selection. // e.g. You could have textCursorEnabled() but no text selection or // vice versa. And the cursor could be outside of the selection. // // In fact, our text commands momentarily violate these "invariants": // // 1. A text box with content must have the cursor somewhere on an // existing text line, possibly 1 position after the last character // on a line. // // 2. Special case: A content-less text box (i.e. no text lines) must // have the cursor at (0,0). // // We don't assert-check them at the moment. We should when we fix // the design so that the invariants are always maintained. /* Copyright (c) 2003-2007 Clarence Dang Copyright (c) 2005 Kazuki Ohta Copyright (c) 2010 Tasuku Suzuki All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #define DEBUG_KP_VIEW_MANAGER 0 #include "kpViewManager.h" #include "kpViewManagerPrivate.h" #include #include #include //#include #include "kpLogCategories.h" #include "kpDefs.h" #include "document/kpDocument.h" #include "mainWindow/kpMainWindow.h" #include "layers/tempImage/kpTempImage.h" #include "layers/selections/text/kpTextSelection.h" #include "tools/kpTool.h" #include "views/kpView.h" // public bool kpViewManager::textCursorEnabled () const { return static_cast (d->textCursorBlinkTimer); } // public void kpViewManager::setTextCursorEnabled (bool yes) { qCDebug(kpLogViews) << "kpViewManager::setTextCursorEnabled(" << yes << ")"; - if (yes == textCursorEnabled ()) + if (yes == textCursorEnabled ()) { return; + } delete d->textCursorBlinkTimer; d->textCursorBlinkTimer = nullptr; setFastUpdates (); setQueueUpdates (); { if (yes) { d->textCursorBlinkTimer = new QTimer (this); d->textCursorBlinkTimer->setSingleShot (true); connect (d->textCursorBlinkTimer, &QTimer::timeout, this, &kpViewManager::slotTextCursorBlink); d->textCursorBlinkState = true; slotTextCursorBlink (); } else { d->textCursorBlinkState = false; updateTextCursor (); } } restoreQueueUpdates (); restoreFastUpdates (); } // public bool kpViewManager::textCursorBlinkState () const { return d->textCursorBlinkState; } // public void kpViewManager::setTextCursorBlinkState (bool on) { - if (on == d->textCursorBlinkState) + if (on == d->textCursorBlinkState) { return; + } d->textCursorBlinkState = on; updateTextCursor (); } // public int kpViewManager::textCursorRow () const { return d->textCursorRow; } // public int kpViewManager::textCursorCol () const { return d->textCursorCol; } // public void kpViewManager::setTextCursorPosition (int row, int col) { - if (row == d->textCursorRow && col == d->textCursorCol) + if (row == d->textCursorRow && col == d->textCursorCol) { return; + } setFastUpdates (); setQueueUpdates (); { // Clear the old cursor. d->textCursorBlinkState = false; updateTextCursor (); d->textCursorRow = row; d->textCursorCol = col; // Render the new cursor. d->textCursorBlinkState = true; updateTextCursor (); } restoreQueueUpdates (); restoreFastUpdates (); } // public QRect kpViewManager::textCursorRect () const { kpTextSelection *textSel = document ()->textSelection (); - if (!textSel) - return QRect (); + if (!textSel) { + return {}; + } QPoint topLeft = textSel->pointForTextRowCol (d->textCursorRow, d->textCursorCol); if (topLeft == KP_INVALID_POINT) { // Text cursor row/col hasn't been specified yet? - if (textSel->hasContent ()) - return QRect (); + if (textSel->hasContent ()) { + return {}; + } // Empty text box should still display a cursor so that the user // knows where typed text will go. topLeft = textSel->textAreaRect ().topLeft (); } Q_ASSERT (topLeft != KP_INVALID_POINT); - return QRect (topLeft.x (), topLeft.y (), - 1, textSel->textStyle ().fontMetrics ().height ()); + return {topLeft.x (), topLeft.y (), + 1, textSel->textStyle ().fontMetrics ().height ()}; } // protected void kpViewManager::updateTextCursor () { qCDebug(kpLogViews) << "kpViewManager::updateTextCursor()"; const QRect r = textCursorRect (); - if (!r.isValid ()) + if (!r.isValid ()) { return; + } setFastUpdates (); { // If !textCursorEnabled(), this will clear. updateViews (r); } restoreFastUpdates (); } // protected slot void kpViewManager::slotTextCursorBlink () { qCDebug(kpLogViews) << "kpViewManager::slotTextCursorBlink() cursorBlinkState=" - << d->textCursorBlinkState << endl; + << d->textCursorBlinkState; if (d->textCursorBlinkTimer) { // (single shot) d->textCursorBlinkTimer->start (QApplication::cursorFlashTime () / 2); } updateTextCursor (); // TODO: Shouldn't this be done _before_ updating the text cursor // because textCursorBlinkState() is supposed to reflect what // updateTextCursor() just rendered, until the next timer tick? d->textCursorBlinkState = !d->textCursorBlinkState; } diff --git a/views/manager/kpViewManager_ViewUpdates.cpp b/views/manager/kpViewManager_ViewUpdates.cpp index 1e196c98..40e63c9e 100644 --- a/views/manager/kpViewManager_ViewUpdates.cpp +++ b/views/manager/kpViewManager_ViewUpdates.cpp @@ -1,228 +1,235 @@ /* Copyright (c) 2003-2007 Clarence Dang All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #define DEBUG_KP_VIEW_MANAGER 0 #include "views/manager/kpViewManager.h" #include "kpViewManagerPrivate.h" #include #include #include #include "kpLogCategories.h" #include "kpDefs.h" #include "document/kpDocument.h" #include "mainWindow/kpMainWindow.h" #include "layers/tempImage/kpTempImage.h" #include "layers/selections/text/kpTextSelection.h" #include "tools/kpTool.h" #include "views/kpView.h" // public slot bool kpViewManager::queueUpdates () const { return (d->queueUpdatesCounter > 0); } // public slot void kpViewManager::setQueueUpdates () { d->queueUpdatesCounter++; qCDebug(kpLogViews) << "kpViewManager::setQueueUpdates() counter=" << d->queueUpdatesCounter; } // public slot void kpViewManager::restoreQueueUpdates () { d->queueUpdatesCounter--; qCDebug(kpLogViews) << "kpViewManager::restoreQueueUpdates() counter=" - << d->queueUpdatesCounter << endl; + << d->queueUpdatesCounter; Q_ASSERT (d->queueUpdatesCounter >= 0); if (d->queueUpdatesCounter == 0) { for (QLinkedList ::const_iterator it = d->views.begin (); it != d->views.end (); ++it) { (*it)->updateQueuedArea (); } } } // public slot bool kpViewManager::fastUpdates () const { return (d->fastUpdatesCounter > 0); } // public slot void kpViewManager::setFastUpdates () { d->fastUpdatesCounter++; qCDebug(kpLogViews) << "kpViewManager::setFastUpdates() counter=" << d->fastUpdatesCounter; } // public slot void kpViewManager::restoreFastUpdates () { d->fastUpdatesCounter--; qCDebug(kpLogViews) << "kpViewManager::restoreFastUpdates() counter=" << d->fastUpdatesCounter; Q_ASSERT (d->fastUpdatesCounter >= 0); } // public slot void kpViewManager::updateView (kpView *v) { updateView (v, QRect (0, 0, v->width (), v->height ())); } // public slot void kpViewManager::updateView (kpView *v, const QRect &viewRect) { if (!queueUpdates ()) { - if (fastUpdates ()) + if (fastUpdates ()) { v->repaint (viewRect); - else + } + else { v->update (viewRect); + } } - else + else { v->addToQueuedArea (viewRect); + } } // public slot void kpViewManager::updateView (kpView *v, int x, int y, int w, int h) { updateView (v, QRect (x, y, w, h)); } // public slot void kpViewManager::updateView (kpView *v, const QRegion &viewRegion) { if (!queueUpdates ()) { - if (fastUpdates ()) + if (fastUpdates ()) { v->repaint (viewRegion); - else + } + else { v->update (viewRegion.boundingRect ()); + } } - else + else { v->addToQueuedArea (viewRegion); + } } // public slot void kpViewManager::updateViewRectangleEdges (kpView *v, const QRect &viewRect) { - if (viewRect.height () <= 0 || viewRect.width () <= 0) + if (viewRect.height () <= 0 || viewRect.width () <= 0) { return; + } // Top line updateView (v, QRect (viewRect.x (), viewRect.y (), viewRect.width (), 1)); if (viewRect.height () >= 2) { // Bottom line updateView (v, QRect (viewRect.x (), viewRect.bottom (), viewRect.width (), 1)); if (viewRect.height () > 2) { // Left line updateView (v, QRect (viewRect.x (), viewRect.y () + 1, 1, viewRect.height () - 2)); if (viewRect.width () >= 2) { // Right line updateView (v, QRect (viewRect.right (), viewRect.y () + 1, 1, viewRect.height () - 2)); } } } } // public slot void kpViewManager::updateViews (const QRect &docRect) { qCDebug(kpLogViews) << "kpViewManager::updateViews (" << docRect << ")"; for (QLinkedList ::const_iterator it = d->views.begin (); it != d->views.end (); ++it) { kpView *view = *it; if (view->zoomLevelX () % 100 == 0 && view->zoomLevelY () % 100 == 0) { qCDebug(kpLogViews) << "\t\tviewRect=" << view->transformDocToView (docRect); updateView (view, view->transformDocToView (docRect)); } else { QRect viewRect = view->transformDocToView (docRect); int diff = qRound (double (qMax (view->zoomLevelX (), view->zoomLevelY ())) / 100.0) + 1; QRect newRect = QRect (viewRect.x () - diff, viewRect.y () - diff, viewRect.width () + 2 * diff, viewRect.height () + 2 * diff) .intersected (QRect (0, 0, view->width (), view->height ())); qCDebug(kpLogViews) << "\t\tviewRect (+compensate)=" << newRect; updateView (view, newRect); } } } // public slot void kpViewManager::adjustViewsToEnvironment () { qCDebug(kpLogViews) << "kpViewManager::adjustViewsToEnvironment()" << " numViews=" << d->views.count (); for (QLinkedList ::const_iterator it = d->views.begin (); it != d->views.end (); ++it) { kpView *view = *it; view->adjustToEnvironment (); } } diff --git a/widgets/colorSimilarity/kpColorSimilarityCubeRenderer.cpp b/widgets/colorSimilarity/kpColorSimilarityCubeRenderer.cpp index 18500348..a732b49d 100644 --- a/widgets/colorSimilarity/kpColorSimilarityCubeRenderer.cpp +++ b/widgets/colorSimilarity/kpColorSimilarityCubeRenderer.cpp @@ -1,227 +1,229 @@ /* Copyright (c) 2003-2007 Clarence Dang All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #define DEBUG_KP_COLOR_SIMILARITY_CUBE 0 #include "kpColorSimilarityCubeRenderer.h" #include #include #include #include "kpLogCategories.h" #include "widgets/colorSimilarity/kpColorSimilarityHolder.h" #include "kpDefs.h" //--------------------------------------------------------------------- static QColor Color (int redOrGreenOrBlue, int baseBrightness, double colorSimilarity, int similarityDirection, int highlight) { int brightness = int (baseBrightness + similarityDirection * 0.5 * colorSimilarity * kpColorSimilarityHolder::ColorCubeDiagonalDistance); - if (brightness < 0) + if (brightness < 0) { brightness = 0; - else if (brightness > 255) + } + else if (brightness > 255) { brightness = 255; + } switch (redOrGreenOrBlue) { default: - case 0: return QColor (brightness, highlight, highlight); - case 1: return QColor (highlight, brightness, highlight); - case 2: return QColor (highlight, highlight, brightness); + case 0: return {brightness, highlight, highlight}; + case 1: return {highlight, brightness, highlight}; + case 2: return {highlight, highlight, brightness}; } } //--------------------------------------------------------------------- static QPointF PointBetween(const QPointF &p, const QPointF &q) { - return QPointF((p.x() + q.x()) / 2.0, (p.y() + q.y()) / 2.0); + return {(p.x() + q.x()) / 2.0, (p.y() + q.y()) / 2.0}; } //--------------------------------------------------------------------- static void DrawQuadrant(QPaintDevice *target, const QColor &col, const QPointF &p1, const QPointF &p2, const QPointF &p3, const QPointF &pointNotOnOutline) { QPolygonF points (4); points [0] = p1; points [1] = p2; points [2] = p3; points [3] = pointNotOnOutline; QPainter p(target); p.setRenderHints(QPainter::Antialiasing, true); // Polygon fill. p.setPen(col); p.setBrush(col); p.drawPolygon(points); // do not draw a black border. It looks ugly } //--------------------------------------------------------------------- static void DrawFace (QPaintDevice *target, double colorSimilarity, int redOrGreenOrBlue, const QPointF &tl, const QPointF &tr, const QPointF &bl, const QPointF &br, int highlight) { qCDebug(kpLogWidgets) << "kpColorSimilarityCubeRenderer.cpp:DrawFace(RorGorB=" << redOrGreenOrBlue << ",tl=" << tl << ",tr=" << tr << ",bl=" << bl << ",br=" << br << ")"; // tl --- tm --- tr // | | | // | | | // ml --- mm --- mr // | | | // | | | // bl --- bm --- br const QPointF tm (::PointBetween (tl, tr)); const QPointF bm (::PointBetween (bl, br)); const QPointF ml (::PointBetween (tl, bl)); const QPointF mr (::PointBetween (tr, br)); const QPointF mm (::PointBetween (ml, mr)); const int baseBrightness = qMax (127, 255 - int (kpColorSimilarityHolder::MaxColorSimilarity * kpColorSimilarityHolder::ColorCubeDiagonalDistance / 2)); QColor colors [2] = { ::Color (redOrGreenOrBlue, baseBrightness, colorSimilarity, -1, highlight), ::Color (redOrGreenOrBlue, baseBrightness, colorSimilarity, +1, highlight) }; qCDebug(kpLogWidgets) << "\tmaxColorSimilarity=" << kpColorSimilarityHolder::MaxColorSimilarity << " colorCubeDiagDist=" << kpColorSimilarityHolder::ColorCubeDiagonalDistance - << endl + << "\n" << "\tbaseBrightness=" << baseBrightness << " color[0]=" << ((colors [0].rgba() & RGB_MASK) >> ((2 - redOrGreenOrBlue) * 8)) << " color[1]=" << ((colors [1].rgba() & RGB_MASK) >> ((2 - redOrGreenOrBlue) * 8)); ::DrawQuadrant(target, colors [0], tm, tl, ml, mm); ::DrawQuadrant(target, colors [1], tm, tr, mr, mm); ::DrawQuadrant(target, colors [1], ml, bl, bm, mm); ::DrawQuadrant(target, colors [0], bm, br, mr, mm); } //--------------------------------------------------------------------- // public static void kpColorSimilarityCubeRenderer::Paint(QPaintDevice *target, int x, int y, int cubeRectSize, double colorSimilarity, int highlight) { Q_ASSERT (highlight >= 0 && highlight <= 255); // // P------- Q --- --- // / / | | | // /A / | side | // R-------S T --- cubeRectSize // | | / / | // S | | / side | // U-------V --- --- // |-------| // side // |-----------| // cubeRectSize // // const double angle = qDegreesToRadians (45.0); // S + S sin A = cubeRectSize // (1 + sin A) x S = cubeRectSize const double side = double(cubeRectSize) / (1.0 + std::sin(angle)); const QPointF pointP(x + (side * std::cos (angle)), y); const QPointF pointQ(x + cubeRectSize - 1, y); const QPointF pointR(x, y + (side * std::sin (angle))); const QPointF pointS(x + (side), y + (side * std::sin (angle))); const QPointF pointT(x + cubeRectSize - 1, y + (side)); const QPointF pointU(x, y + cubeRectSize - 1); const QPointF pointV(x + (side), y + cubeRectSize - 1); // Top Face ::DrawFace(target, colorSimilarity, 0/*red*/, pointP, pointQ, pointR, pointS, highlight); // Front Face ::DrawFace(target, colorSimilarity, 1/*green*/, pointR, pointS, pointU, pointV, highlight); // Right Face ::DrawFace(target, colorSimilarity, 2/*blue*/, pointS, pointQ, pointV, pointT, highlight); } //--------------------------------------------------------------------- diff --git a/widgets/colorSimilarity/kpColorSimilarityFrame.cpp b/widgets/colorSimilarity/kpColorSimilarityFrame.cpp index d03a87c9..dd98e449 100644 --- a/widgets/colorSimilarity/kpColorSimilarityFrame.cpp +++ b/widgets/colorSimilarity/kpColorSimilarityFrame.cpp @@ -1,78 +1,78 @@ /* Copyright (c) 2003-2007 Clarence Dang All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #define DEBUG_KP_COLOR_SIMILARITY_CUBE 0 #include "kpColorSimilarityFrame.h" #include "kpColorSimilarityCubeRenderer.h" #include "kpLogCategories.h" //--------------------------------------------------------------------- kpColorSimilarityFrame::kpColorSimilarityFrame(QWidget *parent) : QWidget(parent) { setWhatsThis (WhatsThis ()); } //--------------------------------------------------------------------- // public virtual [base kpColorSimilarityHolder] void kpColorSimilarityFrame::setColorSimilarity (double similarity) { kpColorSimilarityHolder::setColorSimilarity (similarity); repaint (); } //--------------------------------------------------------------------- // protected virtual [base QWidget] QSize kpColorSimilarityFrame::sizeHint () const { - return QSize (52, 52); + return {52, 52}; } //--------------------------------------------------------------------- // protected virtual [base QWidget] void kpColorSimilarityFrame::paintEvent (QPaintEvent *) { int cubeRectSize = qMin(width() * 6 / 8, height() * 6 / 8); int x = (width() - cubeRectSize) / 2; int y = (height() - cubeRectSize) / 2; kpColorSimilarityCubeRenderer::Paint(this, x, y, cubeRectSize, colorSimilarity()); } //--------------------------------------------------------------------- diff --git a/widgets/colorSimilarity/kpColorSimilarityHolder.cpp b/widgets/colorSimilarity/kpColorSimilarityHolder.cpp index a294e9bb..373fcb38 100644 --- a/widgets/colorSimilarity/kpColorSimilarityHolder.cpp +++ b/widgets/colorSimilarity/kpColorSimilarityHolder.cpp @@ -1,189 +1,190 @@ /* Copyright (c) 2003-2007 Clarence Dang All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #define DEBUG_KP_COLOR_SIMILARITY_CUBE 0 #include "kpColorSimilarityHolder.h" #include "kpColorSimilarityCubeRenderer.h" #include "imagelib/kpColor.h" #include "kpDefs.h" #include #include #include #include #include "kpLogCategories.h" #include // public static const double kpColorSimilarityHolder::ColorCubeDiagonalDistance = std::sqrt (255.0 * 255 * 3); // public static const double kpColorSimilarityHolder::MaxColorSimilarity = 0.30; kpColorSimilarityHolder::kpColorSimilarityHolder () : m_colorSimilarity (0) { } -kpColorSimilarityHolder::~kpColorSimilarityHolder () -{ -} +kpColorSimilarityHolder::~kpColorSimilarityHolder () = default; // Don't cause the translators grief by appending strings etc. // - duplicate text with 2 cases // public static QString kpColorSimilarityHolder::WhatsThisWithClickInstructions () { return i18n ("" "

Color Similarity is how similar the colors of different pixels" " must be, for operations to consider them to be the same.

" "

If you set it to something other than Exact Match," " you can work more effectively with dithered" " images and photos, in a comparable manner to the \"Magic Wand\"" " feature of other paint programs.

" "

This feature applies to:

" "
    " "
  • Selections: In Transparent mode, any color in the" " selection that is similar to the background color will" " be made transparent.
  • " "
  • Flood Fill: For regions with similar - but not" " identical - colored pixels, a higher setting is likely to" " fill more pixels.
  • " "
  • Color Eraser: Any pixel whose color is similar" " to the foreground color will be replaced with the background" " color.
  • " "
  • Autocrop and Remove Internal Border: For" " borders with similar - but not identical - colored pixels," " a higher setting is more likely to crop the whole border.
  • " "
" "

Higher settings mean that operations consider an increased range" " of colors to be sufficiently similar so as to be the same. Therefore," " you should increase the setting if the above operations are not" " affecting pixels whose colors you consider to be similar enough.

" "

However, if they are having too much of an effect and are changing" " pixels whose colors you do not consider to be similar" " (e.g. if Flood Fill is changing too many pixels), you" " should decrease this setting.

" // sync: Compared to the other string below, we've added this line. "

To configure it, click on the cube.

" "
"); } // public static QString kpColorSimilarityHolder::WhatsThis () { return i18n ("" "

Color Similarity is how similar the colors of different pixels" " must be, for operations to consider them to be the same.

" "

If you set it to something other than Exact Match," " you can work more effectively with dithered" " images and photos, in a comparable manner to the \"Magic Wand\"" " feature of other paint programs.

" "

This feature applies to:

" "
    " "
  • Selections: In Transparent mode, any color in the" " selection that is similar to the background color will" " be made transparent.
  • " "
  • Flood Fill: For regions with similar - but not" " identical - colored pixels, a higher setting is likely to" " fill more pixels.
  • " "
  • Color Eraser: Any pixel whose color is similar" " to the foreground color will be replaced with the background" " color.
  • " "
  • Autocrop and Remove Internal Border: For" " borders with similar - but not identical - colored pixels," " a higher setting is more likely to crop the whole border.
  • " "
" "

Higher settings mean that operations consider an increased range" " of colors to be sufficiently similar so as to be the same. Therefore," " you should increase the setting if the above operations are not" " affecting pixels whose colors you consider to be similar enough.

" "

However, if they are having too much of an effect and are changing" " pixels whose colors you do not consider to be similar" " (e.g. if Flood Fill is changing too many pixels), you" " should decrease this setting.

" "
"); } // public double kpColorSimilarityHolder::colorSimilarity () const { return m_colorSimilarity; } // public virtual void kpColorSimilarityHolder::setColorSimilarity (double similarity) { #if DEBUG_KP_COLOR_SIMILARITY_CUBE qCDebug(kpLogWidgets) << "kpColorSimilarityHolder::setColorSimilarity(" << similarity << ")"; #endif - if (m_colorSimilarity == similarity) + if (m_colorSimilarity == similarity) { return; + } - if (similarity < 0) + if (similarity < 0) { similarity = 0; - else if (similarity > MaxColorSimilarity) + } + else if (similarity > MaxColorSimilarity) { similarity = MaxColorSimilarity; + } m_colorSimilarity = similarity; } diff --git a/widgets/colorSimilarity/kpColorSimilarityToolBarItem.cpp b/widgets/colorSimilarity/kpColorSimilarityToolBarItem.cpp index d89431a6..be03de8d 100644 --- a/widgets/colorSimilarity/kpColorSimilarityToolBarItem.cpp +++ b/widgets/colorSimilarity/kpColorSimilarityToolBarItem.cpp @@ -1,263 +1,266 @@ /* Copyright (c) 2003-2007 Clarence Dang All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include "kpColorSimilarityToolBarItem.h" #include #include #include #include #include #include "imagelib/kpColor.h" #include "dialogs/kpColorSimilarityDialog.h" #include "kpColorSimilarityCubeRenderer.h" #include "kpDefs.h" #include "kpLogCategories.h" //--------------------------------------------------------------------- kpColorSimilarityToolBarItem::kpColorSimilarityToolBarItem (QWidget *parent) : QToolButton (parent), kpColorSimilarityHolder (), m_oldColorSimilarity (0), m_processedColorSimilarity (kpColor::Exact), m_flashTimer (new QTimer (this)), m_flashHighlight (0), m_suppressingFlashCounter (0) { setAutoRaise (true); setFixedSize (52, 52); setWhatsThis (WhatsThisWithClickInstructions ()); connect (this, &kpColorSimilarityToolBarItem::clicked, this, &kpColorSimilarityToolBarItem::openDialog); KConfigGroup cfg (KSharedConfig::openConfig (), kpSettingsGroupGeneral); setColorSimilarityInternal (cfg.readEntry (kpSettingColorSimilarity, 0.0), false/*don't write config*/); m_flashTimer->setInterval (100/*ms*/); connect (m_flashTimer, &QTimer::timeout, this, &kpColorSimilarityToolBarItem::slotFlashTimerTimeout); } //--------------------------------------------------------------------- // public int kpColorSimilarityToolBarItem::processedColorSimilarity () const { return m_processedColorSimilarity; } //--------------------------------------------------------------------- // private void kpColorSimilarityToolBarItem::setColorSimilarityInternal (double similarity, bool writeConfig) { qCDebug(kpLogWidgets) << "kpColorSimilarityToolBarItem::setColorSimilarityInternal(" << "similarity=" << similarity << ",writeConfig=" << writeConfig << ")"; m_oldColorSimilarity = colorSimilarity (); kpColorSimilarityHolder::setColorSimilarity (similarity); m_processedColorSimilarity = kpColor::processSimilarity (colorSimilarity ()); updateIcon (); updateToolTip (); if (writeConfig) { KConfigGroup cfg (KSharedConfig::openConfig (), kpSettingsGroupGeneral); cfg.writeEntry (kpSettingColorSimilarity, colorSimilarity ()); cfg.sync (); } emit colorSimilarityChanged (colorSimilarity (), m_processedColorSimilarity); } //--------------------------------------------------------------------- // public virtual [base kopColorSimilarityHolder] void kpColorSimilarityToolBarItem::setColorSimilarity (double similarity) { // (this calls the base setColorSimilarity() as required by base) setColorSimilarityInternal (similarity, true/*write config*/); } //--------------------------------------------------------------------- // public double kpColorSimilarityToolBarItem::oldColorSimilarity () const { return m_oldColorSimilarity; } //--------------------------------------------------------------------- // public void kpColorSimilarityToolBarItem::openDialog () { kpColorSimilarityDialog dialog (this); dialog.setColorSimilarity (colorSimilarity ()); if (dialog.exec ()) { setColorSimilarity (dialog.colorSimilarity ()); } } //--------------------------------------------------------------------- // private slot: void kpColorSimilarityToolBarItem::slotFlashTimerTimeout () { qCDebug(kpLogWidgets) << "kpColorSimilarityToolBarItem::slotFlashTimerTimeout()" << " highlight=" << m_flashHighlight; int newHigh = m_flashHighlight - 20; - if (newHigh < 0) + if (newHigh < 0) { newHigh = 0; + } m_flashHighlight = newHigh; updateIcon (); - if (newHigh == 0) + if (newHigh == 0) { m_flashTimer->stop (); + } } //--------------------------------------------------------------------- // public void kpColorSimilarityToolBarItem::flash () { qCDebug(kpLogWidgets) << "kpColorSimilarityToolBarItem::flash()"; - if (isSuppressingFlash ()) + if (isSuppressingFlash ()) { return; + } if (m_flashHighlight == 255) { qCDebug(kpLogWidgets) << "\tNOP"; } else { m_flashHighlight = 255; updateIcon (); } m_flashTimer->start (); } //--------------------------------------------------------------------- // public bool kpColorSimilarityToolBarItem::isSuppressingFlash () const { return (m_suppressingFlashCounter > 0); } //--------------------------------------------------------------------- // public void kpColorSimilarityToolBarItem::suppressFlash () { m_suppressingFlashCounter++; } //--------------------------------------------------------------------- // public void kpColorSimilarityToolBarItem::unsupressFlash () { m_suppressingFlashCounter--; Q_ASSERT (m_suppressingFlashCounter >= 0); } //--------------------------------------------------------------------- // private void kpColorSimilarityToolBarItem::updateToolTip () { qCDebug(kpLogWidgets) << "kpColorSimilarityToolBarItem::updateToolTip()"; if (colorSimilarity () > 0) { setToolTip ( i18n ("

Color Similarity: %1%

" "

Click to configure.

", qRound (colorSimilarity () * 100))); } else { setToolTip ( i18n ("

Color Similarity: Exact Match

" "

Click to configure.

")); } } //--------------------------------------------------------------------- // private // LOOPT: This gets called twice on KolourPaint startup by: // // 1. setColorSimilarityInternal() called by the ctor // 2. resizeEvent() when it's first shown() // // We could get rid of the first and save a few milliseconds. void kpColorSimilarityToolBarItem::updateIcon () { const int side = width () * 6 / 8; qCDebug(kpLogWidgets) << "kpColorSimilarityToolBarItem::updateIcon() width=" << width () - << " side=" << side << endl; + << " side=" << side; QPixmap icon(side, side); icon.fill(Qt::transparent); kpColorSimilarityCubeRenderer::Paint (&icon, 0/*x*/, 0/*y*/, side, colorSimilarity (), m_flashHighlight); setIconSize(QSize(side, side)); setIcon(icon); } //--------------------------------------------------------------------- // private virtual [base QWidget] void kpColorSimilarityToolBarItem::resizeEvent (QResizeEvent *e) { qCDebug(kpLogWidgets) << "kpColorSimilarityToolBarItem::resizeEvent() size=" << size () - << " oldSize=" << e->oldSize () << endl; + << " oldSize=" << e->oldSize (); QToolButton::resizeEvent (e); updateIcon (); } diff --git a/widgets/imagelib/effects/kpEffectBalanceWidget.cpp b/widgets/imagelib/effects/kpEffectBalanceWidget.cpp index ac14d7aa..f5c66217 100644 --- a/widgets/imagelib/effects/kpEffectBalanceWidget.cpp +++ b/widgets/imagelib/effects/kpEffectBalanceWidget.cpp @@ -1,317 +1,330 @@ /* Copyright (c) 2003-2007 Clarence Dang All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #define DEBUG_KP_EFFECT_BALANCE 0 #include "kpEffectBalanceWidget.h" #include "imagelib/effects/kpEffectBalance.h" #include "commands/imagelib/effects/kpEffectBalanceCommand.h" #include "pixmapfx/kpPixmapFX.h" #include "kpLogCategories.h" #include #include "kpNumInput.h" #include #include #include #include #include #include #if DEBUG_KP_EFFECT_BALANCE #include #endif kpEffectBalanceWidget::kpEffectBalanceWidget (bool actOnSelection, QWidget *parent) : kpEffectWidgetBase (actOnSelection, parent) { - QGridLayout *lay = new QGridLayout (this); + auto *lay = new QGridLayout (this); lay->setContentsMargins(0, 0, 0, 0); - - QLabel *brightnessLabel = new QLabel (i18n ("&Brightness:"), this); + auto *brightnessLabel = new QLabel (i18n ("&Brightness:"), this); m_brightnessInput = new kpIntNumInput (0/*value*/, this); m_brightnessInput->setRange (-50, 50); - QPushButton *brightnessResetPushButton = new QPushButton (i18n ("Re&set"), this); + auto *brightnessResetPushButton = new QPushButton (i18n ("Re&set"), this); - QLabel *contrastLabel = new QLabel (i18n ("Co&ntrast:"), this); + auto *contrastLabel = new QLabel (i18n ("Co&ntrast:"), this); m_contrastInput = new kpIntNumInput (0/*value*/, this); m_contrastInput->setRange (-50, 50); - QPushButton *contrastResetPushButton = new QPushButton (i18n ("&Reset"), this); + auto *contrastResetPushButton = new QPushButton (i18n ("&Reset"), this); - QLabel *gammaLabel = new QLabel (i18n ("&Gamma:"), this); + auto *gammaLabel = new QLabel (i18n ("&Gamma:"), this); m_gammaInput = new kpIntNumInput (0/*value*/, this); m_gammaInput->setRange (-50, 50); // TODO: This is what should be shown in the m_gammaInput spinbox m_gammaLabel = new QLabel (this); // TODO: This doesn't seem to be wide enough with some fonts so the // whole layout moves when we drag the gamma slider. m_gammaLabel->setMinimumWidth (m_gammaLabel->fontMetrics ().width (QLatin1String (" 10.00 "))); m_gammaLabel->setAlignment (m_gammaLabel->alignment () | Qt::AlignRight); - QPushButton *gammaResetPushButton = new QPushButton (i18n ("Rese&t"), this); + auto *gammaResetPushButton = new QPushButton (i18n ("Rese&t"), this); - QWidget *spaceWidget = new QLabel (this); + auto *spaceWidget = new QLabel (this); spaceWidget->setFixedSize (1, fontMetrics ().height () / 4); - QLabel *channelLabel = new QLabel (i18n ("C&hannels:"), this); + auto *channelLabel = new QLabel (i18n ("C&hannels:"), this); m_channelsComboBox = new QComboBox (this); m_channelsComboBox->addItem (i18n ("All")); m_channelsComboBox->addItem (i18n ("Red")); m_channelsComboBox->addItem (i18n ("Green")); m_channelsComboBox->addItem (i18n ("Blue")); - QPushButton *resetPushButton = new QPushButton (i18n ("Reset &All Values"), this); + auto *resetPushButton = new QPushButton (i18n ("Reset &All Values"), this); brightnessLabel->setBuddy (m_brightnessInput); contrastLabel->setBuddy (m_contrastInput); gammaLabel->setBuddy (m_gammaInput); channelLabel->setBuddy (m_channelsComboBox); lay->addWidget (brightnessLabel, 0, 0); lay->addWidget (m_brightnessInput, 0, 1, 1, 2); lay->addWidget (brightnessResetPushButton, 0, 4); lay->addWidget (contrastLabel, 1, 0); lay->addWidget (m_contrastInput, 1, 1, 1, 2); lay->addWidget (contrastResetPushButton, 1, 4); lay->addWidget (gammaLabel, 2, 0); lay->addWidget (m_gammaInput, 2, 1, 1, 2); lay->addWidget (m_gammaLabel, 2, 3); lay->addWidget (gammaResetPushButton, 2, 4); lay->addWidget (spaceWidget, 3, 0, 1, 5); lay->addWidget (resetPushButton, 4, 2, 1, 3, Qt::AlignRight); lay->addWidget (channelLabel, 4, 0); lay->addWidget (m_channelsComboBox, 4, 1, Qt::AlignLeft); //lay->addWidget (resetPushButton, 4, 2, Qt::AlignRight); lay->setColumnStretch (1, 1); // (no need for settingsChangedDelayed() since BCG effect is so fast :)) connect (m_brightnessInput, &kpIntNumInput::valueChanged, this, &kpEffectBalanceWidget::settingsChangedNoWaitCursor); connect (m_contrastInput, &kpIntNumInput::valueChanged, this, &kpEffectBalanceWidget::settingsChangedNoWaitCursor); connect (m_gammaInput, &kpIntNumInput::valueChanged, this, &kpEffectBalanceWidget::recalculateGammaLabel); connect (m_gammaInput, &kpIntNumInput::valueChanged, this, &kpEffectBalanceWidget::settingsChangedNoWaitCursor); connect (m_channelsComboBox, static_cast(&QComboBox::activated), this, &kpEffectBalanceWidget::settingsChanged); connect (brightnessResetPushButton, &QPushButton::clicked, this, &kpEffectBalanceWidget::resetBrightness); connect (contrastResetPushButton, &QPushButton::clicked, this, &kpEffectBalanceWidget::resetContrast); connect (gammaResetPushButton, &QPushButton::clicked, this, &kpEffectBalanceWidget::resetGamma); connect (resetPushButton, &QPushButton::clicked, this, &kpEffectBalanceWidget::resetAll); recalculateGammaLabel (); } -kpEffectBalanceWidget::~kpEffectBalanceWidget () -{ -} +kpEffectBalanceWidget::~kpEffectBalanceWidget () = default; // public virtual [base kpEffectWidgetBase] QString kpEffectBalanceWidget::caption () const { return i18n ("Settings"); } // public virtual [base kpEffectWidgetBase] bool kpEffectBalanceWidget::isNoOp () const { return (brightness () == 0 && contrast () == 0 && gamma () == 0); } // public virtual [base kpEffectWidgetBase] kpImage kpEffectBalanceWidget::applyEffect (const kpImage &image) { return kpEffectBalance::applyEffect (image, channels (), brightness (), contrast (), gamma ()); } // public virtual [base kpEffectWidgetBase] kpEffectCommandBase *kpEffectBalanceWidget::createCommand ( kpCommandEnvironment *cmdEnviron) const { return new kpEffectBalanceCommand (channels (), brightness (), contrast (), gamma (), m_actOnSelection, cmdEnviron); } // protected int kpEffectBalanceWidget::channels () const { switch (m_channelsComboBox->currentIndex ()) { default: case 0: return kpEffectBalance::RGB; case 1: return kpEffectBalance::Red; case 2: return kpEffectBalance::Green; case 3: return kpEffectBalance::Blue; } } // protected int kpEffectBalanceWidget::brightness () const { return m_brightnessInput->value (); } // protected int kpEffectBalanceWidget::contrast () const { return m_contrastInput->value (); } // protected int kpEffectBalanceWidget::gamma () const { return m_gammaInput->value (); } // protected slot void kpEffectBalanceWidget::recalculateGammaLabel () { m_gammaLabel->setText ( QLatin1String (" ") + QString::number (std::pow (10, gamma () / 50.0), 'f'/*[-]9.9*/, 2/*precision*/) + QLatin1String (" ")); m_gammaLabel->repaint (); } // protected slot void kpEffectBalanceWidget::resetBrightness () { - if (brightness () == 0) + if (brightness () == 0) { return; + } bool sb = signalsBlocked (); - if (!sb) blockSignals (true); + if (!sb) { + blockSignals (true); + } m_brightnessInput->setValue (0); - if (!sb) blockSignals (false); + if (!sb) { + blockSignals (false); + } // Immediate update (if signals aren't blocked) emit settingsChanged (); } // protected slot void kpEffectBalanceWidget::resetContrast () { - if (contrast () == 0) + if (contrast () == 0) { return; + } bool sb = signalsBlocked (); - if (!sb) blockSignals (true); + if (!sb) { + blockSignals (true); + } m_contrastInput->setValue (0); - if (!sb) blockSignals (false); + if (!sb) { + blockSignals (false); + } // Immediate update (if signals aren't blocked) emit settingsChanged (); } // protected slot void kpEffectBalanceWidget::resetGamma () { - if (gamma () == 0) + if (gamma () == 0) { return; + } bool sb = signalsBlocked (); - if (!sb) blockSignals (true); + if (!sb) { + blockSignals (true); + } m_gammaInput->setValue (0); recalculateGammaLabel (); - if (!sb) blockSignals (false); + if (!sb) { + blockSignals (false); + } // Immediate update (if signals aren't blocked) emit settingsChanged (); } // protected slot void kpEffectBalanceWidget::resetAll () { - if (isNoOp ()) + if (isNoOp ()) { return; + } // Prevent multiple settingsChanged() which would normally result in // redundant, expensive preview repaints blockSignals (true); resetBrightness (); resetContrast (); resetGamma (); recalculateGammaLabel (); blockSignals (false); emit settingsChanged (); } diff --git a/widgets/imagelib/effects/kpEffectBlurSharpenWidget.cpp b/widgets/imagelib/effects/kpEffectBlurSharpenWidget.cpp index f847e4eb..a5a34e94 100644 --- a/widgets/imagelib/effects/kpEffectBlurSharpenWidget.cpp +++ b/widgets/imagelib/effects/kpEffectBlurSharpenWidget.cpp @@ -1,178 +1,177 @@ /* Copyright (c) 2003-2007 Clarence Dang All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #define DEBUG_KP_EFFECT_BLUR_SHARPEN 0 #include "kpEffectBlurSharpenWidget.h" #include "commands/imagelib/effects/kpEffectBlurSharpenCommand.h" #include "kpLogCategories.h" #include #include "kpNumInput.h" #include #include #include kpEffectBlurSharpenWidget::kpEffectBlurSharpenWidget (bool actOnSelection, QWidget *parent) : kpEffectWidgetBase (actOnSelection, parent) { - QGridLayout *lay = new QGridLayout (this); + auto *lay = new QGridLayout (this); lay->setContentsMargins(0, 0, 0, 0); - - QLabel *amountLabel = new QLabel (i18n ("&Amount:"), this); + auto *amountLabel = new QLabel (i18n ("&Amount:"), this); m_amountInput = new kpIntNumInput (this); m_amountInput->setRange (-kpEffectBlurSharpen::MaxStrength/*- for blur*/, +kpEffectBlurSharpen::MaxStrength/*+ for sharpen*/); m_typeLabel = new QLabel (this); // Make sure doesn't expand when the effect type changes, // as otherwise, that would cause the preview pixmap label in the // "More Effects" dialog (which our widget is inside) to contract, // which would look a bit weird. // // We do this by setting the label to every possible string it could // contain and fixing its height to the maximum seen size hint height. - int h = m_typeLabel->sizeHint ().height (); + auto h = m_typeLabel->sizeHint ().height (); qCDebug(kpLogWidgets) << "initial size hint height=" << h; m_typeLabel->setText ( kpEffectBlurSharpenCommand::nameForType (kpEffectBlurSharpen::Blur)); h = qMax (h, m_typeLabel->sizeHint ().height ()); m_typeLabel->setText ( kpEffectBlurSharpenCommand::nameForType (kpEffectBlurSharpen::Sharpen)); h = qMax (h, m_typeLabel->sizeHint ().height ()); // Set this text last as the label's text needs to reflect the default // effect of "None". m_typeLabel->setText ( kpEffectBlurSharpenCommand::nameForType (kpEffectBlurSharpen::None)); h = qMax (h, m_typeLabel->sizeHint ().height ()); qCDebug(kpLogWidgets) << "maximum size hint height" << h; m_typeLabel->setFixedHeight (h); m_typeLabel->setAlignment (Qt::AlignCenter); amountLabel->setBuddy (m_amountInput); lay->addWidget (amountLabel, 0, 0); lay->addWidget (m_amountInput, 0, 1); lay->addWidget (m_typeLabel, 1, 0, 1, 2, Qt::AlignCenter); lay->setColumnStretch (1, 1); connect (m_amountInput, &kpIntNumInput::valueChanged, this, &kpEffectBlurSharpenWidget::settingsChangedDelayed); connect (m_amountInput, &kpIntNumInput::valueChanged, this, &kpEffectBlurSharpenWidget::slotUpdateTypeLabel); } -kpEffectBlurSharpenWidget::~kpEffectBlurSharpenWidget () -{ -} +kpEffectBlurSharpenWidget::~kpEffectBlurSharpenWidget () = default; // public virtual [base kpEffectWidgetBase] QString kpEffectBlurSharpenWidget::caption () const { return QString(); } // public virtual [base kpEffectWidgetBase] bool kpEffectBlurSharpenWidget::isNoOp () const { return (type () == kpEffectBlurSharpen::None); } // public virtual [base kpEffectWidgetBase] kpImage kpEffectBlurSharpenWidget::applyEffect (const kpImage &image) { return kpEffectBlurSharpen::applyEffect (image, type (), strength ()); } // public virtual [base kpEffectWidgetBase] kpEffectCommandBase *kpEffectBlurSharpenWidget::createCommand ( kpCommandEnvironment *cmdEnviron) const { return new kpEffectBlurSharpenCommand (type (), strength (), m_actOnSelection, cmdEnviron); } // protected slot void kpEffectBlurSharpenWidget::slotUpdateTypeLabel () { QString text = kpEffectBlurSharpenCommand::nameForType (type ()); - qCDebug(kpLogWidgets) << "kpEffectBlurSharpenWidget::slotUpdateTypeLabel() text=" - << text << endl; + qCDebug(kpLogWidgets) << "kpEffectBlurSharpenWidget::slotUpdateTypeLabel() text=" << text; const int h = m_typeLabel->height (); m_typeLabel->setText (text); if (m_typeLabel->height () != h) { qCCritical(kpLogWidgets) << "Label changed height despite the hack in ctor:" << "was=" << h << "now=" << m_typeLabel->height (); } } // protected kpEffectBlurSharpen::Type kpEffectBlurSharpenWidget::type () const { - if (m_amountInput->value () == 0) + if (m_amountInput->value () == 0) { return kpEffectBlurSharpen::None; - else if (m_amountInput->value () < 0) + } + + if (m_amountInput->value () < 0) { return kpEffectBlurSharpen::Blur; - else - return kpEffectBlurSharpen::Sharpen; + } + + return kpEffectBlurSharpen::Sharpen; } // protected int kpEffectBlurSharpenWidget::strength () const { return qAbs (m_amountInput->value ()); } diff --git a/widgets/imagelib/effects/kpEffectEmbossWidget.cpp b/widgets/imagelib/effects/kpEffectEmbossWidget.cpp index 296d0ae8..114a2069 100644 --- a/widgets/imagelib/effects/kpEffectEmbossWidget.cpp +++ b/widgets/imagelib/effects/kpEffectEmbossWidget.cpp @@ -1,108 +1,106 @@ /* Copyright (c) 2003-2007 Clarence Dang All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #define DEBUG_KP_EFFECT_EMBOSS 0 #include "kpEffectEmbossWidget.h" #include #include #include "kpLogCategories.h" #include #include "imagelib/effects/kpEffectEmboss.h" #include "commands/imagelib/effects/kpEffectEmbossCommand.h" kpEffectEmbossWidget::kpEffectEmbossWidget (bool actOnSelection, QWidget *parent) : kpEffectWidgetBase (actOnSelection, parent) { - QGridLayout *lay = new QGridLayout (this); + auto *lay = new QGridLayout (this); lay->setContentsMargins(0, 0, 0, 0); - m_enableCheckBox = new QCheckBox (i18n ("E&nable"), this); lay->addWidget (m_enableCheckBox, 0, 0, 1, 2, Qt::AlignCenter); // (settingsChangedDelayed() instead of settingsChanged() so that the // user can quickly press OK to apply effect to document directly and // not have to wait for the also slow preview) connect (m_enableCheckBox, &QCheckBox::toggled, this, &kpEffectEmbossWidget::settingsChangedDelayed); } -kpEffectEmbossWidget::~kpEffectEmbossWidget () -{ -} +kpEffectEmbossWidget::~kpEffectEmbossWidget () = default; // public virtual [base kpEffectWidgetBase] QString kpEffectEmbossWidget::caption () const { return QString(); } // public virtual [base kpEffectWidgetBase] bool kpEffectEmbossWidget::isNoOp () const { //return (m_amountInput->value () == 0); return !m_enableCheckBox->isChecked (); } // public virtual [base kpEffectWidgetBase] kpImage kpEffectEmbossWidget::applyEffect (const kpImage &image) { - if (isNoOp ()) + if (isNoOp ()) { return image; + } return kpEffectEmboss::applyEffect (image, strength ()); } // public virtual [base kpEffectWidgetBase] kpEffectCommandBase *kpEffectEmbossWidget::createCommand ( kpCommandEnvironment *cmdEnviron) const { return new kpEffectEmbossCommand (strength (), m_actOnSelection, cmdEnviron); } // protected int kpEffectEmbossWidget::strength () const { return kpEffectEmboss::MaxStrength; } diff --git a/widgets/imagelib/effects/kpEffectFlattenWidget.cpp b/widgets/imagelib/effects/kpEffectFlattenWidget.cpp index 24d41b8c..85e75b0c 100644 --- a/widgets/imagelib/effects/kpEffectFlattenWidget.cpp +++ b/widgets/imagelib/effects/kpEffectFlattenWidget.cpp @@ -1,176 +1,177 @@ /* Copyright (c) 2003-2007 Clarence Dang All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #define DEBUG_KP_EFFECT_FLATTEN 0 #include "kpEffectFlattenWidget.h" #include "kpDefs.h" #include "imagelib/effects/kpEffectFlatten.h" #include "commands/imagelib/effects/kpEffectFlattenCommand.h" #include "kpLogCategories.h" #include #include #include #include #include #include // public static QColor kpEffectFlattenWidget::s_lastColor1; QColor kpEffectFlattenWidget::s_lastColor2; kpEffectFlattenWidget::kpEffectFlattenWidget (bool actOnSelection, QWidget *parent) : kpEffectWidgetBase (actOnSelection, parent) { if (!s_lastColor1.isValid () || !s_lastColor2.isValid ()) { KConfigGroup cfgGroupSaver (KSharedConfig::openConfig (), kpSettingsGroupFlattenEffect); s_lastColor1 = cfgGroupSaver.readEntry (kpSettingFlattenEffectColor1, QColor ()); - if (!s_lastColor1.isValid ()) + if (!s_lastColor1.isValid ()) { s_lastColor1 = Qt::red; + } s_lastColor2 = cfgGroupSaver.readEntry (kpSettingFlattenEffectColor2, QColor ()); - if (!s_lastColor2.isValid ()) + if (!s_lastColor2.isValid ()) { s_lastColor2 = Qt::blue; + } } m_enableCheckBox = new QCheckBox (i18n ("E&nable"), this); m_color1Button = new KColorButton (s_lastColor1, this); m_color2Button = new KColorButton (s_lastColor2, this); m_color1Button->setEnabled (false); m_color2Button->setEnabled (false); - - QVBoxLayout *lay = new QVBoxLayout (this); + auto *lay = new QVBoxLayout (this); lay->setContentsMargins(0, 0, 0, 0); lay->addWidget (m_enableCheckBox); lay->addWidget (m_color1Button); lay->addWidget (m_color2Button); - connect (m_enableCheckBox, &QCheckBox::toggled, this, &kpEffectFlattenWidget::slotEnableChanged); connect (m_color1Button, &KColorButton::changed, this, &kpEffectFlattenWidget::settingsChanged); connect (m_color2Button, &KColorButton::changed, this, &kpEffectFlattenWidget::settingsChanged); } kpEffectFlattenWidget::~kpEffectFlattenWidget () { s_lastColor1 = color1 (); s_lastColor2 = color2 (); KConfigGroup cfg (KSharedConfig::openConfig (), kpSettingsGroupFlattenEffect); cfg.writeEntry (kpSettingFlattenEffectColor1, s_lastColor1); cfg.writeEntry (kpSettingFlattenEffectColor2, s_lastColor2); cfg.sync (); } // public QColor kpEffectFlattenWidget::color1 () const { return m_color1Button->color (); } // public QColor kpEffectFlattenWidget::color2 () const { return m_color2Button->color (); } // // kpEffectFlattenWidget implements kpEffectWidgetBase interface // // public virtual [base kpEffectWidgetBase] QString kpEffectFlattenWidget::caption () const { return i18n ("Colors"); } // public virtual [base kpEffectWidgetBase] bool kpEffectFlattenWidget::isNoOp () const { return !m_enableCheckBox->isChecked (); } // public virtual [base kpEffectWidgetBase] kpImage kpEffectFlattenWidget::applyEffect (const kpImage &image) { qCDebug(kpLogWidgets) << "kpEffectFlattenWidget::applyEffect() nop=" << isNoOp (); - if (isNoOp ()) + if (isNoOp ()) { return image; + } return kpEffectFlatten::applyEffect (image, color1 (), color2 ()); } // public virtual [base kpEffectWidgetBase] kpEffectCommandBase *kpEffectFlattenWidget::createCommand ( kpCommandEnvironment *cmdEnviron) const { return new kpEffectFlattenCommand (color1 (), color2 (), m_actOnSelection, cmdEnviron); } // protected slot: void kpEffectFlattenWidget::slotEnableChanged (bool enable) { qCDebug(kpLogWidgets) << "kpEffectFlattenWidget::slotEnableChanged(" << enable << ") enableButton=" << m_enableCheckBox->isChecked (); m_color1Button->setEnabled (enable); m_color2Button->setEnabled (enable); emit settingsChanged (); } diff --git a/widgets/imagelib/effects/kpEffectHSVWidget.cpp b/widgets/imagelib/effects/kpEffectHSVWidget.cpp index 8d9a3ec4..40b0f9f0 100644 --- a/widgets/imagelib/effects/kpEffectHSVWidget.cpp +++ b/widgets/imagelib/effects/kpEffectHSVWidget.cpp @@ -1,126 +1,121 @@ /* Copyright (c) 2007 Mike Gashler All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include "kpEffectHSVWidget.h" #include #include #include "kpLogCategories.h" #include #include "kpNumInput.h" #include "imagelib/effects/kpEffectHSV.h" #include "commands/imagelib/effects/kpEffectHSVCommand.h" kpEffectHSVWidget::kpEffectHSVWidget (bool actOnSelection, QWidget *parent) : kpEffectWidgetBase (actOnSelection, parent) { - QGridLayout *lay = new QGridLayout (this); + auto *lay = new QGridLayout (this); lay->setContentsMargins(0, 0, 0, 0); - QLabel *hueLabel = new QLabel (i18n ("&Hue:"), this); - QLabel *saturationLabel = new QLabel (i18n ("&Saturation:"), this); - QLabel *valueLabel = new QLabel (i18nc ("The V of HSV", "&Value:"), this); + auto *hueLabel = new QLabel (i18n ("&Hue:"), this); + auto *saturationLabel = new QLabel (i18n ("&Saturation:"), this); + auto *valueLabel = new QLabel (i18nc ("The V of HSV", "&Value:"), this); m_hueInput = new kpDoubleNumInput (this); m_hueInput->setRange (-180, 180, 15/*step*/); m_saturationInput = new kpDoubleNumInput (this); m_saturationInput->setRange (-1, 1, 0.1/*step*/); m_valueInput = new kpDoubleNumInput (this); m_valueInput->setRange (-1, 1, 0.1/*step*/); hueLabel->setBuddy (m_hueInput); saturationLabel->setBuddy (m_saturationInput); valueLabel->setBuddy (m_valueInput); lay->addWidget (hueLabel, 0, 0); lay->addWidget (m_hueInput, 0, 1); lay->addWidget (saturationLabel, 1, 0); lay->addWidget (m_saturationInput, 1, 1); lay->addWidget (valueLabel, 2, 0); lay->addWidget (m_valueInput, 2, 1); lay->setColumnStretch (1, 1); connect (m_hueInput, &kpDoubleNumInput::valueChanged, this, &kpEffectHSVWidget::settingsChangedDelayed); connect (m_saturationInput, &kpDoubleNumInput::valueChanged, this, &kpEffectHSVWidget::settingsChangedDelayed); connect (m_valueInput, &kpDoubleNumInput::valueChanged, this, &kpEffectHSVWidget::settingsChangedDelayed); } -kpEffectHSVWidget::~kpEffectHSVWidget () -{ -} +kpEffectHSVWidget::~kpEffectHSVWidget () = default; // public virtual [base kpEffectWidgetBase] QString kpEffectHSVWidget::caption () const { // TODO: Why doesn't this have a caption? Ditto for the other effects. - return QString(); + return {}; } // public virtual [base kpEffectWidgetBase] bool kpEffectHSVWidget::isNoOp () const { - if (m_hueInput->value () == 0 && m_saturationInput->value () == 0 && m_valueInput->value () == 0) - return true; - else - return false; + return m_hueInput->value () == 0 && m_saturationInput->value () == 0 && m_valueInput->value () == 0; } // public virtual [base kpEffectWidgetBase] kpImage kpEffectHSVWidget::applyEffect (const kpImage &image) { return kpEffectHSV::applyEffect (image, m_hueInput->value (), m_saturationInput->value (), m_valueInput->value ()); } // public virtual [base kpEffectWidgetBase] kpEffectCommandBase *kpEffectHSVWidget::createCommand ( kpCommandEnvironment *cmdEnviron) const { return new kpEffectHSVCommand ( m_hueInput->value (), m_saturationInput->value (), m_valueInput->value (), m_actOnSelection, cmdEnviron); } diff --git a/widgets/imagelib/effects/kpEffectInvertWidget.cpp b/widgets/imagelib/effects/kpEffectInvertWidget.cpp index 07b5d45b..4601850c 100644 --- a/widgets/imagelib/effects/kpEffectInvertWidget.cpp +++ b/widgets/imagelib/effects/kpEffectInvertWidget.cpp @@ -1,206 +1,207 @@ /* Copyright (c) 2003-2007 Clarence Dang All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #define DEBUG_KP_EFFECT_INVERT 0 #include "kpEffectInvertWidget.h" #include "imagelib/effects/kpEffectInvert.h" #include "commands/imagelib/effects/kpEffectInvertCommand.h" #include "pixmapfx/kpPixmapFX.h" #include "kpLogCategories.h" #include #include #include #include #include kpEffectInvertWidget::kpEffectInvertWidget (bool actOnSelection, QWidget *parent) : kpEffectWidgetBase (actOnSelection, parent) { - QVBoxLayout *topLevelLay = new QVBoxLayout (this); + auto *topLevelLay = new QVBoxLayout (this); topLevelLay->setContentsMargins(0, 0, 0, 0); - - QWidget *centerWidget = new QWidget (this); + auto *centerWidget = new QWidget (this); topLevelLay->addWidget (centerWidget, 0/*stretch*/, Qt::AlignCenter); - - QVBoxLayout *centerWidgetLay = new QVBoxLayout (centerWidget ); + auto *centerWidgetLay = new QVBoxLayout (centerWidget ); centerWidgetLay->setContentsMargins(0, 0, 0, 0); m_redCheckBox = new QCheckBox (i18n ("&Red"), centerWidget); m_greenCheckBox = new QCheckBox (i18n ("&Green"), centerWidget); m_blueCheckBox = new QCheckBox (i18n ("&Blue"), centerWidget); - QWidget *spaceWidget = new QWidget (centerWidget); + auto *spaceWidget = new QWidget (centerWidget); spaceWidget->setFixedSize (1, fontMetrics ().height () / 4); m_allCheckBox = new QCheckBox (i18n ("&All"), centerWidget); m_redCheckBox->setChecked (false); m_greenCheckBox->setChecked (false); m_blueCheckBox->setChecked (false); m_allCheckBox->setChecked (false); centerWidgetLay->addWidget (m_redCheckBox); centerWidgetLay->addWidget (m_greenCheckBox); centerWidgetLay->addWidget (m_blueCheckBox); centerWidgetLay->addWidget (spaceWidget); centerWidgetLay->addWidget (m_allCheckBox); m_inSignalHandler = false; connect (m_redCheckBox, &QCheckBox::toggled, this, &kpEffectInvertWidget::slotRGBCheckBoxToggled); connect (m_greenCheckBox, &QCheckBox::toggled, this, &kpEffectInvertWidget::slotRGBCheckBoxToggled); connect (m_blueCheckBox, &QCheckBox::toggled, this, &kpEffectInvertWidget::slotRGBCheckBoxToggled); connect (m_allCheckBox, &QCheckBox::toggled, this, &kpEffectInvertWidget::slotAllCheckBoxToggled); } -kpEffectInvertWidget::~kpEffectInvertWidget () -{ -} +kpEffectInvertWidget::~kpEffectInvertWidget () = default; // public int kpEffectInvertWidget::channels () const { qCDebug(kpLogWidgets) << "kpEffectInvertWidget::channels()" << " isChecked: r=" << m_redCheckBox->isChecked () << " g=" << m_greenCheckBox->isChecked () << " b=" << m_blueCheckBox->isChecked (); int channels = 0; - if (m_redCheckBox->isChecked ()) + if (m_redCheckBox->isChecked ()) { channels |= kpEffectInvert::Red; + } - if (m_greenCheckBox->isChecked ()) + if (m_greenCheckBox->isChecked ()) { channels |= kpEffectInvert::Green; + } - if (m_blueCheckBox->isChecked ()) + if (m_blueCheckBox->isChecked ()) { channels |= kpEffectInvert::Blue; + } qCDebug(kpLogWidgets) << "\treturning channels=" << (int *) channels; return channels; } // // kpEffectInvertWidget implements kpEffectWidgetBase interface // // public virtual [base kpEffectWidgetBase] QString kpEffectInvertWidget::caption () const { return i18n ("Channels"); } // public virtual [base kpEffectWidgetBase] bool kpEffectInvertWidget::isNoOp () const { return (channels () == kpEffectInvert::None); } // public virtual [base kpEffectWidgetBase] kpImage kpEffectInvertWidget::applyEffect (const kpImage &image) { return kpEffectInvert::applyEffect (image, channels ()); } // public virtual [base kpEffectWidgetBase] kpEffectCommandBase *kpEffectInvertWidget::createCommand ( kpCommandEnvironment *cmdEnviron) const { return new kpEffectInvertCommand (channels (), m_actOnSelection, cmdEnviron); } // protected slots void kpEffectInvertWidget::slotRGBCheckBoxToggled () { - if (m_inSignalHandler) + if (m_inSignalHandler) { return; + } m_inSignalHandler = true; //blockSignals (true); m_allCheckBox->setChecked (m_redCheckBox->isChecked () && m_blueCheckBox->isChecked () && m_greenCheckBox->isChecked ()); //blockSignals (false); emit settingsChanged (); m_inSignalHandler = false; } // protected slot void kpEffectInvertWidget::slotAllCheckBoxToggled () { - if (m_inSignalHandler) + if (m_inSignalHandler) { return; + } m_inSignalHandler = true; //blockSignals (true); m_redCheckBox->setChecked (m_allCheckBox->isChecked ()); m_greenCheckBox->setChecked (m_allCheckBox->isChecked ()); m_blueCheckBox->setChecked (m_allCheckBox->isChecked ()); //blockSignals (false); emit settingsChanged (); m_inSignalHandler = false; } diff --git a/widgets/imagelib/effects/kpEffectReduceColorsWidget.cpp b/widgets/imagelib/effects/kpEffectReduceColorsWidget.cpp index ad495a0b..362b9169 100644 --- a/widgets/imagelib/effects/kpEffectReduceColorsWidget.cpp +++ b/widgets/imagelib/effects/kpEffectReduceColorsWidget.cpp @@ -1,179 +1,178 @@ /* Copyright (c) 2003-2007 Clarence Dang All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #define DEBUG_KP_EFFECT_REDUCE_COLORS 0 #include "kpEffectReduceColorsWidget.h" #include "imagelib/effects/kpEffectReduceColors.h" #include "commands/imagelib/effects/kpEffectReduceColorsCommand.h" #include "pixmapfx/kpPixmapFX.h" #include "kpLogCategories.h" #include #include #include #include #include #include #include #include kpEffectReduceColorsWidget::kpEffectReduceColorsWidget (bool actOnSelection, QWidget *parent) : kpEffectWidgetBase (actOnSelection, parent) { - QVBoxLayout *lay = new QVBoxLayout (this); + auto *lay = new QVBoxLayout (this); lay->setContentsMargins(0, 0, 0, 0); - m_blackAndWhiteRadioButton = new QRadioButton (i18n ("&Monochrome"), this); m_blackAndWhiteDitheredRadioButton = new QRadioButton (i18n ("Mo&nochrome (dithered)"), this); m_8BitRadioButton = new QRadioButton (i18n ("256 co&lor"), this); m_8BitDitheredRadioButton = new QRadioButton (i18n ("256 colo&r (dithered)"), this); m_24BitRadioButton = new QRadioButton (i18n ("24-&bit color"), this); // LOCOMPAT: don't think this is needed - QButtonGroup *buttonGroup = new QButtonGroup (this); + auto *buttonGroup = new QButtonGroup (this); buttonGroup->addButton (m_blackAndWhiteRadioButton); buttonGroup->addButton (m_blackAndWhiteDitheredRadioButton); buttonGroup->addButton (m_8BitRadioButton); buttonGroup->addButton (m_8BitDitheredRadioButton); buttonGroup->addButton (m_24BitRadioButton); m_defaultRadioButton = m_24BitRadioButton; m_defaultRadioButton->setChecked (true); lay->addWidget (m_blackAndWhiteRadioButton); lay->addWidget (m_blackAndWhiteDitheredRadioButton); lay->addWidget (m_8BitRadioButton); lay->addWidget (m_8BitDitheredRadioButton); lay->addWidget (m_24BitRadioButton); connect (m_blackAndWhiteRadioButton, &QRadioButton::toggled, this, &kpEffectReduceColorsWidget::settingsChanged); connect (m_blackAndWhiteDitheredRadioButton, &QRadioButton::toggled, this, &kpEffectReduceColorsWidget::settingsChanged); connect (m_8BitRadioButton, &QRadioButton::toggled, this, &kpEffectReduceColorsWidget::settingsChanged); connect (m_8BitDitheredRadioButton, &QRadioButton::toggled, this, &kpEffectReduceColorsWidget::settingsChanged); connect (m_24BitRadioButton, &QRadioButton::toggled, this, &kpEffectReduceColorsWidget::settingsChanged); } //--------------------------------------------------------------------- // public int kpEffectReduceColorsWidget::depth () const { // These values (1, 8, 32) are QImage's supported depths. // TODO: Qt-4.7.1: 1, 8, 16, 24 and 32 if (m_blackAndWhiteRadioButton->isChecked () || m_blackAndWhiteDitheredRadioButton->isChecked ()) { return 1; } - else if (m_8BitRadioButton->isChecked () || + + if (m_8BitRadioButton->isChecked () || m_8BitDitheredRadioButton->isChecked ()) { return 8; } - else if (m_24BitRadioButton->isChecked ()) + + if (m_24BitRadioButton->isChecked ()) { return 32; } - else - { - return 0; - } + + return 0; } //--------------------------------------------------------------------- // public bool kpEffectReduceColorsWidget::dither () const { return (m_blackAndWhiteDitheredRadioButton->isChecked () || m_8BitDitheredRadioButton->isChecked ()); } //--------------------------------------------------------------------- // // kpEffectReduceColorsWidget implements kpEffectWidgetBase interface // // public virtual [base kpEffectWidgetBase] QString kpEffectReduceColorsWidget::caption () const { return i18n ("Reduce To"); } //--------------------------------------------------------------------- // public virtual [base kpEffectWidgetBase] bool kpEffectReduceColorsWidget::isNoOp () const { return (!m_defaultRadioButton || m_defaultRadioButton->isChecked ()); } //--------------------------------------------------------------------- // public virtual [base kpEffectWidgetBase] kpImage kpEffectReduceColorsWidget::applyEffect (const kpImage &image) { return kpEffectReduceColors::applyEffect (image, depth (), dither ()); } //--------------------------------------------------------------------- // public virtual [base kpEffectWidgetBase] kpEffectCommandBase *kpEffectReduceColorsWidget::createCommand ( kpCommandEnvironment *cmdEnviron) const { return new kpEffectReduceColorsCommand (depth (), dither (), m_actOnSelection, cmdEnviron); } //--------------------------------------------------------------------- diff --git a/widgets/imagelib/effects/kpEffectToneEnhanceWidget.cpp b/widgets/imagelib/effects/kpEffectToneEnhanceWidget.cpp index 7d1016d2..cb59c6b4 100644 --- a/widgets/imagelib/effects/kpEffectToneEnhanceWidget.cpp +++ b/widgets/imagelib/effects/kpEffectToneEnhanceWidget.cpp @@ -1,141 +1,139 @@ /* Copyright (c) 2003-2007 Clarence Dang Copyright (c) 2006 Mike Gashler All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include "kpEffectToneEnhanceWidget.h" #include "imagelib/effects/kpEffectToneEnhance.h" #include "commands/imagelib/effects/kpEffectToneEnhanceCommand.h" #include "pixmapfx/kpPixmapFX.h" #include "kpNumInput.h" #include #include #include "kpLogCategories.h" #include kpEffectToneEnhanceWidget::kpEffectToneEnhanceWidget (bool actOnSelection, QWidget *parent) : kpEffectWidgetBase (actOnSelection, parent), m_granularityInput (nullptr), m_amountInput (nullptr) { - QGridLayout *lay = new QGridLayout (this); + auto *lay = new QGridLayout (this); lay->setContentsMargins(0, 0, 0, 0); - // See kpEffectToneEnhance::applyEffect(). - { - QLabel *granularityLabel = new QLabel (i18n ("&Granularity:"), this); - QLabel *amountLabel = new QLabel (i18n ("&Amount:"), this); + auto *granularityLabel = new QLabel (i18n ("&Granularity:"), this); - m_granularityInput = new kpDoubleNumInput (this); - m_granularityInput->setRange (0, 1, 0.1/*step*/); + auto *amountLabel = new QLabel (i18n ("&Amount:"), this); - m_amountInput = new kpDoubleNumInput (this); - m_amountInput->setRange (0, 1, 0.1/*step*/); + m_granularityInput = new kpDoubleNumInput (this); + m_granularityInput->setRange (0, 1, 0.1/*step*/); - granularityLabel->setBuddy (m_granularityInput); - amountLabel->setBuddy (m_amountInput); + m_amountInput = new kpDoubleNumInput (this); + m_amountInput->setRange (0, 1, 0.1/*step*/); + granularityLabel->setBuddy (m_granularityInput); + amountLabel->setBuddy (m_amountInput); - lay->addWidget (granularityLabel, 0, 0); - lay->addWidget (m_granularityInput, 0, 1); - lay->addWidget (amountLabel, 1, 0); - lay->addWidget (m_amountInput, 1, 1); + lay->addWidget (granularityLabel, 0, 0); + lay->addWidget (m_granularityInput, 0, 1); - lay->setColumnStretch (1, 1); + lay->addWidget (amountLabel, 1, 0); + lay->addWidget (m_amountInput, 1, 1); + lay->setColumnStretch (1, 1); - connect (m_granularityInput, &kpDoubleNumInput::valueChanged, - this, &kpEffectToneEnhanceWidget::settingsChangedDelayed); - connect (m_amountInput, &kpDoubleNumInput::valueChanged, - this, &kpEffectToneEnhanceWidget::settingsChangedDelayed); - } -} + connect (m_granularityInput, &kpDoubleNumInput::valueChanged, + this, &kpEffectToneEnhanceWidget::settingsChangedDelayed); + + connect (m_amountInput, &kpDoubleNumInput::valueChanged, + this, &kpEffectToneEnhanceWidget::settingsChangedDelayed); -kpEffectToneEnhanceWidget::~kpEffectToneEnhanceWidget () -{ } +kpEffectToneEnhanceWidget::~kpEffectToneEnhanceWidget () = default; + // public virtual [base kpEffectWidgetBase] QString kpEffectToneEnhanceWidget::caption () const { // TODO: Why doesn't this have a caption? Ditto for the other effects. return QString(); } // private double kpEffectToneEnhanceWidget::amount () const { return m_amountInput ? m_amountInput->value () : 0; } // private double kpEffectToneEnhanceWidget::granularity () const { return m_granularityInput ? m_granularityInput->value () : 0; } // public virtual [base kpEffectWidgetBase] bool kpEffectToneEnhanceWidget::isNoOp () const { // If the "amount" is 0, nothing happens regardless of the granularity. // Note that if "granularity" is 0 but "amount" > 0, the effect _is_ active. // Therefore, "granularity" should have no involvement in this check. - if (amount () == 0) + if (amount () == 0) { return true; - else - return false; + } + + return false; } // public virtual [base kpEffectWidgetBase] kpImage kpEffectToneEnhanceWidget::applyEffect (const kpImage &image) { return kpEffectToneEnhance::applyEffect (image, granularity (), amount ()); } // public virtual [base kpEffectWidgetBase] kpEffectCommandBase *kpEffectToneEnhanceWidget::createCommand ( kpCommandEnvironment *cmdEnviron) const { return new kpEffectToneEnhanceCommand (granularity (), amount (), m_actOnSelection, cmdEnviron); } diff --git a/widgets/imagelib/effects/kpEffectWidgetBase.cpp b/widgets/imagelib/effects/kpEffectWidgetBase.cpp index ae0a0d6a..ba00e854 100644 --- a/widgets/imagelib/effects/kpEffectWidgetBase.cpp +++ b/widgets/imagelib/effects/kpEffectWidgetBase.cpp @@ -1,50 +1,48 @@ /* Copyright (c) 2003-2007 Clarence Dang All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include "kpEffectWidgetBase.h" kpEffectWidgetBase::kpEffectWidgetBase (bool actOnSelection, QWidget *parent) : QWidget (parent), m_actOnSelection (actOnSelection) { } -kpEffectWidgetBase::~kpEffectWidgetBase () -{ -} +kpEffectWidgetBase::~kpEffectWidgetBase () = default; // public QString kpEffectWidgetBase::caption () const { return QString(); } diff --git a/widgets/imagelib/effects/kpNumInput.cpp b/widgets/imagelib/effects/kpNumInput.cpp index 17771256..ca8e8fe7 100644 --- a/widgets/imagelib/effects/kpNumInput.cpp +++ b/widgets/imagelib/effects/kpNumInput.cpp @@ -1,710 +1,710 @@ /* This file is part of the KDE libraries * Initial implementation: * Copyright (c) 1997 Patrick Dowler * Rewritten and maintained by: * Copyright (c) 2000 Dirk Mueller * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This library 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 * Library General Public License for more details. * * You should have received a copy of the GNU Library General Public License * along with this library; see the file COPYING.LIB. If not, write to * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, * Boston, MA 02110-1301, USA. */ #include "kpNumInput.h" #include #include #include #include #include #include #include #include #include #include static inline int calcDiffByTen(int x, int y) { // calculate ( x - y ) / 10 without overflowing ints: return (x / 10) - (y / 10) + (x % 10 - y % 10) / 10; } // ---------------------------------------------------------------------------- class kpNumInputPrivate { public: kpNumInputPrivate(kpNumInput *q) : q(q), column1Width(0), column2Width(0), label(nullptr), slider(nullptr), labelAlignment(nullptr) { } static kpNumInputPrivate *get(const kpNumInput *i) { return i->d; } kpNumInput *q; int column1Width, column2Width; QLabel *label; QSlider *slider; QSize sliderSize, labelSize; Qt::Alignment labelAlignment; }; #define K_USING_kpNumInput_P(_d) kpNumInputPrivate *_d = kpNumInputPrivate::get(this) kpNumInput::kpNumInput(QWidget *parent) : QWidget(parent), d(new kpNumInputPrivate(this)) { setSizePolicy(QSizePolicy(QSizePolicy::Minimum, QSizePolicy::Fixed)); setFocusPolicy(Qt::StrongFocus); KConfigDialogManager::changedMap()->insert("kpIntNumInput", SIGNAL(valueChanged(int))); KConfigDialogManager::changedMap()->insert("QSpinBox", SIGNAL(valueChanged(int))); KConfigDialogManager::changedMap()->insert("kpDoubleSpinBox", SIGNAL(valueChanged(double))); } kpNumInput::~kpNumInput() { delete d; } QSlider *kpNumInput::slider() const { return d->slider; } bool kpNumInput::showSlider() const { return d->slider; } void kpNumInput::setLabel(const QString &label, Qt::Alignment a) { if (label.isEmpty()) { delete d->label; d->label = nullptr; d->labelAlignment = nullptr; } else { if (!d->label) { d->label = new QLabel(this); } d->label->setText(label); d->label->setObjectName("kpNumInput::QLabel"); d->label->setAlignment(a); // if no vertical alignment set, use Top alignment if (!(a & (Qt::AlignTop | Qt::AlignBottom | Qt::AlignVCenter))) { a |= Qt::AlignTop; } d->labelAlignment = a; } layout(); } QString kpNumInput::label() const { return d->label ? d->label->text() : QString(); } void kpNumInput::layout() { // label sizeHint d->labelSize = (d->label ? d->label->sizeHint() : QSize(0, 0)); if (d->label && (d->labelAlignment & Qt::AlignVCenter)) { d->column1Width = d->labelSize.width() + 4; } else { d->column1Width = 0; } // slider sizeHint d->sliderSize = (d->slider ? d->slider->sizeHint() : QSize(0, 0)); doLayout(); } QSize kpNumInput::sizeHint() const { return minimumSizeHint(); } void kpNumInput::setSteps(int minor, int major) { if (d->slider) { d->slider->setSingleStep(minor); d->slider->setPageStep(major); } } // ---------------------------------------------------------------------------- class kpIntNumInput::kpIntNumInputPrivate { public: kpIntNumInput *q; QSpinBox *intSpinBox; QSize intSpinBoxSize; kpIntNumInputPrivate(kpIntNumInput *q) : q(q) {} }; kpIntNumInput::kpIntNumInput(QWidget *parent) : kpNumInput(parent) , d(new kpIntNumInputPrivate(this)) { initWidget(0); } kpIntNumInput::kpIntNumInput(int val, QWidget *parent) : kpNumInput(parent) , d(new kpIntNumInputPrivate(this)) { initWidget(val); } QSpinBox *kpIntNumInput::spinBox() const { return d->intSpinBox; } void kpIntNumInput::initWidget(int val) { d->intSpinBox = new QSpinBox(this); d->intSpinBox->setRange(INT_MIN, INT_MAX); d->intSpinBox->setSingleStep(1); d->intSpinBox->setValue(val); d->intSpinBox->setObjectName("kpIntNumInput::QSpinBox"); connect(d->intSpinBox, QOverload::of(&QSpinBox::valueChanged), this, &kpIntNumInput::spinValueChanged); setFocusProxy(d->intSpinBox); layout(); } void kpIntNumInput::spinValueChanged(int val) { K_USING_kpNumInput_P(priv); if (priv->slider) { priv->slider->setValue(val); } emit valueChanged(val); } void kpIntNumInput::setRange(int lower, int upper, int singleStep) { if (upper < lower || singleStep <= 0) { qDebug() << "WARNING: kpIntNumInput::setRange() called with bad arguments. Ignoring call..."; return; } d->intSpinBox->setMinimum(lower); d->intSpinBox->setMaximum(upper); d->intSpinBox->setSingleStep(singleStep); singleStep = d->intSpinBox->singleStep(); // maybe QRangeControl didn't like our lineStep? layout(); // update slider information K_USING_kpNumInput_P(priv); if (!priv->slider) { priv->slider = new QSlider(Qt::Horizontal, this); connect(priv->slider, &QSlider::valueChanged, d->intSpinBox, &QSpinBox::setValue); priv->slider->setTickPosition(QSlider::TicksBelow); layout(); } const int value = d->intSpinBox->value(); priv->slider->setRange(d->intSpinBox->minimum(), d->intSpinBox->maximum()); priv->slider->setPageStep(d->intSpinBox->singleStep()); priv->slider->setValue(value); // calculate (upper-lower)/10 without overflowing int's: const int major = calcDiffByTen(d->intSpinBox->maximum(), d->intSpinBox->minimum()); priv->slider->setSingleStep(d->intSpinBox->singleStep()); priv->slider->setPageStep(qMax(1, major)); priv->slider->setTickInterval(major); } void kpIntNumInput::setMinimum(int min) { setRange(min, d->intSpinBox->maximum(), d->intSpinBox->singleStep()); } int kpIntNumInput::minimum() const { return d->intSpinBox->minimum(); } void kpIntNumInput::setMaximum(int max) { setRange(d->intSpinBox->minimum(), max, d->intSpinBox->singleStep()); } int kpIntNumInput::maximum() const { return d->intSpinBox->maximum(); } int kpIntNumInput::singleStep() const { return d->intSpinBox->singleStep(); } void kpIntNumInput::setSingleStep(int singleStep) { d->intSpinBox->setSingleStep(singleStep); } void kpIntNumInput::setSuffix(const QString &suffix) { d->intSpinBox->setSuffix(suffix); layout(); } QString kpIntNumInput::suffix() const { return d->intSpinBox->suffix(); } void kpIntNumInput::setEditFocus(bool mark) { if (mark) { d->intSpinBox->setFocus(); } } QSize kpIntNumInput::minimumSizeHint() const { K_USING_kpNumInput_P(priv); ensurePolished(); int w; int h; h = qMax(d->intSpinBoxSize.height(), priv->sliderSize.height()); // if in extra row, then count it here if (priv->label && (priv->labelAlignment & (Qt::AlignBottom | Qt::AlignTop))) { h += 4 + priv->labelSize.height(); } else { // label is in the same row as the other widgets h = qMax(h, priv->labelSize.height() + 2); } const int spacingHint = style()->pixelMetric(QStyle::PM_DefaultLayoutSpacing); w = priv->slider ? priv->slider->sizeHint().width() + spacingHint : 0; w += priv->column1Width + priv->column2Width; if (priv->labelAlignment & (Qt::AlignTop | Qt::AlignBottom)) { w = qMax(w, priv->labelSize.width() + 4); } - return QSize(w, h); + return {w, h}; } void kpIntNumInput::doLayout() { K_USING_kpNumInput_P(priv); d->intSpinBoxSize = d->intSpinBox->sizeHint(); priv->column2Width = d->intSpinBoxSize.width(); if (priv->label) { priv->label->setBuddy(d->intSpinBox); } } void kpIntNumInput::resizeEvent(QResizeEvent *e) { K_USING_kpNumInput_P(priv); int w = priv->column1Width; int h = 0; const int spacingHint = style()->pixelMetric(QStyle::PM_DefaultLayoutSpacing); if (priv->label && (priv->labelAlignment & Qt::AlignTop)) { priv->label->setGeometry(0, 0, e->size().width(), priv->labelSize.height()); h += priv->labelSize.height() + spacingHint; } if (priv->label && (priv->labelAlignment & Qt::AlignVCenter)) { priv->label->setGeometry(0, 0, w, d->intSpinBoxSize.height()); } if (qApp->layoutDirection() == Qt::RightToLeft) { d->intSpinBox->setGeometry(w, h, priv->slider ? priv->column2Width : qMax(priv->column2Width, e->size().width() - w), d->intSpinBoxSize.height()); w += priv->column2Width + spacingHint; if (priv->slider) { priv->slider->setGeometry(w, h, e->size().width() - w, d->intSpinBoxSize.height() + spacingHint); } } else if (priv->slider) { priv->slider->setGeometry(w, h, e->size().width() - (w + priv->column2Width + spacingHint), d->intSpinBoxSize.height() + spacingHint); d->intSpinBox->setGeometry(w + priv->slider->size().width() + spacingHint, h, priv->column2Width, d->intSpinBoxSize.height()); } else { d->intSpinBox->setGeometry(w, h, qMax(priv->column2Width, e->size().width() - w), d->intSpinBoxSize.height()); } h += d->intSpinBoxSize.height() + 2; if (priv->label && (priv->labelAlignment & Qt::AlignBottom)) { priv->label->setGeometry(0, h, priv->labelSize.width(), priv->labelSize.height()); } } kpIntNumInput::~kpIntNumInput() { delete d; } void kpIntNumInput::setValue(int val) { d->intSpinBox->setValue(val); // slider value is changed by spinValueChanged } int kpIntNumInput::value() const { return d->intSpinBox->value(); } void kpIntNumInput::setSpecialValueText(const QString &text) { d->intSpinBox->setSpecialValueText(text); layout(); } QString kpIntNumInput::specialValueText() const { return d->intSpinBox->specialValueText(); } void kpIntNumInput::setLabel(const QString &label, Qt::Alignment a) { K_USING_kpNumInput_P(priv); kpNumInput::setLabel(label, a); if (priv->label) { priv->label->setBuddy(d->intSpinBox); } } // ---------------------------------------------------------------------------- class kpDoubleNumInput::kpDoubleNumInputPrivate { public: kpDoubleNumInputPrivate() : spin(nullptr) {} QDoubleSpinBox *spin; QSize editSize; QString specialValue; }; kpDoubleNumInput::kpDoubleNumInput(QWidget *parent) : kpNumInput(parent) , d(new kpDoubleNumInputPrivate()) { initWidget(0.0, 0.0, 9999.0, 0.01, 2); } kpDoubleNumInput::kpDoubleNumInput(double lower, double upper, double value, QWidget *parent, double singleStep, int precision) : kpNumInput(parent) , d(new kpDoubleNumInputPrivate()) { initWidget(value, lower, upper, singleStep, precision); } kpDoubleNumInput::~kpDoubleNumInput() { delete d; } QString kpDoubleNumInput::specialValueText() const { return d->specialValue; } void kpDoubleNumInput::initWidget(double value, double lower, double upper, double singleStep, int precision) { d->spin = new QDoubleSpinBox(this); d->spin->setRange(lower, upper); d->spin->setSingleStep(singleStep); d->spin->setValue(value); d->spin->setDecimals(precision); d->spin->setObjectName("kpDoubleNumInput::QDoubleSpinBox"); setFocusProxy(d->spin); connect(d->spin, QOverload::of(&QDoubleSpinBox::valueChanged), this, &kpDoubleNumInput::valueChanged); layout(); } double kpDoubleNumInput::mapSliderToSpin(int val) const { K_USING_kpNumInput_P(priv); // map [slidemin,slidemax] to [spinmin,spinmax] const double spinmin = d->spin->minimum(); const double spinmax = d->spin->maximum(); const double slidemin = priv->slider->minimum(); // cast int to double to avoid const double slidemax = priv->slider->maximum(); // overflow in rel denominator const double rel = (double(val) - slidemin) / (slidemax - slidemin); return spinmin + rel * (spinmax - spinmin); } void kpDoubleNumInput::sliderMoved(int val) { d->spin->setValue(mapSliderToSpin(val)); } void kpDoubleNumInput::spinBoxChanged(double val) { K_USING_kpNumInput_P(priv); const double spinmin = d->spin->minimum(); const double spinmax = d->spin->maximum(); const double slidemin = priv->slider->minimum(); // cast int to double to avoid const double slidemax = priv->slider->maximum(); // overflow in rel denominator const double rel = (val - spinmin) / (spinmax - spinmin); if (priv->slider) { priv->slider->blockSignals(true); priv->slider->setValue(qRound(slidemin + rel * (slidemax - slidemin))); priv->slider->blockSignals(false); } } QSize kpDoubleNumInput::minimumSizeHint() const { K_USING_kpNumInput_P(priv); ensurePolished(); int w; int h; h = qMax(d->editSize.height(), priv->sliderSize.height()); // if in extra row, then count it here if (priv->label && (priv->labelAlignment & (Qt::AlignBottom | Qt::AlignTop))) { h += 4 + priv->labelSize.height(); } else { // label is in the same row as the other widgets h = qMax(h, priv->labelSize.height() + 2); } const int spacingHint = style()->pixelMetric(QStyle::PM_DefaultLayoutSpacing); w = priv->slider ? priv->slider->sizeHint().width() + spacingHint : 0; w += priv->column1Width + priv->column2Width; if (priv->labelAlignment & (Qt::AlignTop | Qt::AlignBottom)) { w = qMax(w, priv->labelSize.width() + 4); } - return QSize(w, h); + return {w, h}; } void kpDoubleNumInput::resizeEvent(QResizeEvent *e) { K_USING_kpNumInput_P(priv); int w = priv->column1Width; int h = 0; const int spacingHint = style()->pixelMetric(QStyle::PM_DefaultLayoutSpacing); if (priv->label && (priv->labelAlignment & Qt::AlignTop)) { priv->label->setGeometry(0, 0, e->size().width(), priv->labelSize.height()); h += priv->labelSize.height() + 4; } if (priv->label && (priv->labelAlignment & Qt::AlignVCenter)) { priv->label->setGeometry(0, 0, w, d->editSize.height()); } if (qApp->layoutDirection() == Qt::RightToLeft) { d->spin->setGeometry(w, h, priv->slider ? priv->column2Width : e->size().width() - w, d->editSize.height()); w += priv->column2Width + spacingHint; if (priv->slider) { priv->slider->setGeometry(w, h, e->size().width() - w, d->editSize.height() + spacingHint); } } else if (priv->slider) { priv->slider->setGeometry(w, h, e->size().width() - (priv->column1Width + priv->column2Width + spacingHint), d->editSize.height() + spacingHint); d->spin->setGeometry(w + priv->slider->width() + spacingHint, h, priv->column2Width, d->editSize.height()); } else { d->spin->setGeometry(w, h, e->size().width() - w, d->editSize.height()); } h += d->editSize.height() + 2; if (priv->label && (priv->labelAlignment & Qt::AlignBottom)) { priv->label->setGeometry(0, h, priv->labelSize.width(), priv->labelSize.height()); } } void kpDoubleNumInput::doLayout() { K_USING_kpNumInput_P(priv); d->editSize = d->spin->sizeHint(); priv->column2Width = d->editSize.width(); } void kpDoubleNumInput::setValue(double val) { d->spin->setValue(val); } void kpDoubleNumInput::setRange(double lower, double upper, double singleStep) { K_USING_kpNumInput_P(priv); QDoubleSpinBox *spin = d->spin; d->spin->setRange(lower, upper); d->spin->setSingleStep(singleStep); const double range = spin->maximum() - spin->minimum(); const double steps = range * std::pow(10.0, spin->decimals()); if (!priv->slider) { priv->slider = new QSlider(Qt::Horizontal, this); priv->slider->setTickPosition(QSlider::TicksBelow); // feedback line: when one moves, the other moves, too: connect(priv->slider, &QSlider::valueChanged, this, &kpDoubleNumInput::sliderMoved); layout(); } if (steps > 1000 ) { priv->slider->setRange(0, 1000); priv->slider->setSingleStep(1); priv->slider->setPageStep(50); } else { const int singleSteps = qRound(steps); priv->slider->setRange(0, singleSteps); priv->slider->setSingleStep(1); const int pageSteps = qBound(1, singleSteps / 20, 10); priv->slider->setPageStep(pageSteps); } spinBoxChanged(spin->value()); connect(spin, QOverload::of(&QDoubleSpinBox::valueChanged), this, &kpDoubleNumInput::spinBoxChanged); layout(); } void kpDoubleNumInput::setMinimum(double min) { setRange(min, maximum(), d->spin->singleStep()); } double kpDoubleNumInput::minimum() const { return d->spin->minimum(); } void kpDoubleNumInput::setMaximum(double max) { setRange(minimum(), max, d->spin->singleStep()); } double kpDoubleNumInput::maximum() const { return d->spin->maximum(); } double kpDoubleNumInput::singleStep() const { return d->spin->singleStep(); } void kpDoubleNumInput::setSingleStep(double singleStep) { d->spin->setSingleStep(singleStep); } double kpDoubleNumInput::value() const { return d->spin->value(); } QString kpDoubleNumInput::suffix() const { return d->spin->suffix(); } void kpDoubleNumInput::setSuffix(const QString &suffix) { d->spin->setSuffix(suffix); layout(); } void kpDoubleNumInput::setDecimals(int decimals) { d->spin->setDecimals(decimals); layout(); } int kpDoubleNumInput::decimals() const { return d->spin->decimals(); } void kpDoubleNumInput::setSpecialValueText(const QString &text) { d->spin->setSpecialValueText(text); layout(); } void kpDoubleNumInput::setLabel(const QString &label, Qt::Alignment a) { K_USING_kpNumInput_P(priv); kpNumInput::setLabel(label, a); if (priv->label) { priv->label->setBuddy(d->spin); } } #include "moc_kpNumInput.cpp" diff --git a/widgets/kpColorCells.cpp b/widgets/kpColorCells.cpp index 7f42cee0..45fe8a16 100644 --- a/widgets/kpColorCells.cpp +++ b/widgets/kpColorCells.cpp @@ -1,580 +1,588 @@ /* Copyright (c) 2003-2007 Clarence Dang All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include "widgets/kpColorCells.h" #include "imagelib/kpColor.h" #include "lgpl/generic/kpColorCollection.h" #include "widgets/kpDefaultColorCollection.h" #include "kpLogCategories.h" #include #include #include #include #include //--------------------------------------------------------------------- // // Table Geometry // // The number of columns that the table normally has. const int TableDefaultNumColumns = 11; const int TableDefaultWidth = ::TableDefaultNumColumns * 26; const int TableDefaultHeight = 52; static int TableNumColumns (const kpColorCollection &colorCol) { - if (colorCol.count () == 0) + if (colorCol.count () == 0) { return 0; + } return ::TableDefaultNumColumns; } static int TableNumRows (const kpColorCollection &colorCol) { const int cols = ::TableNumColumns (colorCol); - if (cols == 0) + if (cols == 0) { return 0; + } return (colorCol.count () + (cols - 1)) / cols; } static int TableCellWidth (const kpColorCollection &colorCol) { Q_UNUSED (colorCol); return ::TableDefaultWidth / ::TableDefaultNumColumns; } static int TableCellHeight (const kpColorCollection &colorCol) { - if (::TableNumRows (colorCol) <= 2) + if (::TableNumRows (colorCol) <= 2) { return ::TableDefaultHeight / 2; - else - return ::TableDefaultHeight / 3; + } + + return ::TableDefaultHeight / 3; } // // kpColorCells // struct kpColorCellsPrivate { - Qt::Orientation orientation; + Qt::Orientation orientation{}; // REFACTOR: This is data duplication with kpColorCellsBase::color[]. // We've probably forgotten to synchronize them in some points. // // Calls to kpColorCellsBase::setColor() (which also come from // kpColorCellsBase itself) will automatically update both // kpColorCellsBase::d->color[] and the table cells. setColor() emits // colorChanged(), which is caught by our slotColorChanged(), // which synchronizes this color collection and updates the modified flag. // // Avoid calling our grandparent's, QTableWidget's, mutating methods as we // don't override enough of them, to fire signals that we can catch to update // this color collection. // // If you modify this color collection directly (e.g. in setColorCollection(), // openColorCollection(), appendRow(), deleteLastRow(), ...), you must work // the other way and call makeCellsMatchColorCollection() to synchronize // kpColorCellsBase::d->color[] and the table cells. You still need to update // the modified flag. kpColorCollection colorCol; QUrl url; - bool isModified; + bool isModified{}; - bool blockColorChangedSig; + bool blockColorChangedSig{}; }; //--------------------------------------------------------------------- kpColorCells::kpColorCells (QWidget *parent, Qt::Orientation o) : kpColorCellsBase (parent, 0/*rows for now*/, 0/*cols for now*/), d (new kpColorCellsPrivate ()) { d->orientation = o; d->isModified = false; d->blockColorChangedSig = false; // When a text box is active, clicking to change the background color // should not move the keyboard focus away from the text box. setFocusPolicy (Qt::TabFocus); setShading (false); // no 3D look setAcceptDrops (true); setAcceptDrags (true); setCellsResizable (false); if (o == Qt::Horizontal) { // Reserve enough room for the default color collection's cells _and_ // a vertical scrollbar, which only appears when it's required. // This ensures that if the vertical scrollbar appears, it does not obscure // any cells or require the addition of a horizontal scrollbar, which would // look ugly and take even more precious room. // // We do not dynamically reserve room based on the actual number of rows // of cells, as that would make our containing widgets too big. setMinimumSize (::TableDefaultWidth + frameWidth () * 2 + verticalScrollBar()->sizeHint().width(), ::TableDefaultHeight + frameWidth () * 2); } else { Q_ASSERT (!"implemented"); } setVerticalScrollBarPolicy (Qt::ScrollBarAsNeeded); // The default QTableWidget policy of QSizePolicy::Expanding forces our // containing widgets to get too big. Override it. setSizePolicy (QSizePolicy::Minimum, QSizePolicy::Minimum); connect (this, &kpColorCells::colorSelectedWhitButton, this, &kpColorCells::slotColorSelected); connect (this, &kpColorCells::colorDoubleClicked, this, &kpColorCells::slotColorDoubleClicked); connect (this, &kpColorCells::colorChanged, this, &kpColorCells::slotColorChanged); setColorCollection (DefaultColorCollection ()); setWhatsThis ( i18n ( "" "

To select the foreground color that tools use to draw," " left-click on a filled-in color cell." " To select the background color, right-click instead.

" "

To change the color of a color cell itself, double-click on it.

" "

You can also swap the color of a filled-in cell with any other" " cell using drag and drop." " Also, if you hold down the Ctrl key, the destination" " cell's color will be" " overwritten, instead of being swapped with the color of the source cell.

" "
")); } //--------------------------------------------------------------------- kpColorCells::~kpColorCells () { delete d; } //--------------------------------------------------------------------- // public static kpColorCollection kpColorCells::DefaultColorCollection () { return kpDefaultColorCollection (); } //--------------------------------------------------------------------- // public Qt::Orientation kpColorCells::orientation () const { return d->orientation; } //--------------------------------------------------------------------- // public void kpColorCells::setOrientation (Qt::Orientation o) { d->orientation = o; makeCellsMatchColorCollection (); } //--------------------------------------------------------------------- // protected // OPT: Find out why this is being called multiple times on startup. void kpColorCells::makeCellsMatchColorCollection () { int c, r; if (orientation () == Qt::Horizontal) { c = ::TableNumColumns (d->colorCol); r = ::TableNumRows (d->colorCol); } else { c = ::TableNumRows (d->colorCol); - r = ::TableNumColumns (d->colorCol);; + r = ::TableNumColumns (d->colorCol); } qCDebug(kpLogWidgets) << "kpColorCells::makeCellsMatchColorCollection():" << "r=" << r << "c=" << c; qCDebug(kpLogWidgets) << "verticalScrollBar=" << verticalScrollBar () << " sizeHint=" << (verticalScrollBar () ? verticalScrollBar ()->sizeHint () : QSize (-12, -34)); // Delete all cell widgets. This ensures that there will be no left-over // cell widgets, for the colors in the new color collection that are // actually invalid (which should not have cell widgets). clearContents (); setRowCount (r); setColumnCount (c); int CellWidth = ::TableCellWidth (d->colorCol), CellHeight = ::TableCellHeight (d->colorCol); // TODO: Take a screenshot of KolourPaint, magnify it and you'll find the // cells don't have exactly the sizes requested here. e.g. the // top row of cells is 1 pixel shorter than the bottom row. There // are probably other glitches. - for (int y = 0; y < r; y++) + for (int y = 0; y < r; y++) { setRowHeight (y, CellHeight); - for (int x = 0; x < c; x++) + } + for (int x = 0; x < c; x++) { setColumnWidth (x, CellWidth); + } const bool oldBlockColorChangedSig = d->blockColorChangedSig; d->blockColorChangedSig = true; // The last "(rowCount() * columnCount()) - d->colorCol.count()" cells // will be empty because we did not initialize them. for (int i = 0; i < d->colorCol.count (); i++) { int y, x; int pos; if (orientation () == Qt::Horizontal) { y = i / c; x = i % c; pos = i; } else { y = i % r; x = i / r; // int x = c - 1 - i / r; pos = y * c + x; } qCDebug(kpLogWidgets) << "\tSetting cell " << i << ": y=" << y << " x=" << x - << " pos=" << pos << endl; + << " pos=" << pos; qCDebug(kpLogWidgets) << "\t\tcolor=" << (int *) d->colorCol.color (i).rgba() << "isValid=" << d->colorCol.color (i).isValid (); // (color may be invalid resulting in a hole in the middle of the table) setColor (pos, d->colorCol.color (i)); //this->setToolTip( cellGeometry (y, x), colors [i].name ()); } d->blockColorChangedSig = oldBlockColorChangedSig; } //--------------------------------------------------------------------- bool kpColorCells::isModified () const { return d->isModified; } //--------------------------------------------------------------------- void kpColorCells::setModified (bool yes) { qCDebug(kpLogWidgets) << "kpColorCells::setModified(" << yes << ")"; - if (yes == d->isModified) + if (yes == d->isModified) { return; + } d->isModified = yes; emit isModifiedChanged (yes); } //--------------------------------------------------------------------- void kpColorCells::setModified () { setModified (true); } //--------------------------------------------------------------------- QUrl kpColorCells::url () const { return d->url; } //--------------------------------------------------------------------- QString kpColorCells::name () const { return d->colorCol.name (); } //--------------------------------------------------------------------- const kpColorCollection *kpColorCells::colorCollection () const { return &d->colorCol; } //--------------------------------------------------------------------- void kpColorCells::ensureHaveAtLeastOneRow () { - if (d->colorCol.count () == 0) + if (d->colorCol.count () == 0) { d->colorCol.resize (::TableDefaultNumColumns); + } } //--------------------------------------------------------------------- void kpColorCells::setColorCollection (const kpColorCollection &colorCol, const QUrl &url) { d->colorCol = colorCol; ensureHaveAtLeastOneRow (); d->url = url; setModified (false); makeCellsMatchColorCollection (); emit rowCountChanged (rowCount ()); emit urlChanged (d->url); emit nameChanged (name ()); } //--------------------------------------------------------------------- bool kpColorCells::openColorCollection (const QUrl &url) { // (this will pop up an error dialog on failure) if (d->colorCol.open (url, this)) { ensureHaveAtLeastOneRow (); d->url = url; setModified (false); makeCellsMatchColorCollection (); emit rowCountChanged (rowCount ()); emit urlChanged (d->url); emit nameChanged (name ()); return true; } return false; } //--------------------------------------------------------------------- bool kpColorCells::saveColorCollectionAs (const QUrl &url) { // (this will pop up an error dialog on failure) if (d->colorCol.saveAs (url, true/*show overwrite prompt*/, this)) { d->url = url; setModified (false); emit urlChanged (d->url); return true; } return false; } //--------------------------------------------------------------------- bool kpColorCells::saveColorCollection () { // (this will pop up an error dialog on failure) if (d->colorCol.saveAs (d->url, false/*no overwrite prompt*/, this)) { setModified (false); return true; } return false; } //--------------------------------------------------------------------- void kpColorCells::appendRow () { // This is the easiest implementation: change the color collection // and then synchronize the table cells. The other way is to call // setRowCount() and then, synchronize the color collection. const int targetNumCells = (rowCount () + 1) * ::TableDefaultNumColumns; d->colorCol.resize (targetNumCells); setModified (true); makeCellsMatchColorCollection (); emit rowCountChanged (rowCount ()); } //--------------------------------------------------------------------- void kpColorCells::deleteLastRow () { // This is the easiest implementation: change the color collection // and then synchronize the table cells. The other way is to call // setRowCount() and then, synchronize the color collection. const int targetNumCells = qMax (0, (rowCount () - 1) * ::TableDefaultNumColumns); d->colorCol.resize (targetNumCells); // If there was only one row of colors to start with, the effect of this // line (after the above resize()) is to change that row to a row of // invalid colors. ensureHaveAtLeastOneRow (); setModified (true); makeCellsMatchColorCollection (); emit rowCountChanged (rowCount ()); } //--------------------------------------------------------------------- // protected virtual [base QWidget] void kpColorCells::contextMenuEvent (QContextMenuEvent *e) { // Eat right-mouse press to prevent it from getting to the toolbar. e->accept (); } //--------------------------------------------------------------------- // protected slot void kpColorCells::slotColorSelected (int cell, const QColor &color, Qt::MouseButton button) { qCDebug(kpLogWidgets) << "kpColorCells::slotColorSelected(cell=" << cell << ") mouseButton = " << button - << " rgb=" << (int *) color.rgba() - << endl; + << " rgb=" << (int *) color.rgba(); if (button == Qt::LeftButton) { emit foregroundColorChanged (kpColor (color.rgba())); } else if (button == Qt::RightButton) { emit backgroundColorChanged (kpColor (color.rgba())); } // REFACTOR: Make selectedness configurable inside kpColorCellsBase? // // Deselect the selected cell (selected by above kpColorCellsBase::mouseReleaseEvent()). // KolourPaint's palette has no concept of a current cell/color: you can // pick a color but you can't mark a cell as selected. In any case, a // selected cell would be rendered as violet, which would ruin the cell. // // setSelectionMode (kpColorCellsBase::NoSelection); does not work so we // clearSelection(). I think setSelectionMode() concerns when the user // directly selects a cell - not when kpColorCellsBase::mouseReleaseEvent() // selects a cell programmatically. clearSelection (); } //--------------------------------------------------------------------- // protected slot void kpColorCells::slotColorDoubleClicked (int cell, const QColor &) { QColorDialog dialog(this); dialog.setCurrentColor(kpColorCellsBase::color(cell)); dialog.setOptions(QColorDialog::ShowAlphaChannel); if ( dialog.exec() == QDialog::Accepted ) setColor (cell, dialog.currentColor()); } //--------------------------------------------------------------------- // protected slot void kpColorCells::slotColorChanged (int cell, const QColor &color) { qCDebug(kpLogWidgets) << "cell=" << cell << "color=" << (const int *) color.rgba() << "d->colorCol.count()=" << d->colorCol.count (); - if (d->blockColorChangedSig) + if (d->blockColorChangedSig) { return; + } // Cater for adding new colors to the end. - if (cell >= d->colorCol.count ()) + if (cell >= d->colorCol.count ()) { d->colorCol.resize (cell + 1); + } // TODO: We lose color names on a color swap (during drag-and-drop). const int ret = d->colorCol.changeColor (cell, color, QString ()/*color name*/); Q_ASSERT (ret == cell); setModified (true); } diff --git a/widgets/kpDefaultColorCollection.cpp b/widgets/kpDefaultColorCollection.cpp index b1889e60..cec8e1b3 100644 --- a/widgets/kpDefaultColorCollection.cpp +++ b/widgets/kpDefaultColorCollection.cpp @@ -1,70 +1,68 @@ /* Copyright (c) 2003-2007 Clarence Dang All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include "kpDefaultColorCollection.h" #include "imagelib/kpColor.h" kpDefaultColorCollection::kpDefaultColorCollection () { kpColor colors [] = { kpColor::Black, kpColor::Gray, kpColor::Red, kpColor::Orange, kpColor::Yellow, kpColor::Green, kpColor::Aqua, kpColor::Blue, kpColor::Purple, kpColor::Pink, kpColor::LightGreen, kpColor::White, kpColor::LightGray, kpColor::DarkRed, kpColor::DarkOrange, kpColor::DarkYellow, kpColor::DarkGreen, kpColor::DarkAqua, kpColor::DarkBlue, kpColor::DarkPurple, kpColor::LightBlue, kpColor::Tan }; - for (int i = 0; i < static_cast (sizeof (colors) / sizeof (colors [0])); i++) + for (const auto & color : colors) { - addColor (colors [i].toQColor ()); + addColor (color.toQColor ()); } } -kpDefaultColorCollection::~kpDefaultColorCollection () -{ -} +kpDefaultColorCollection::~kpDefaultColorCollection () = default; diff --git a/widgets/kpDocumentSaveOptionsWidget.cpp b/widgets/kpDocumentSaveOptionsWidget.cpp index f257f673..a4bf7f66 100644 --- a/widgets/kpDocumentSaveOptionsWidget.cpp +++ b/widgets/kpDocumentSaveOptionsWidget.cpp @@ -1,703 +1,697 @@ /* Copyright (c) 2003-2007 Clarence Dang All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include "widgets/kpDocumentSaveOptionsWidget.h" #include "kpDefs.h" #include "document/kpDocument.h" #include "dialogs/kpDocumentSaveOptionsPreviewDialog.h" #include "pixmapfx/kpPixmapFX.h" #include "generic/widgets/kpResizeSignallingLabel.h" #include "dialogs/imagelib/transforms/kpTransformPreviewDialog.h" #include "generic/kpWidgetMapper.h" #include "kpLogCategories.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include kpDocumentSaveOptionsWidget::kpDocumentSaveOptionsWidget ( const QImage &docPixmap, const kpDocumentSaveOptions &saveOptions, const kpDocumentMetaInfo &metaInfo, QWidget *parent) : QWidget (parent), m_visualParent (parent) { init (); setDocumentSaveOptions (saveOptions); setDocumentPixmap (docPixmap); setDocumentMetaInfo (metaInfo); } kpDocumentSaveOptionsWidget::kpDocumentSaveOptionsWidget ( QWidget *parent) : QWidget (parent), m_visualParent (parent) { init (); } // private void kpDocumentSaveOptionsWidget::init () { m_documentPixmap = nullptr; m_previewDialog = nullptr; m_visualParent = nullptr; m_colorDepthLabel = new QLabel (i18n ("Convert &to:"), this); m_colorDepthCombo = new QComboBox (this); m_colorDepthSpaceWidget = new QWidget (this); m_qualityLabel = new QLabel(i18n ("Quali&ty:"), this); m_qualityInput = new QSpinBox(this); // Note that we set min to 1 not 0 since "0 Quality" is a bit misleading // and 101 quality settings would be weird. So we lose 1 quality setting // according to QImage::save(). // TODO: 100 quality is also misleading since that implies perfect quality. m_qualityInput->setRange (1, 100); m_previewButton = new QPushButton (i18n ("&Preview"), this); m_previewButton->setCheckable (true); m_colorDepthLabel->setBuddy (m_colorDepthCombo); m_qualityLabel->setBuddy (m_qualityInput); - QHBoxLayout *lay = new QHBoxLayout (this); + auto *lay = new QHBoxLayout (this); lay->setContentsMargins(0, 0, 0, 0); lay->addWidget (m_colorDepthLabel, 0/*stretch*/, Qt::AlignLeft); lay->addWidget (m_colorDepthCombo, 0/*stretch*/); lay->addWidget (m_colorDepthSpaceWidget, 1/*stretch*/); lay->addWidget (m_qualityLabel, 0/*stretch*/, Qt::AlignLeft); lay->addWidget (m_qualityInput, 2/*stretch*/); lay->addWidget (m_previewButton, 0/*stretch*/, Qt::AlignRight); connect (m_colorDepthCombo, static_cast(&QComboBox::activated), this, &kpDocumentSaveOptionsWidget::slotColorDepthSelected); connect (m_colorDepthCombo, static_cast(&QComboBox::activated), this, &kpDocumentSaveOptionsWidget::updatePreview); connect (m_qualityInput, static_cast(&QSpinBox::valueChanged), this, &kpDocumentSaveOptionsWidget::updatePreviewDelayed); connect (m_previewButton, &QPushButton::toggled, this, &kpDocumentSaveOptionsWidget::showPreview); m_updatePreviewDelay = 200/*ms*/; m_updatePreviewTimer = new QTimer (this); m_updatePreviewTimer->setSingleShot (true); connect (m_updatePreviewTimer, &QTimer::timeout, this, &kpDocumentSaveOptionsWidget::updatePreview); m_updatePreviewDialogLastRelativeGeometryTimer = new QTimer (this); connect (m_updatePreviewDialogLastRelativeGeometryTimer, &QTimer::timeout, this, &kpDocumentSaveOptionsWidget::updatePreviewDialogLastRelativeGeometry); setMode (None); slotColorDepthSelected (); } kpDocumentSaveOptionsWidget::~kpDocumentSaveOptionsWidget () { qCDebug(kpLogWidgets) << "kpDocumentSaveOptionsWidget::()"; hidePreview (); delete m_documentPixmap; } // public void kpDocumentSaveOptionsWidget::setVisualParent (QWidget *visualParent) { qCDebug(kpLogWidgets) << "kpDocumentSaveOptionsWidget::setVisualParent(" << visualParent << ")"; m_visualParent = visualParent; } // protected bool kpDocumentSaveOptionsWidget::mimeTypeHasConfigurableColorDepth () const { return kpDocumentSaveOptions::mimeTypeHasConfigurableColorDepth (mimeType ()); } // protected bool kpDocumentSaveOptionsWidget::mimeTypeHasConfigurableQuality () const { return kpDocumentSaveOptions::mimeTypeHasConfigurableQuality (mimeType ()); } // public QString kpDocumentSaveOptionsWidget::mimeType () const { return m_baseDocumentSaveOptions.mimeType (); } // public slots void kpDocumentSaveOptionsWidget::setMimeType (const QString &string) { qCDebug(kpLogWidgets) << "kpDocumentSaveOptionsWidget::setMimeType(" << string << ") maxColorDepth=" << kpDocumentSaveOptions::mimeTypeMaximumColorDepth (string); const int newMimeTypeMaxDepth = kpDocumentSaveOptions::mimeTypeMaximumColorDepth (string); qCDebug(kpLogWidgets) << "\toldMimeType=" << mimeType () << " maxColorDepth=" << kpDocumentSaveOptions::mimeTypeMaximumColorDepth ( mimeType ()); if (mimeType ().isEmpty () || kpDocumentSaveOptions::mimeTypeMaximumColorDepth (mimeType ()) != newMimeTypeMaxDepth) { m_colorDepthCombo->clear (); m_colorDepthCombo->insertItem (0, i18n ("Monochrome")); m_colorDepthCombo->insertItem (1, i18n ("Monochrome (Dithered)")); if (newMimeTypeMaxDepth >= 8) { m_colorDepthCombo->insertItem (2, i18n ("256 Color")); m_colorDepthCombo->insertItem (3, i18n ("256 Color (Dithered)")); } if (newMimeTypeMaxDepth >= 24) { m_colorDepthCombo->insertItem (4, i18n ("24-bit Color")); } if (m_colorDepthComboLastSelectedItem >= 0 && m_colorDepthComboLastSelectedItem < m_colorDepthCombo->count ()) { qCDebug(kpLogWidgets) << "\tsetting colorDepthCombo to " << m_colorDepthComboLastSelectedItem; m_colorDepthCombo->setCurrentIndex (m_colorDepthComboLastSelectedItem); } else { qCDebug(kpLogWidgets) << "\tsetting colorDepthCombo to max item since" << " m_colorDepthComboLastSelectedItem=" << m_colorDepthComboLastSelectedItem << " out of range"; m_colorDepthCombo->setCurrentIndex (m_colorDepthCombo->count () - 1); } } m_baseDocumentSaveOptions.setMimeType (string); - if (mimeTypeHasConfigurableColorDepth ()) + if (mimeTypeHasConfigurableColorDepth ()) { setMode (ColorDepth); - else if (mimeTypeHasConfigurableQuality ()) + } + else if (mimeTypeHasConfigurableQuality ()) { setMode (Quality); - else + } + else { setMode (None); + } updatePreview (); } // public int kpDocumentSaveOptionsWidget::colorDepth () const { if (mode () & ColorDepth) { // The returned values match QImage's supported depths. switch (m_colorDepthCombo->currentIndex ()) { case 0: case 1: return 1; case 2: case 3: return 8; case 4: // 24-bit is known as 32-bit with QImage. return 32; default: return kpDocumentSaveOptions::invalidColorDepth (); } } else { return m_baseDocumentSaveOptions.colorDepth (); } } // public bool kpDocumentSaveOptionsWidget::dither () const { if (mode () & ColorDepth) { return (m_colorDepthCombo->currentIndex () == 1 || m_colorDepthCombo->currentIndex () == 3); } - else - { - return m_baseDocumentSaveOptions.dither (); - } + + return m_baseDocumentSaveOptions.dither (); } // protected static int kpDocumentSaveOptionsWidget::colorDepthComboItemFromColorDepthAndDither ( int depth, bool dither) { - if (depth == 1) - { - if (!dither) - { + switch (depth) { + case 1: + if (!dither) { return 0; } - else - { - return 1; - } - } - else if (depth == 8) - { - if (!dither) - { + return 1; + + case 8: + if (!dither) { return 2; } - else - { - return 3; - } - } - else if (depth == 32) - { + return 3; + + case 32: return 4; - } - else - { + + default: return -1; } } // public slots void kpDocumentSaveOptionsWidget::setColorDepthDither (int newDepth, bool newDither) { qCDebug(kpLogWidgets) << "kpDocumentSaveOptionsWidget::setColorDepthDither(" << "depth=" << newDepth << ",dither=" << newDither << ")"; m_baseDocumentSaveOptions.setColorDepth (newDepth); m_baseDocumentSaveOptions.setDither (newDither); const int comboItem = colorDepthComboItemFromColorDepthAndDither ( newDepth, newDither); // TODO: Ignoring when comboItem >= m_colorDepthCombo->count() is wrong. // This happens if this mimeType has configurable colour depth // and an incorrect maximum colour depth (less than a QImage of // this mimeType, opened by kpDocument). - if (comboItem >= 0 && comboItem < m_colorDepthCombo->count ()) + if (comboItem >= 0 && comboItem < m_colorDepthCombo->count ()) { m_colorDepthCombo->setCurrentIndex (comboItem); + } slotColorDepthSelected (); } // protected slot void kpDocumentSaveOptionsWidget::slotColorDepthSelected () { if (mode () & ColorDepth) { m_colorDepthComboLastSelectedItem = m_colorDepthCombo->currentIndex (); } else { m_colorDepthComboLastSelectedItem = colorDepthComboItemFromColorDepthAndDither ( m_baseDocumentSaveOptions.colorDepth (), m_baseDocumentSaveOptions.dither ()); } qCDebug(kpLogWidgets) << "kpDocumentSaveOptionsWidget::slotColorDepthSelected()" << " mode&ColorDepth=" << (mode () & ColorDepth) << " colorDepthComboLastSelectedItem=" << m_colorDepthComboLastSelectedItem; } // public int kpDocumentSaveOptionsWidget::quality () const { if (mode () & Quality) { return m_qualityInput->value (); } - else - { - return m_baseDocumentSaveOptions.quality (); - } + + return m_baseDocumentSaveOptions.quality (); } // public void kpDocumentSaveOptionsWidget::setQuality (int newQuality) { qCDebug(kpLogWidgets) << "kpDocumentSaveOptionsWidget::setQuality(" << newQuality << ")"; m_baseDocumentSaveOptions.setQuality (newQuality); m_qualityInput->setValue (newQuality == -1/*QImage::save() default*/ ? 75 : newQuality); } // public kpDocumentSaveOptions kpDocumentSaveOptionsWidget::documentSaveOptions () const { return kpDocumentSaveOptions (mimeType (), colorDepth (), dither (), quality ()); } // public void kpDocumentSaveOptionsWidget::setDocumentSaveOptions ( const kpDocumentSaveOptions &saveOptions) { setMimeType (saveOptions.mimeType ()); setColorDepthDither (saveOptions.colorDepth (), saveOptions.dither ()); setQuality (saveOptions.quality ()); } // public void kpDocumentSaveOptionsWidget::setDocumentPixmap (const QImage &documentPixmap) { delete m_documentPixmap; m_documentPixmap = new QImage (documentPixmap); updatePreview (); } // public void kpDocumentSaveOptionsWidget::setDocumentMetaInfo ( const kpDocumentMetaInfo &metaInfo) { m_documentMetaInfo = metaInfo; updatePreview (); } // public kpDocumentSaveOptionsWidget::Mode kpDocumentSaveOptionsWidget::mode () const { return m_mode; } // public void kpDocumentSaveOptionsWidget::setMode (Mode mode) { m_mode = mode; // If mode == None, we show still show the Color Depth widgets but disabled m_colorDepthLabel->setVisible (mode != Quality); m_colorDepthCombo->setVisible (mode != Quality); m_colorDepthSpaceWidget->setVisible (mode != Quality); m_qualityLabel->setVisible (mode == Quality); m_qualityInput->setVisible (mode == Quality); m_colorDepthLabel->setEnabled (mode == ColorDepth); m_colorDepthCombo->setEnabled (mode == ColorDepth); m_qualityLabel->setEnabled (mode == Quality); m_qualityInput->setEnabled (mode == Quality); // SYNC: HACK: When changing between color depth and quality widgets, // we change the height of "this", causing the text on the labels // to move but the first instance of the text doesn't get erased. // Qt bug. QTimer::singleShot (0, this, SLOT (repaintLabels())); } // protected slot void kpDocumentSaveOptionsWidget::repaintLabels () { - if (mode () != Quality) + if (mode () != Quality) { m_colorDepthLabel->repaint (); - if (mode () == Quality) + } + if (mode () == Quality) { m_qualityLabel->repaint (); + } } // protected slot void kpDocumentSaveOptionsWidget::showPreview (bool yes) { qCDebug(kpLogWidgets) << "kpDocumentSaveOptionsWidget::showPreview(" << yes << ")" << " m_previewDialog=" << bool (m_previewDialog); - if (yes == bool (m_previewDialog)) + if (yes == bool (m_previewDialog)) { return; + } - if (!m_visualParent) + if (!m_visualParent) { return; + } if (yes) { m_previewDialog = new kpDocumentSaveOptionsPreviewDialog( m_visualParent ); m_previewDialog->setObjectName( QLatin1String( "previewSaveDialog" ) ); updatePreview (); connect (m_previewDialog, &kpDocumentSaveOptionsPreviewDialog::finished, this, &kpDocumentSaveOptionsWidget::hidePreview); KConfigGroup cfg (KSharedConfig::openConfig (), kpSettingsGroupPreviewSave); if (cfg.hasKey (kpSettingPreviewSaveUpdateDelay)) { m_updatePreviewDelay = cfg.readEntry (kpSettingPreviewSaveUpdateDelay, 0); } else { cfg.writeEntry (kpSettingPreviewSaveUpdateDelay, m_updatePreviewDelay); cfg.sync (); } - if (m_updatePreviewDelay < 0) + if (m_updatePreviewDelay < 0) { m_updatePreviewDelay = 0; - qCDebug(kpLogWidgets) << "\tread cfg preview dialog update delay=" - << m_updatePreviewDelay; + } + qCDebug(kpLogWidgets) << "\tread cfg preview dialog update delay=" << m_updatePreviewDelay; if (m_previewDialogLastRelativeGeometry.isEmpty ()) { qCDebug(kpLogWidgets) << "\tread cfg preview dialog last rel geometry"; KConfigGroup cfg (KSharedConfig::openConfig (), kpSettingsGroupPreviewSave); m_previewDialogLastRelativeGeometry = cfg.readEntry ( kpSettingPreviewSaveGeometry, QRect ()); } qCDebug(kpLogWidgets) << "\tpreviewDialogLastRelativeGeometry=" << m_previewDialogLastRelativeGeometry << " visualParent->rect()=" << m_visualParent->rect (); QRect relativeGeometry; if (!m_previewDialogLastRelativeGeometry.isEmpty () && m_visualParent->rect ().intersects (m_previewDialogLastRelativeGeometry)) { qCDebug(kpLogWidgets) << "\tok"; relativeGeometry = m_previewDialogLastRelativeGeometry; } else { qCDebug(kpLogWidgets) << "\t\tinvalid"; const int margin = 20; relativeGeometry = QRect (m_visualParent->width () - m_previewDialog->preferredMinimumSize ().width () - margin, margin * 2, // Avoid folder combo m_previewDialog->preferredMinimumSize ().width (), m_previewDialog->preferredMinimumSize ().height ()); } const QRect globalGeometry = kpWidgetMapper::toGlobal (m_visualParent, relativeGeometry); qCDebug(kpLogWidgets) << "\trelativeGeometry=" << relativeGeometry << " globalGeometry=" << globalGeometry; m_previewDialog->resize (globalGeometry.size ()); m_previewDialog->move (globalGeometry.topLeft ()); m_previewDialog->show (); qCDebug(kpLogWidgets) << "\tgeometry after show=" << QRect (m_previewDialog->x (), m_previewDialog->y (), m_previewDialog->width (), m_previewDialog->height ()); updatePreviewDialogLastRelativeGeometry (); connect (m_previewDialog, &kpDocumentSaveOptionsPreviewDialog::moved, this, &kpDocumentSaveOptionsWidget::updatePreviewDialogLastRelativeGeometry); connect (m_previewDialog, &kpDocumentSaveOptionsPreviewDialog::resized, this, &kpDocumentSaveOptionsWidget::updatePreviewDialogLastRelativeGeometry); m_updatePreviewDialogLastRelativeGeometryTimer->start (200/*ms*/); } else { m_updatePreviewDialogLastRelativeGeometryTimer->stop (); KConfigGroup cfg (KSharedConfig::openConfig (), kpSettingsGroupPreviewSave); cfg.writeEntry (kpSettingPreviewSaveGeometry, m_previewDialogLastRelativeGeometry); cfg.sync (); qCDebug(kpLogWidgets) << "\tsaving preview geometry " << m_previewDialogLastRelativeGeometry << " (Qt would have us believe " << kpWidgetMapper::fromGlobal (m_visualParent, QRect (m_previewDialog->x (), m_previewDialog->y (), m_previewDialog->width (), m_previewDialog->height ())) << ")"; m_previewDialog->deleteLater (); m_previewDialog = nullptr; } } // protected slot void kpDocumentSaveOptionsWidget::hidePreview () { - if (m_previewButton->isChecked ()) + if (m_previewButton->isChecked ()) { m_previewButton->toggle (); + } } // protected slot void kpDocumentSaveOptionsWidget::updatePreviewDelayed () { // (single shot) m_updatePreviewTimer->start (m_updatePreviewDelay); } // protected slot void kpDocumentSaveOptionsWidget::updatePreview () { - if (!m_previewDialog || !m_documentPixmap) + if (!m_previewDialog || !m_documentPixmap) { return; + } m_updatePreviewTimer->stop (); QApplication::setOverrideCursor (Qt::WaitCursor); QByteArray data; QBuffer buffer (&data); buffer.open (QIODevice::WriteOnly); bool savedOK = kpDocument::savePixmapToDevice (*m_documentPixmap, &buffer, documentSaveOptions (), m_documentMetaInfo, false/*no lossy prompt*/, this); buffer.close (); QImage image; // Ignore any failed saves. // // Failed saves might literally have written half a file. The final // save (when the user clicks OK), _will_ fail so we shouldn't have a // preview even if this "half a file" is actually loadable by // QImage::loadFormData(). if (savedOK) { image.loadFromData(data); } else { // Leave as invalid. // TODO: This code path has not been well tested. // Will we trigger divide by zero errors in "m_previewDialog"? } // REFACTOR: merge with kpDocument::getPixmapFromFile() m_previewDialog->setFilePixmapAndSize (image, data.size ()); QApplication::restoreOverrideCursor (); } // protected slot void kpDocumentSaveOptionsWidget::updatePreviewDialogLastRelativeGeometry () { qCDebug(kpLogWidgets) << "kpDocumentSaveOptionsWidget::" << "updatePreviewDialogLastRelativeGeometry()"; if (m_previewDialog && m_previewDialog->isVisible ()) { m_previewDialogLastRelativeGeometry = kpWidgetMapper::fromGlobal (m_visualParent, QRect (m_previewDialog->x (), m_previewDialog->y (), m_previewDialog->width (), m_previewDialog->height ())); qCDebug(kpLogWidgets) << "\tcaching pos = " - << m_previewDialogLastRelativeGeometry - << endl; + << m_previewDialogLastRelativeGeometry; } else { qCDebug(kpLogWidgets) << "\tnot visible - ignoring geometry"; } } diff --git a/widgets/kpDualColorButton.cpp b/widgets/kpDualColorButton.cpp index e5427770..cd4da1ff 100644 --- a/widgets/kpDualColorButton.cpp +++ b/widgets/kpDualColorButton.cpp @@ -1,438 +1,444 @@ /* Copyright (c) 2003-2007 Clarence Dang All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #define DEBUG_KP_DUAL_COLOR_BUTTON 0 #include "kpDualColorButton.h" #include "views/kpView.h" #include #include "kpLogCategories.h" #include #include #include #include #include #include #include #include //--------------------------------------------------------------------- kpDualColorButton::kpDualColorButton (QWidget *parent) : QFrame (parent), m_dragStartPoint (KP_INVALID_POINT) { setSizePolicy (QSizePolicy::Fixed/*horizontal*/, QSizePolicy::Fixed/*vertical*/); setFrameStyle (QFrame::Panel | QFrame::Sunken); m_color [0] = kpColor (0, 0, 0); // black m_color [1] = kpColor (255, 255, 255); // white setAcceptDrops (true); } //--------------------------------------------------------------------- kpColor kpDualColorButton::color (int which) const { Q_ASSERT (which == 0 || which == 1); return m_color [which]; } //--------------------------------------------------------------------- kpColor kpDualColorButton::foregroundColor () const { return color (0); } //--------------------------------------------------------------------- kpColor kpDualColorButton::backgroundColor () const { return color (1); } //--------------------------------------------------------------------- void kpDualColorButton::setColor (int which, const kpColor &color) { Q_ASSERT (which == 0 || which == 1); - if (m_color [which] == color) + if (m_color [which] == color) { return; + } m_oldColor [which] = m_color [which]; m_color [which] = color; update (); - if (which == 0) + if (which == 0) { emit foregroundColorChanged (color); - else + } + else { emit backgroundColorChanged (color); + } } //--------------------------------------------------------------------- void kpDualColorButton::setForegroundColor (const kpColor &color) { setColor (0, color); } //--------------------------------------------------------------------- void kpDualColorButton::setBackgroundColor (const kpColor &color) { setColor (1, color); } //--------------------------------------------------------------------- // public kpColor kpDualColorButton::oldForegroundColor () const { return m_oldColor [0]; } //--------------------------------------------------------------------- // public kpColor kpDualColorButton::oldBackgroundColor () const { return m_oldColor [1]; } //--------------------------------------------------------------------- // public virtual [base QWidget] QSize kpDualColorButton::sizeHint () const { - return QSize (52, 52); + return {52, 52}; } //--------------------------------------------------------------------- // protected QRect kpDualColorButton::swapPixmapRect () const { QPixmap swapPixmap = UserIcon ("colorbutton_swap_16x16"); - return QRect (contentsRect ().width () - swapPixmap.width (), - 0, - swapPixmap.width (), - swapPixmap.height ()); + return {contentsRect ().width () - swapPixmap.width (), 0, + swapPixmap.width (), swapPixmap.height ()}; } //--------------------------------------------------------------------- // protected QRect kpDualColorButton::foregroundBackgroundRect () const { QRect cr (contentsRect ()); - return QRect (cr.width () / 8, - cr.height () / 8, - cr.width () * 6 / 8, - cr.height () * 6 / 8); + return {cr.width () / 8, cr.height () / 8, + cr.width () * 6 / 8, cr.height () * 6 / 8}; } //--------------------------------------------------------------------- // protected QRect kpDualColorButton::foregroundRect () const { QRect fbr (foregroundBackgroundRect ()); - return QRect (fbr.x (), - fbr.y (), - fbr.width () * 3 / 4, - fbr.height () * 3 / 4); + return {fbr.x (), fbr.y (), + fbr.width () * 3 / 4, fbr.height () * 3 / 4}; } //--------------------------------------------------------------------- // protected QRect kpDualColorButton::backgroundRect () const { QRect fbr (foregroundBackgroundRect ()); - return QRect (fbr.x () + fbr.width () / 4, - fbr.y () + fbr.height () / 4, - fbr.width () * 3 / 4, - fbr.height () * 3 / 4); + return {fbr.x () + fbr.width () / 4, fbr.y () + fbr.height () / 4, + fbr.width () * 3 / 4, fbr.height () * 3 / 4}; } //--------------------------------------------------------------------- // protected virtual void kpDualColorButton::dragEnterEvent (QDragEnterEvent *e) { qCDebug(kpLogWidgets) << "kpDualColorButton::dragEnterEvent() canDecode=" - << KColorMimeData::canDecode (e->mimeData ()) - << endl; + << KColorMimeData::canDecode (e->mimeData ()); e->accept (); } //--------------------------------------------------------------------- // protected virtual [base QWidget] void kpDualColorButton::dragMoveEvent (QDragMoveEvent *e) { qCDebug(kpLogWidgets) << "kpDualColorButton::dragMoveEvent() canDecode=" - << KColorMimeData::canDecode (e->mimeData ()) - << endl; + << KColorMimeData::canDecode (e->mimeData ()); e->setAccepted ( (foregroundRect ().contains (e->pos ()) || backgroundRect ().contains (e->pos ())) && KColorMimeData::canDecode (e->mimeData ())); } //--------------------------------------------------------------------- // protected virtual [base QWidget] void kpDualColorButton::dropEvent (QDropEvent *e) { QColor col = KColorMimeData::fromMimeData (e->mimeData ()); qCDebug(kpLogWidgets) << "kpDualColorButton::dropEvent() col=" << (int *) col.rgba() - << " (with alpha=" << (int *) col.rgba () << ")" << endl; + << " (with alpha=" << (int *) col.rgba () << ")"; if (col.isValid ()) { - if (foregroundRect ().contains (e->pos ())) + if (foregroundRect ().contains (e->pos ())) { setForegroundColor (kpColor (col.rgba())); - else if (backgroundRect ().contains (e->pos ())) + } + else if (backgroundRect ().contains (e->pos ())) { setBackgroundColor (kpColor (col.rgba())); + } } } //--------------------------------------------------------------------- // protected virtual [base QWidget] void kpDualColorButton::mousePressEvent (QMouseEvent *e) { qCDebug(kpLogWidgets) << "kpDualColorButton::mousePressEvent() pos=" << e->pos (); m_dragStartPoint = KP_INVALID_POINT; - if (e->button () == Qt::LeftButton) + if (e->button () == Qt::LeftButton) { m_dragStartPoint = e->pos (); + } } //--------------------------------------------------------------------- void kpDualColorButton::mouseMoveEvent (QMouseEvent *e) { qCDebug(kpLogWidgets) << "kpDualColorButton::mouseMoveEvent() pos=" << e->pos () << " buttons=" << e->buttons () << " dragStartPoint=" << m_dragStartPoint; - if (m_dragStartPoint == KP_INVALID_POINT) + if (m_dragStartPoint == KP_INVALID_POINT) { return; + } if (!(e->buttons () & Qt::LeftButton)) { m_dragStartPoint = KP_INVALID_POINT; return; } const int delay = QApplication::startDragDistance (); if (e->x () < m_dragStartPoint.x () - delay || e->x () > m_dragStartPoint.x () + delay || e->y () < m_dragStartPoint.y () - delay || e->y () > m_dragStartPoint.y () + delay) { qCDebug(kpLogWidgets) << "\tstarting drag as long as it's in a rectangle"; kpColor color; - if (foregroundRect ().contains (m_dragStartPoint)) + if (foregroundRect ().contains (m_dragStartPoint)) { color = foregroundColor (); - else if (backgroundRect ().contains (m_dragStartPoint)) + } + else if (backgroundRect ().contains (m_dragStartPoint)) { color = backgroundColor (); - else - { - // "color" is left as invalid. } qCDebug(kpLogWidgets) << "\tcolor.isValid=" << color.isValid () << " rgb=" << (color.isValid () ? (int *) color.toQRgb () : 0); if (color.isValid ()) { - if (!color.isTransparent ()) + if (!color.isTransparent ()) { KColorMimeData::createDrag (color.toQColor (), this)->exec (); + } } m_dragStartPoint = KP_INVALID_POINT; } } //--------------------------------------------------------------------- // protected virtual [base QWidget] void kpDualColorButton::mouseReleaseEvent (QMouseEvent *e) { m_dragStartPoint = KP_INVALID_POINT; if (swapPixmapRect ().contains (e->pos ()) && m_color [0] != m_color [1]) { qCDebug(kpLogWidgets) << "kpDualColorButton::mouseReleaseEvent() swap colors:"; m_oldColor [0] = m_color [0]; m_oldColor [1] = m_color [1]; kpColor temp = m_color [0]; m_color [0] = m_color [1]; m_color [1] = temp; update (); emit colorsSwapped (m_color [0], m_color [1]); emit foregroundColorChanged (m_color [0]); emit backgroundColorChanged (m_color [1]); } } //--------------------------------------------------------------------- // protected virtual [base QWidget] void kpDualColorButton::mouseDoubleClickEvent (QMouseEvent *e) { int whichColor = -1; - if (foregroundRect ().contains (e->pos ())) + if (foregroundRect ().contains (e->pos ())) { whichColor = 0; - else if (backgroundRect ().contains (e->pos ())) + } + else if (backgroundRect ().contains (e->pos ())) { whichColor = 1; + } if (whichColor == 0 || whichColor == 1) { QColorDialog dialog(this); dialog.setCurrentColor(color(whichColor).toQColor()); dialog.setOptions(QColorDialog::ShowAlphaChannel); - if ( dialog.exec() == QDialog::Accepted ) + if ( dialog.exec() == QDialog::Accepted ) { setColor(whichColor, kpColor(dialog.currentColor().rgba())); + } } } //--------------------------------------------------------------------- // protected virtual [base QWidget] void kpDualColorButton::paintEvent (QPaintEvent *e) { qCDebug(kpLogWidgets) << "kpDualColorButton::draw() rect=" << rect () << " contentsRect=" << contentsRect (); // Draw frame first. QFrame::paintEvent (e); QPainter painter (this); // Fill with background. if (isEnabled ()) { kpView::drawTransparentBackground (&painter, contentsRect ().topLeft ()/*checkerboard top-left*/, contentsRect (), true/*preview*/); } else { // Use default widget background. } painter.translate (contentsRect ().x (), contentsRect ().y ()); // Draw "Swap Colours" button (top-right). QPixmap swapPixmap = UserIcon ("colorbutton_swap_16x16"); if (!isEnabled ()) { // Don't let the fill() touch the mask. QBitmap swapBitmapMask = swapPixmap.mask (); swapPixmap.setMask (QBitmap ()); // Grey out the opaque parts of "swapPixmap". swapPixmap.fill (palette ().color (QPalette::Dark)); swapPixmap.setMask (swapBitmapMask); } painter.drawPixmap (swapPixmapRect ().topLeft (), swapPixmap); // Draw background colour patch. QRect bgRect = backgroundRect (); QRect bgRectInside = QRect (bgRect.x () + 2, bgRect.y () + 2, bgRect.width () - 4, bgRect.height () - 4); if (isEnabled ()) { qCDebug(kpLogWidgets) << "\tbackgroundColor=" << (int *) m_color [1].toQRgb (); - if (m_color [1].isTransparent ()) // only if fully transparent + if (m_color [1].isTransparent ()) { // only if fully transparent painter.drawPixmap (bgRectInside, UserIcon ("color_transparent_26x26")); - else + } + else { painter.fillRect (bgRectInside, m_color [1].toQColor ()); + } } - else + else { painter.fillRect (bgRectInside, palette().color (QPalette::Button)); + } qDrawShadePanel (&painter, bgRect, palette(), false/*not sunken*/, 2/*lineWidth*/, nullptr/*never fill*/); + // Draw foreground colour patch. // Must be drawn after background patch since we're on top. QRect fgRect = foregroundRect (); QRect fgRectInside = QRect (fgRect.x () + 2, fgRect.y () + 2, fgRect.width () - 4, fgRect.height () - 4); if (isEnabled ()) { qCDebug(kpLogWidgets) << "\tforegroundColor=" << (int *) m_color [0].toQRgb (); - if (m_color [0].isTransparent ()) // only if fully transparent + if (m_color [0].isTransparent ()) { // only if fully transparent painter.drawPixmap (fgRectInside, UserIcon ("color_transparent_26x26")); - else + } + else { painter.fillRect (fgRectInside, m_color [0].toQColor ()); + } } - else + else { painter.fillRect (fgRectInside, palette ().color (QPalette::Button)); + } qDrawShadePanel (&painter, fgRect, palette (), false/*not sunken*/, 2/*lineWidth*/, nullptr/*never fill*/); } diff --git a/widgets/kpPrintDialogPage.cpp b/widgets/kpPrintDialogPage.cpp index eef13278..e8e84782 100644 --- a/widgets/kpPrintDialogPage.cpp +++ b/widgets/kpPrintDialogPage.cpp @@ -1,94 +1,96 @@ /* Copyright (c) 2003-2007 Clarence Dang Copyright (c) 2007 John Layt All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #define DEBUG_KP_PRINT_DIALOG_PAGE 0 #include "kpPrintDialogPage.h" #include #include #include #include "kpLogCategories.h" #include #include "kpDefs.h" struct kpPrintDialogPagePrivate { QRadioButton *printCenteredRadio, *printTopLeftRadio; }; kpPrintDialogPage::kpPrintDialogPage (QWidget *parent) : QWidget (parent), d (new kpPrintDialogPagePrivate ()) { qCDebug(kpLogWidgets) << "kpPrintDialogPage::()"; setWindowTitle (i18nc ("@title:tab", "I&mage Position")); d->printCenteredRadio = new QRadioButton (i18n ("&Center of the page"), this); d->printTopLeftRadio = new QRadioButton (i18n ("Top-&left of the page"), this); - QVBoxLayout *lay = new QVBoxLayout (this); + auto *lay = new QVBoxLayout (this); lay->addWidget (d->printCenteredRadio); lay->addWidget (d->printTopLeftRadio); lay->addStretch (); setPrintImageCenteredOnPage (true); } kpPrintDialogPage::~kpPrintDialogPage () { delete d; } bool kpPrintDialogPage::printImageCenteredOnPage () { qCDebug(kpLogWidgets) << "kpPrintDialogPage::printImageCenteredOnPage()" - << " returning " << d->printCenteredRadio->isChecked() << endl; + << " returning " << d->printCenteredRadio->isChecked(); return d->printCenteredRadio->isChecked (); } void kpPrintDialogPage::setPrintImageCenteredOnPage (bool printCentered) { qCDebug(kpLogWidgets) << "kpPrintDialogPage::setOptions(" << printCentered << ")"; - if (printCentered) + if (printCentered) { d->printCenteredRadio->setChecked (true); - else + } + else { d->printTopLeftRadio->setChecked (true); + } } diff --git a/widgets/kpTransparentColorCell.cpp b/widgets/kpTransparentColorCell.cpp index 60d931a1..e4586e20 100644 --- a/widgets/kpTransparentColorCell.cpp +++ b/widgets/kpTransparentColorCell.cpp @@ -1,126 +1,126 @@ /* Copyright (c) 2003-2007 Clarence Dang All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #define DEBUG_KP_TRANSPARENT_COLOR_CELL 0 #include "kpTransparentColorCell.h" #include "imagelib/kpColor.h" #include #include #include #include #include #include "kpLogCategories.h" //--------------------------------------------------------------------- kpTransparentColorCell::kpTransparentColorCell (QWidget *parent) : QFrame (parent) { setSizePolicy (QSizePolicy::Fixed/*horizontal*/, QSizePolicy::Fixed/*vertical*/); setFrameStyle (QFrame::Panel | QFrame::Sunken); m_pixmap = UserIcon ("color_transparent_26x26"); this->setToolTip( i18n ("Transparent")); } //--------------------------------------------------------------------- // public virtual [base QWidget] QSize kpTransparentColorCell::sizeHint () const { - return QSize (m_pixmap.width () + frameWidth () * 2, - m_pixmap.height () + frameWidth () * 2); + return {m_pixmap.width () + frameWidth () * 2, + m_pixmap.height () + frameWidth () * 2}; } //--------------------------------------------------------------------- // protected virtual [base QWidget] void kpTransparentColorCell::mousePressEvent (QMouseEvent * /*e*/) { // Eat press so that we own the mouseReleaseEvent(). // [http://blogs.qtdeveloper.net/archives/2006/05/27/mouse-event-propagation/] // // However, contrary to that blog, it doesn't seem to be needed? } //--------------------------------------------------------------------- // protected virtual [base QWidget] void kpTransparentColorCell::contextMenuEvent (QContextMenuEvent *e) { // Eat right-mouse press to prevent it from getting to the toolbar. e->accept (); } //--------------------------------------------------------------------- // protected virtual [base QWidget] void kpTransparentColorCell::mouseReleaseEvent (QMouseEvent *e) { if (rect ().contains (e->pos ())) { if (e->button () == Qt::LeftButton) { emit transparentColorSelected (0); emit foregroundColorChanged (kpColor::Transparent); } else if (e->button () == Qt::RightButton) { emit transparentColorSelected (1); emit backgroundColorChanged (kpColor::Transparent); } } } //--------------------------------------------------------------------- // protected virtual [base QWidget] void kpTransparentColorCell::paintEvent (QPaintEvent *e) { // Draw frame first. QFrame::paintEvent (e); if (isEnabled ()) { qCDebug(kpLogWidgets) << "kpTransparentColorCell::paintEvent() contentsRect=" << contentsRect (); QPainter p (this); p.drawPixmap (contentsRect (), m_pixmap); } } //--------------------------------------------------------------------- diff --git a/widgets/toolbars/kpColorToolBar.cpp b/widgets/toolbars/kpColorToolBar.cpp index 796d641b..69acde75 100644 --- a/widgets/toolbars/kpColorToolBar.cpp +++ b/widgets/toolbars/kpColorToolBar.cpp @@ -1,324 +1,328 @@ /* Copyright (c) 2003-2007 Clarence Dang All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #define DEBUG_KP_COLOR_TOOL_BAR 0 #include "widgets/toolbars/kpColorToolBar.h" #include #include #include #include #include #include "kpLogCategories.h" #include "widgets/kpColorCells.h" #include "widgets/kpColorPalette.h" #include "widgets/colorSimilarity/kpColorSimilarityToolBarItem.h" #include "kpDefs.h" #include "widgets/kpDualColorButton.h" #include "lgpl/generic/kpUrlFormatter.h" //--------------------------------------------------------------------- kpColorToolBar::kpColorToolBar (const QString &label, QWidget *parent) : QDockWidget (parent) { setWindowTitle (label); // not closable, as it's not a KDE toolbar yet and can not be made shown easily again setFeatures(QDockWidget::DockWidgetMovable | QDockWidget::DockWidgetFloatable); setAcceptDrops (true); QWidget *base = new QWidget (this); m_boxLayout = new QBoxLayout (QBoxLayout::LeftToRight, base); m_boxLayout->setMargin (5); m_boxLayout->setSpacing (10 * 3); // This holds the current global foreground and background colors, for // tools. m_dualColorButton = new kpDualColorButton (base); connect (m_dualColorButton, &kpDualColorButton::colorsSwapped, this, &kpColorToolBar::colorsSwapped); connect (m_dualColorButton, &kpDualColorButton::foregroundColorChanged, this, &kpColorToolBar::foregroundColorChanged); connect (m_dualColorButton, &kpDualColorButton::backgroundColorChanged, this, &kpColorToolBar::backgroundColorChanged); m_boxLayout->addWidget (m_dualColorButton, 0/*stretch*/, Qt::AlignVCenter); m_colorPalette = new kpColorPalette (base); connect (m_colorPalette, &kpColorPalette::foregroundColorChanged, m_dualColorButton, &kpDualColorButton::setForegroundColor); connect (m_colorPalette, &kpColorPalette::backgroundColorChanged, m_dualColorButton, &kpDualColorButton::setBackgroundColor); connect (m_colorPalette->colorCells (), &kpColorCells::isModifiedChanged, this, &kpColorToolBar::updateNameOrUrlLabel); connect (m_colorPalette->colorCells (), &kpColorCells::urlChanged, this, &kpColorToolBar::updateNameOrUrlLabel); connect (m_colorPalette->colorCells (), &kpColorCells::nameChanged, this, &kpColorToolBar::updateNameOrUrlLabel); updateNameOrUrlLabel (); m_boxLayout->addWidget (m_colorPalette, 0/*stretch*/); m_colorSimilarityToolBarItem = new kpColorSimilarityToolBarItem (base); connect (m_colorSimilarityToolBarItem, &kpColorSimilarityToolBarItem::colorSimilarityChanged, this, &kpColorToolBar::colorSimilarityChanged); m_boxLayout->addWidget (m_colorSimilarityToolBarItem, 0/*stretch*/); // Pad out all the horizontal space on the right of the Color Tool Bar so that // that the real Color Tool Bar widgets aren't placed in the center of the // Color Tool Bar. m_boxLayout->addItem ( new QSpacerItem (1, 1, QSizePolicy::Expanding, QSizePolicy::Preferred)); adjustToOrientation (Qt::Horizontal); setWidget (base); } //--------------------------------------------------------------------- void kpColorToolBar::adjustToOrientation (Qt::Orientation o) { qCDebug(kpLogWidgets) << "kpColorToolBar::adjustToOrientation(" << (o == Qt::Vertical ? "vertical" : "horizontal") << ") called!"; Q_ASSERT (o == Qt::Horizontal); if (o == Qt::Horizontal) { m_boxLayout->setDirection (QBoxLayout::LeftToRight); } else { m_boxLayout->setDirection (QBoxLayout::TopToBottom); } m_colorPalette->setOrientation (o); } //--------------------------------------------------------------------- // public kpColorCells *kpColorToolBar::colorCells () const { return m_colorPalette->colorCells (); } //--------------------------------------------------------------------- kpColor kpColorToolBar::color (int which) const { Q_ASSERT (which == 0 || which == 1); return m_dualColorButton->color (which); } //--------------------------------------------------------------------- void kpColorToolBar::setColor (int which, const kpColor &color) { Q_ASSERT (which == 0 || which == 1); m_dualColorButton->setColor (which, color); } //--------------------------------------------------------------------- kpColor kpColorToolBar::foregroundColor () const { return m_dualColorButton->foregroundColor (); } //--------------------------------------------------------------------- void kpColorToolBar::setForegroundColor (const kpColor &color) { qCDebug(kpLogWidgets) << "kpColorToolBar::setForegroundColor(" - << (int *) color.toQRgb () << ")" << endl; + << (int *) color.toQRgb () << ")"; m_dualColorButton->setForegroundColor (color); } //--------------------------------------------------------------------- kpColor kpColorToolBar::backgroundColor () const { return m_dualColorButton->backgroundColor (); } //--------------------------------------------------------------------- void kpColorToolBar::setBackgroundColor (const kpColor &color) { qCDebug(kpLogWidgets) << "kpColorToolBar::setBackgroundColor(" - << (int *) color.toQRgb () << ")" << endl; + << (int *) color.toQRgb () << ")"; m_dualColorButton->setBackgroundColor (color); } //--------------------------------------------------------------------- kpColor kpColorToolBar::oldForegroundColor () const { return m_dualColorButton->oldForegroundColor (); } //--------------------------------------------------------------------- kpColor kpColorToolBar::oldBackgroundColor () const { return m_dualColorButton->oldBackgroundColor (); } //--------------------------------------------------------------------- double kpColorToolBar::oldColorSimilarity () const { return m_colorSimilarityToolBarItem->oldColorSimilarity (); } //--------------------------------------------------------------------- double kpColorToolBar::colorSimilarity () const { return m_colorSimilarityToolBarItem->colorSimilarity (); } //--------------------------------------------------------------------- void kpColorToolBar::setColorSimilarity (double similarity) { m_colorSimilarityToolBarItem->setColorSimilarity (similarity); } //--------------------------------------------------------------------- int kpColorToolBar::processedColorSimilarity () const { return m_colorSimilarityToolBarItem->processedColorSimilarity (); } //--------------------------------------------------------------------- void kpColorToolBar::openColorSimilarityDialog () { m_colorSimilarityToolBarItem->openDialog (); } //--------------------------------------------------------------------- void kpColorToolBar::flashColorSimilarityToolBarItem () { m_colorSimilarityToolBarItem->flash (); } //--------------------------------------------------------------------- // private slot void kpColorToolBar::updateNameOrUrlLabel () { QString name; kpColorCells *colorCells = m_colorPalette->colorCells (); - if (!colorCells->url ().isEmpty ()) + if (!colorCells->url ().isEmpty ()) { name = kpUrlFormatter::PrettyFilename (colorCells->url ()); + } else { - if (!colorCells->name ().isEmpty ()) + if (!colorCells->name ().isEmpty ()) { name = colorCells->name (); - else + } + else { name = i18n ("KolourPaint Defaults"); + } } - if (name.isEmpty ()) + if (name.isEmpty ()) { name = i18n ("Untitled"); + } KLocalizedString labelStr; if (!m_colorPalette->colorCells ()->isModified ()) { labelStr = ki18nc ("Colors: name_or_url_of_color_palette", "Colors: %1") .subs (name); } else { labelStr = ki18nc ("Colors: name_or_url_of_color_palette [modified]", "Colors: %1 [modified]") .subs (name); } // Kill 2 birds with 1 stone: // // 1. Hide the windowTitle() when it's docked. // 2. Add a label containing the name of the open color palette. // // TODO: This currently hides the windowTitle() even when it's not docked, // because we've abused it to show the name of open color palette // instead. setWindowTitle (labelStr.toString ()); } //--------------------------------------------------------------------- // protected virtual [base QWidget] void kpColorToolBar::dragEnterEvent (QDragEnterEvent *e) { // Grab the color drag for this widget, preventing it from being // handled by our parent, the main window. - e->setAccepted (KColorMimeData::canDecode (e->mimeData ()) == true); + e->setAccepted (KColorMimeData::canDecode (e->mimeData ())); qCDebug(kpLogWidgets) << "isAccepted=" << e->isAccepted (); } //--------------------------------------------------------------------- // protected virtual [base QWidget] void kpColorToolBar::dragMoveEvent (QDragMoveEvent *e) { // Stop the grabbed drag from being dropped. - e->setAccepted (KColorMimeData::canDecode (e->mimeData ()) == false); + e->setAccepted (!KColorMimeData::canDecode (e->mimeData ())); qCDebug(kpLogWidgets) << "isAccepted=" << e->isAccepted (); } diff --git a/widgets/toolbars/kpToolToolBar.cpp b/widgets/toolbars/kpToolToolBar.cpp index b0795ab8..b0c2a572 100644 --- a/widgets/toolbars/kpToolToolBar.cpp +++ b/widgets/toolbars/kpToolToolBar.cpp @@ -1,447 +1,458 @@ /* Copyright (c) 2003-2007 Clarence Dang Copyright (c) 2011 Martin Koller All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #define DEBUG_KP_TOOL_TOOL_BAR 0 #include "widgets/toolbars/kpToolToolBar.h" #include #include #include #include #include #include "kpLogCategories.h" #include "kpDefs.h" #include "tools/kpTool.h" #include "tools/kpToolAction.h" #include "widgets/toolbars/options/kpToolWidgetBrush.h" #include "widgets/toolbars/options/kpToolWidgetEraserSize.h" #include "widgets/toolbars/options/kpToolWidgetFillStyle.h" #include "widgets/toolbars/options/kpToolWidgetLineWidth.h" #include "widgets/toolbars/options/kpToolWidgetOpaqueOrTransparent.h" #include "widgets/toolbars/options/kpToolWidgetSpraycanSize.h" //--------------------------------------------------------------------- class kpToolButton : public QToolButton { public: kpToolButton (kpTool *tool, QWidget *parent) : QToolButton (parent), m_tool (tool) { } kpTool *tool() const { return m_tool; } protected: void mouseDoubleClickEvent(QMouseEvent *e) override { - if (e->button () == Qt::LeftButton && m_tool) + if (e->button () == Qt::LeftButton && m_tool) { m_tool->globalDraw (); + } } kpTool *m_tool; }; //--------------------------------------------------------------------- kpToolToolBar::kpToolToolBar(const QString &name, int colsOrRows, QMainWindow *parent) : KToolBar(name, parent, Qt::LeftToolBarArea), m_vertCols (colsOrRows), m_buttonGroup (nullptr), m_baseWidget (nullptr), m_baseLayout (nullptr), m_toolLayout (nullptr), m_previousTool (nullptr), m_currentTool (nullptr) { m_baseWidget = new QWidget(this); m_toolWidgets.append (m_toolWidgetBrush = new kpToolWidgetBrush (m_baseWidget, "Tool Widget Brush")); m_toolWidgets.append (m_toolWidgetEraserSize = new kpToolWidgetEraserSize (m_baseWidget, "Tool Widget Eraser Size")); m_toolWidgets.append (m_toolWidgetFillStyle = new kpToolWidgetFillStyle (m_baseWidget, "Tool Widget Fill Style")); m_toolWidgets.append (m_toolWidgetLineWidth = new kpToolWidgetLineWidth (m_baseWidget, "Tool Widget Line Width")); m_toolWidgets.append (m_toolWidgetOpaqueOrTransparent = new kpToolWidgetOpaqueOrTransparent (m_baseWidget, "Tool Widget Opaque/Transparent")); m_toolWidgets.append (m_toolWidgetSpraycanSize = new kpToolWidgetSpraycanSize (m_baseWidget, "Tool Widget Spraycan Size")); - foreach(kpToolWidgetBase *w, m_toolWidgets) + for (auto *w : m_toolWidgets) { connect (w, &kpToolWidgetBase::optionSelected, this, &kpToolToolBar::toolWidgetOptionSelected); } adjustToOrientation(orientation()); connect (this, &kpToolToolBar::orientationChanged, this, &kpToolToolBar::adjustToOrientation); m_buttonGroup = new QButtonGroup (this); connect (m_buttonGroup, static_cast(&QButtonGroup::buttonClicked), this, &kpToolToolBar::slotToolButtonClicked); hideAllToolWidgets (); addWidget(m_baseWidget); connect (this, &kpToolToolBar::iconSizeChanged, this, &kpToolToolBar::slotIconSizeChanged); connect (this, &kpToolToolBar::toolButtonStyleChanged, this, &kpToolToolBar::slotToolButtonStyleChanged); } //--------------------------------------------------------------------- kpToolToolBar::~kpToolToolBar() { - while ( !m_toolButtons.isEmpty() ) - delete m_toolButtons.takeFirst(); + while ( !m_toolButtons.isEmpty() ) { + delete m_toolButtons.takeFirst(); + } } //--------------------------------------------------------------------- // public void kpToolToolBar::registerTool (kpTool *tool) { - foreach (const kpToolButton *b, m_toolButtons) + for (const auto *b : m_toolButtons) { - if ( b->tool() == tool ) // already given - return; + if ( b->tool() == tool ) { // already given + return; + } } - kpToolButton *b = new kpToolButton(tool, m_baseWidget); + auto *b = new kpToolButton(tool, m_baseWidget); b->setToolButtonStyle(toolButtonStyle()); b->setIconSize(iconSize()); b->setAutoRaise(true); // tell layout to make all with equal width (much better when text-below-icon) b->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Preferred); b->setDefaultAction(tool->action()); m_buttonGroup->addButton(b); addButton(b, orientation(), m_toolButtons.count()); m_toolButtons.append(b); connect (tool, &kpTool::actionActivated, this, &kpToolToolBar::slotToolActionActivated); adjustSizeConstraint(); } //--------------------------------------------------------------------- // public void kpToolToolBar::unregisterTool(kpTool *tool) { for (int i = 0; i < m_toolButtons.count(); i++) { if ( m_toolButtons[i]->tool() == tool ) { delete m_toolButtons.takeAt(i); disconnect (tool, &kpTool::actionActivated, this, &kpToolToolBar::slotToolActionActivated); return; } } } //--------------------------------------------------------------------- // public kpTool *kpToolToolBar::tool () const { return m_currentTool; } //--------------------------------------------------------------------- // public void kpToolToolBar::selectTool (const kpTool *tool, bool reselectIfSameTool) { qCDebug(kpLogWidgets) << "kpToolToolBar::selectTool (tool=" << tool << ") currentTool=" << m_currentTool; - if (!reselectIfSameTool && tool == m_currentTool) + if (!reselectIfSameTool && tool == m_currentTool) { return; + } if (tool) { tool->action()->setChecked(true); slotToolButtonClicked(); } else { QAbstractButton *b = m_buttonGroup->checkedButton(); if (b) { // HACK: qbuttongroup.html says the following about exclusive // button groups: // // "to untoggle a button you must click on another button // in the group" // // But we don't want any button to be selected. // So don't be an exclusive button group temporarily. m_buttonGroup->setExclusive (false); b->setChecked (false); m_buttonGroup->setExclusive (true); slotToolButtonClicked (); } } } //--------------------------------------------------------------------- // public kpTool *kpToolToolBar::previousTool () const { return m_previousTool; } //--------------------------------------------------------------------- // public void kpToolToolBar::selectPreviousTool () { selectTool (m_previousTool); } //--------------------------------------------------------------------- // public void kpToolToolBar::hideAllToolWidgets () { - foreach(kpToolWidgetBase *w, m_toolWidgets) + for (auto *w : m_toolWidgets) { w->hide (); + } } //--------------------------------------------------------------------- // public kpToolWidgetBase *kpToolToolBar::shownToolWidget (int which) const { int uptoVisibleWidget = 0; - foreach(kpToolWidgetBase *w, m_toolWidgets) + for(auto *w : m_toolWidgets) { if ( !w->isHidden() ) { - if (which == uptoVisibleWidget) + if (which == uptoVisibleWidget) { return w; + } uptoVisibleWidget++; } } return nullptr; } //--------------------------------------------------------------------- // private slot void kpToolToolBar::slotToolButtonClicked () { QAbstractButton *b = m_buttonGroup->checkedButton(); qCDebug(kpLogWidgets) << "kpToolToolBar::slotToolButtonClicked() button=" << b; kpTool *tool = nullptr; - foreach (const kpToolButton *button, m_toolButtons) + for (const auto *button : m_toolButtons) { if ( button == b ) { tool = button->tool(); break; } } qCDebug(kpLogWidgets) << "\ttool=" << tool << " currentTool=" << m_currentTool; if (tool == m_currentTool) { - if (m_currentTool) + if (m_currentTool) { m_currentTool->reselect (); + } return; } - if (m_currentTool) + if (m_currentTool) { m_currentTool->endInternal (); + } m_previousTool = m_currentTool; m_currentTool = tool; if (m_currentTool) { kpToolAction *action = m_currentTool->action (); if (action) { action->setChecked (true); } m_currentTool->beginInternal (); } emit sigToolSelected (m_currentTool); m_baseLayout->activate(); adjustSizeConstraint(); } //--------------------------------------------------------------------- // private slot void kpToolToolBar::slotToolActionActivated () { - const kpTool *tool = dynamic_cast(sender()); + const auto *tool = dynamic_cast(sender()); qCDebug(kpLogWidgets) << "kpToolToolBar::slotToolActionActivated() tool=" << (tool ? tool->objectName () : "null"); selectTool (tool, true/*reselect if same tool*/); } //--------------------------------------------------------------------- // public void kpToolToolBar::adjustToOrientation(Qt::Orientation o) { qCDebug(kpLogWidgets) << "kpToolToolBar::adjustToOrientation(" << (o == Qt::Vertical ? "vertical" : "horizontal") << ") called!"; delete m_baseLayout; if (o == Qt::Vertical) { m_baseLayout = new QBoxLayout (QBoxLayout::TopToBottom, m_baseWidget); } else // if (o == Qt::Horizontal) { m_baseLayout = new QBoxLayout (QBoxLayout::LeftToRight, m_baseWidget); } m_baseLayout->setSizeConstraint(QLayout::SetFixedSize); m_baseLayout->setContentsMargins(0, 0, 0, 0); m_toolLayout = new QGridLayout(); m_toolLayout->setContentsMargins(0, 0, 0, 0); // (ownership is transferred to m_baseLayout) m_baseLayout->addItem (m_toolLayout); - int num = 0; + auto num = 0; - foreach (kpToolButton *b, m_toolButtons) + for (auto *b : m_toolButtons) { addButton(b, o, num); num++; } - foreach(kpToolWidgetBase *w, m_toolWidgets) + for (auto *w : m_toolWidgets) { m_baseLayout->addWidget(w, 0/*stretch*/, o == Qt::Vertical ? Qt::AlignHCenter : Qt::AlignVCenter); } adjustSizeConstraint(); } //--------------------------------------------------------------------- // this makes the size handled correctly during dragging/undocking the toolbar void kpToolToolBar::adjustSizeConstraint() { // remove constraints setFixedSize(QSize(QWIDGETSIZE_MAX, QWIDGETSIZE_MAX)); if ( orientation() == Qt::Vertical ) { setFixedWidth(m_baseLayout->sizeHint().width() + layout()->contentsMargins().left() + layout()->contentsMargins().right()); } else { setFixedHeight(m_baseLayout->sizeHint().height() + layout()->contentsMargins().top() + layout()->contentsMargins().bottom()); } } //--------------------------------------------------------------------- // private void kpToolToolBar::addButton(QAbstractButton *button, Qt::Orientation o, int num) { - if (o == Qt::Vertical) + if (o == Qt::Vertical) { m_toolLayout->addWidget (button, num / m_vertCols, num % m_vertCols); + } else { // maps Left (o = vertical) to Bottom (o = horizontal) int row = (m_vertCols - 1) - (num % m_vertCols); m_toolLayout->addWidget (button, row, num / m_vertCols); } } //--------------------------------------------------------------------- void kpToolToolBar::slotIconSizeChanged(const QSize &size) { - foreach (kpToolButton *b, m_toolButtons) - b->setIconSize(size); + for (auto *b : m_toolButtons) { + b->setIconSize(size); + } m_baseLayout->activate(); adjustSizeConstraint(); } //--------------------------------------------------------------------- void kpToolToolBar::slotToolButtonStyleChanged(Qt::ToolButtonStyle style) { - foreach (kpToolButton *b, m_toolButtons) - b->setToolButtonStyle(style); + for (auto *b : m_toolButtons) { + b->setToolButtonStyle(style); + } m_baseLayout->activate(); adjustSizeConstraint(); } //--------------------------------------------------------------------- diff --git a/widgets/toolbars/options/kpToolWidgetBase.cpp b/widgets/toolbars/options/kpToolWidgetBase.cpp index aedcee91..49c38a0e 100644 --- a/widgets/toolbars/options/kpToolWidgetBase.cpp +++ b/widgets/toolbars/options/kpToolWidgetBase.cpp @@ -1,722 +1,754 @@ /* Copyright (c) 2003-2007 Clarence Dang All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #define DEBUG_KP_TOOL_WIDGET_BASE 0 #include "kpToolWidgetBase.h" #include "kpDefs.h" #include #include #include #include "kpLogCategories.h" #include #include #include #include #include #include #include #include //--------------------------------------------------------------------- kpToolWidgetBase::kpToolWidgetBase (QWidget *parent, const QString &name) : QFrame(parent), m_baseWidget(nullptr), m_selectedRow(-1), m_selectedCol(-1) { setObjectName (name); setFrameStyle (QFrame::Panel | QFrame::Sunken); setFixedSize (44, 66); setSizePolicy (QSizePolicy::Minimum, QSizePolicy::Minimum); } //--------------------------------------------------------------------- -kpToolWidgetBase::~kpToolWidgetBase () -{ -} +kpToolWidgetBase::~kpToolWidgetBase () = default; //--------------------------------------------------------------------- // public void kpToolWidgetBase::addOption (const QPixmap &pixmap, const QString &toolTip) { - if (m_pixmaps.isEmpty ()) + if (m_pixmaps.isEmpty ()) { startNewOptionRow (); + } m_pixmaps.last ().append (pixmap); m_pixmapRects.last ().append (QRect ()); m_toolTips.last ().append (toolTip); } //--------------------------------------------------------------------- // public void kpToolWidgetBase::startNewOptionRow () { m_pixmaps.append (QList ()); m_pixmapRects.append (QList ()); m_toolTips.append (QList ()); } //--------------------------------------------------------------------- // public void kpToolWidgetBase::finishConstruction (int fallBackRow, int fallBackCol) { #if DEBUG_KP_TOOL_WIDGET_BASE qCDebug(kpLogWidgets) << "kpToolWidgetBase(" << objectName () << ")::kpToolWidgetBase(fallBack:row=" << fallBackRow << ",col=" << fallBackCol - << ")" - << endl; + << ")"; #endif relayoutOptions (); // HACK: Undo the maximum half of setFixedSize() in the ctor to avoid // bizarre redraw errors when tool widgets are hidden and others // are shown. // // The reason why we didn't just use setMinimumSize() in the ctor is // because all tool widgets construct pixmaps whose sizes are dependent // on the size() in the ctor, so we needed to get the correct size // in there. This is bad design because it means that tool widgets // can't really be resized. setMaximumSize (QWIDGETSIZE_MAX, QWIDGETSIZE_MAX); const QPair rowColPair = defaultSelectedRowAndCol (); if (!setSelected (rowColPair.first, rowColPair.second, false/*don't save*/)) { if (!setSelected (fallBackRow, fallBackCol)) { if (!setSelected (0, 0)) { qCCritical(kpLogWidgets) << "kpToolWidgetBase::finishConstruction() " - "can't even fall back to setSelected(row=0,col=0)" << endl; + "can't even fall back to setSelected(row=0,col=0)"; } } } } //--------------------------------------------------------------------- // private QList kpToolWidgetBase::spreadOutElements (const QList &sizes, int max) { - if (sizes.count () == 0) + if (sizes.count () == 0) { return QList (); - else if (sizes.count () == 1) + } + + if (sizes.count () == 1) { QList ret; ret.append (sizes.first () > max ? 0 : 1/*margin*/); return ret; } QList retOffsets; - for (int i = 0; i < sizes.count (); i++) + for (int i = 0; i < sizes.count (); i++) { retOffsets.append (0); + } int totalSize = 0; - for (int i = 0; i < sizes.count (); i++) + for (int i = 0; i < sizes.count (); i++) { totalSize += sizes [i]; + } int margin = 1; // if don't fit with margin, then just return elements // packed right next to each other if (totalSize + margin * 2 > max) { retOffsets [0] = 0; - for (int i = 1; i < sizes.count (); i++) + for (int i = 1; i < sizes.count (); i++) { retOffsets [i] = retOffsets [i - 1] + sizes [i - 1]; + } return retOffsets; } int maxLeftOver = max - (totalSize + margin * 2 * sizes.count()); int startCompensating = -1; int numCompensate = 0; int spacing = 0; spacing = maxLeftOver / (sizes.count () - 1); if (spacing * int (sizes.count () - 1) < maxLeftOver) { numCompensate = maxLeftOver - spacing * (sizes.count () - 1); startCompensating = ((sizes.count () - 1) - numCompensate) / 2; } retOffsets [0] = margin; for (int i = 1; i < sizes.count (); i++) { retOffsets [i] += retOffsets [i - 1] + sizes [i - 1] + spacing + ((numCompensate && i >= startCompensating && i < startCompensating + numCompensate) ? 1 : 0); } return retOffsets; } //--------------------------------------------------------------------- // public QPair kpToolWidgetBase::defaultSelectedRowAndCol () const { int row = -1, col = -1; if (!objectName ().isEmpty ()) { KConfigGroup cfg (KSharedConfig::openConfig (), kpSettingsGroupTools); row = cfg.readEntry (objectName () + QLatin1String (" Row"), -1); col = cfg.readEntry (objectName () + QLatin1String (" Col"), -1); } #if DEBUG_KP_TOOL_WIDGET_BASE qCDebug(kpLogWidgets) << "kpToolWidgetBase(" << objectName () << ")::defaultSelectedRowAndCol() returning row=" << row - << " col=" << col - << endl; + << " col=" << col; #endif return qMakePair (row, col); } //--------------------------------------------------------------------- // public int kpToolWidgetBase::defaultSelectedRow () const { return defaultSelectedRowAndCol ().first; } //--------------------------------------------------------------------- // public int kpToolWidgetBase::defaultSelectedCol () const { return defaultSelectedRowAndCol ().second; } //--------------------------------------------------------------------- // public void kpToolWidgetBase::saveSelectedAsDefault () const { #if DEBUG_KP_TOOL_WIDGET_BASE qCDebug(kpLogWidgets) << "kpToolWidgetBase(" << objectName () << ")::saveSelectedAsDefault() row=" << m_selectedRow - << " col=" << m_selectedCol << endl; + << " col=" << m_selectedCol; #endif - if (objectName ().isEmpty ()) + if (objectName ().isEmpty ()) { return; + } KConfigGroup cfg (KSharedConfig::openConfig (), kpSettingsGroupTools); cfg.writeEntry (objectName () + QLatin1String (" Row"), m_selectedRow); cfg.writeEntry (objectName () + QLatin1String (" Col"), m_selectedCol); cfg.sync (); } //--------------------------------------------------------------------- // public void kpToolWidgetBase::relayoutOptions () { #if DEBUG_KP_TOOL_WIDGET_BASE qCDebug(kpLogWidgets) << "kpToolWidgetBase::relayoutOptions() size=" << size (); #endif while (!m_pixmaps.isEmpty () && m_pixmaps.last ().count () == 0) { #if DEBUG_KP_TOOL_WIDGET_BASE qCDebug(kpLogWidgets) << "\tkilling #" << m_pixmaps.count () - 1; #endif m_pixmaps.removeLast (); m_pixmapRects.removeLast (); m_toolTips.removeLast (); } - if (m_pixmaps.isEmpty ()) + if (m_pixmaps.isEmpty ()) { return; + } #if DEBUG_KP_TOOL_WIDGET_BASE qCDebug(kpLogWidgets) << "\tsurvived killing of empty rows"; qCDebug(kpLogWidgets) << "\tfinding heights of rows:"; #endif QList maxHeightOfRow; - for (int r = 0; r < m_pixmaps.count (); r++) + for (int r = 0; r < m_pixmaps.count (); r++) { maxHeightOfRow.append (0); + } for (int r = 0; r < m_pixmaps.count (); r++) { for (int c = 0; c < m_pixmaps [r].count (); c++) { - if (c == 0 || m_pixmaps [r][c].height () > maxHeightOfRow [r]) + if (c == 0 || m_pixmaps [r][c].height () > maxHeightOfRow [r]) { maxHeightOfRow [r] = m_pixmaps [r][c].height (); + } } #if DEBUG_KP_TOOL_WIDGET_BASE qCDebug(kpLogWidgets) << "\t\t" << r << ": " << maxHeightOfRow [r]; #endif } QList rowYOffset = spreadOutElements (maxHeightOfRow, height ()); #if DEBUG_KP_TOOL_WIDGET_BASE qCDebug(kpLogWidgets) << "\tspread out offsets of rows:"; - for (int r = 0; r < (int) rowYOffset.count (); r++) + for (int r = 0; r < (int) rowYOffset.count (); r++) { qCDebug(kpLogWidgets) << "\t\t" << r << ": " << rowYOffset [r]; + } #endif for (int r = 0; r < m_pixmaps.count (); r++) { #if DEBUG_KP_TOOL_WIDGET_BASE qCDebug(kpLogWidgets) << "\tlaying out row " << r << ":"; #endif QList widths; for (int c = 0; c < m_pixmaps [r].count (); c++) widths.append (m_pixmaps [r][c].width ()); #if DEBUG_KP_TOOL_WIDGET_BASE qCDebug(kpLogWidgets) << "\t\twidths of cols:"; - for (int c = 0; c < m_pixmaps [r].count (); c++) + for (int c = 0; c < m_pixmaps [r].count (); c++) { qCDebug(kpLogWidgets) << "\t\t\t" << c << ": " << widths [c]; + } #endif QList colXOffset = spreadOutElements (widths, width ()); #if DEBUG_KP_TOOL_WIDGET_BASE qCDebug(kpLogWidgets) << "\t\tspread out offsets of cols:"; - for (int c = 0; c < colXOffset.count (); c++) + for (int c = 0; c < colXOffset.count (); c++) { qCDebug(kpLogWidgets) << "\t\t\t" << c << ": " << colXOffset [c]; + } #endif for (int c = 0; c < colXOffset.count (); c++) { int x = colXOffset [c]; int y = rowYOffset [r]; int w, h; if (c == colXOffset.count () - 1) { - if (x + m_pixmaps [r][c].width () >= width ()) + if (x + m_pixmaps [r][c].width () >= width ()) { w = m_pixmaps [r][c].width (); - else + } + else { w = width () - 1 - x; + } } - else + else { w = colXOffset [c + 1] - x; + } if (r == m_pixmaps.count () - 1) { - if (y + m_pixmaps [r][c].height () >= height ()) + if (y + m_pixmaps [r][c].height () >= height ()) { h = m_pixmaps [r][c].height (); - else + } + else { h = height () - 1 - y; + } } - else + else { h = rowYOffset [r + 1] - y; + } m_pixmapRects [r][c] = QRect (x, y, w, h); } } update (); } //--------------------------------------------------------------------- // public int kpToolWidgetBase::selectedRow () const { return m_selectedRow; } //--------------------------------------------------------------------- // public int kpToolWidgetBase::selectedCol () const { return m_selectedCol; } //--------------------------------------------------------------------- // public int kpToolWidgetBase::selected () const { if (m_selectedRow < 0 || m_selectedRow >= m_pixmaps.count () || m_selectedCol < 0) { return -1; } int upto = 0; - for (int y = 0; y < m_selectedRow; y++) + for (int y = 0; y < m_selectedRow; y++) { upto += m_pixmaps [y].count (); + } - if (m_selectedCol >= m_pixmaps [m_selectedRow].count ()) + if (m_selectedCol >= m_pixmaps [m_selectedRow].count ()) { return -1; + } upto += m_selectedCol; return upto; } //--------------------------------------------------------------------- // public bool kpToolWidgetBase::hasPreviousOption (int *row, int *col) const { #if DEBUG_KP_TOOL_WIDGET_BASE qCDebug(kpLogWidgets) << "kpToolWidgetBase(" << objectName () << ")::hasPreviousOption() current row=" << m_selectedRow - << " col=" << m_selectedCol - << endl; + << " col=" << m_selectedCol; #endif - if (row) + if (row) { *row = -1; - if (col) + } + if (col) { *col = -1; + } - if (m_selectedRow < 0 || m_selectedCol < 0) + if (m_selectedRow < 0 || m_selectedCol < 0) { return false; + } int newRow = m_selectedRow, newCol = m_selectedCol; newCol--; if (newCol < 0) { newRow--; - if (newRow < 0) + if (newRow < 0) { return false; + } newCol = m_pixmaps [newRow].count () - 1; - if (newCol < 0) + if (newCol < 0) { return false; + } } - if (row) + if (row) { *row = newRow; - if (col) + } + if (col) { *col = newCol; + } return true; } //--------------------------------------------------------------------- // public bool kpToolWidgetBase::hasNextOption (int *row, int *col) const { #if DEBUG_KP_TOOL_WIDGET_BASE qCDebug(kpLogWidgets) << "kpToolWidgetBase(" << objectName () << ")::hasNextOption() current row=" << m_selectedRow - << " col=" << m_selectedCol - << endl; + << " col=" << m_selectedCol; #endif - if (row) + if (row) { *row = -1; - if (col) + } + if (col) { *col = -1; + } - if (m_selectedRow < 0 || m_selectedCol < 0) + if (m_selectedRow < 0 || m_selectedCol < 0) { return false; + } int newRow = m_selectedRow, newCol = m_selectedCol; newCol++; if (newCol >= m_pixmaps [newRow].count ()) { newRow++; - if (newRow >= m_pixmaps.count ()) + if (newRow >= m_pixmaps.count ()) { return false; + } newCol = 0; - if (newCol >= m_pixmaps [newRow].count ()) + if (newCol >= m_pixmaps [newRow].count ()) { return false; + } } - if (row) + if (row) { *row = newRow; - if (col) + } + if (col) { *col = newCol; + } return true; } //--------------------------------------------------------------------- // public slot virtual bool kpToolWidgetBase::setSelected (int row, int col, bool saveAsDefault) { #if DEBUG_KP_TOOL_WIDGET_BASE qCDebug(kpLogWidgets) << "kpToolWidgetBase::setSelected(row=" << row << ",col=" << col << ",saveAsDefault=" << saveAsDefault - << ")" - << endl; + << ")"; #endif if (row < 0 || col < 0 || row >= m_pixmapRects.count () || col >= m_pixmapRects [row].count ()) { #if DEBUG_KP_TOOL_WIDGET_BASE qCDebug(kpLogWidgets) << "\tout of range"; #endif return false; } if (row == m_selectedRow && col == m_selectedCol) { #if DEBUG_KP_TOOL_WIDGET_BASE qCDebug(kpLogWidgets) << "\tNOP"; #endif - if (saveAsDefault) + if (saveAsDefault) { saveSelectedAsDefault (); + } return true; } const int wasSelectedRow = m_selectedRow; const int wasSelectedCol = m_selectedCol; m_selectedRow = row; m_selectedCol = col; if (wasSelectedRow >= 0 && wasSelectedCol >= 0) { // unhighlight old option update (m_pixmapRects [wasSelectedRow][wasSelectedCol]); } // highlight new option update (m_pixmapRects [row][col]); #if DEBUG_KP_TOOL_WIDGET_BASE qCDebug(kpLogWidgets) << "\tOK"; #endif - if (saveAsDefault) + if (saveAsDefault) { saveSelectedAsDefault (); + } emit optionSelected (row, col); return true; } //--------------------------------------------------------------------- // public slot bool kpToolWidgetBase::setSelected (int row, int col) { return setSelected (row, col, true/*set as default*/); } //--------------------------------------------------------------------- // public slot bool kpToolWidgetBase::selectPreviousOption () { int newRow, newCol; - if (!hasPreviousOption (&newRow, &newCol)) + if (!hasPreviousOption (&newRow, &newCol)) { return false; + } return setSelected (newRow, newCol); } //--------------------------------------------------------------------- // public slot bool kpToolWidgetBase::selectNextOption () { int newRow, newCol; - if (!hasNextOption (&newRow, &newCol)) + if (!hasNextOption (&newRow, &newCol)) { return false; + } return setSelected (newRow, newCol); } //--------------------------------------------------------------------- // protected virtual [base QWidget] bool kpToolWidgetBase::event (QEvent *e) { // TODO: It's unclear when we should call the base, call accept() and // return true or false. Look at other event() handlers. The // kpToolText one is wrong since after calling accept(), it calls // its base which calls ignore() :) if (e->type () == QEvent::ToolTip) { - QHelpEvent *he = dynamic_cast (e); + auto *he = dynamic_cast (e); #if DEBUG_KP_TOOL_WIDGET_BASE qCDebug(kpLogWidgets) << "kpToolWidgetBase::event() QHelpEvent pos=" << he->pos (); #endif bool showedText = false; for (int r = 0; r < m_pixmapRects.count (); r++) { for (int c = 0; c < m_pixmapRects [r].count (); c++) { if (m_pixmapRects [r][c].contains (he->pos ())) { const QString tip = m_toolTips [r][c]; #if DEBUG_KP_TOOL_WIDGET_BASE qCDebug(kpLogWidgets) << "\tin option: r=" << r << "c=" << c - << "tip='" << tip << "'" << endl; + << "tip='" << tip << "'"; #endif if (!tip.isEmpty ()) { QToolTip::showText (he->globalPos (), tip, this); showedText = true; } e->accept (); goto exit_loops; } } } exit_loops: if (!showedText) { #if DEBUG_KP_TOOL_WIDGET_BASE qCDebug(kpLogWidgets) << "\thiding text"; #endif QToolTip::hideText (); } return true; } - else - return QWidget::event (e); + + return QWidget::event (e); } //--------------------------------------------------------------------- // protected virtual [base QWidget] void kpToolWidgetBase::mousePressEvent (QMouseEvent *e) { e->ignore (); - if (e->button () != Qt::LeftButton) + if (e->button () != Qt::LeftButton) { return; + } for (int i = 0; i < m_pixmapRects.count (); i++) { for (int j = 0; j < m_pixmapRects [i].count (); j++) { if (m_pixmapRects [i][j].contains (e->pos ())) { setSelected (i, j); e->accept (); return; } } } } //--------------------------------------------------------------------- // protected virtual [base QWidget] void kpToolWidgetBase::paintEvent (QPaintEvent *e) { #if DEBUG_KP_TOOL_WIDGET_BASE && 1 qCDebug(kpLogWidgets) << "kpToolWidgetBase::paintEvent(): rect=" << contentsRect (); #endif // Draw frame first. QFrame::paintEvent (e); QPainter painter (this); for (int i = 0; i < m_pixmaps.count (); i++) { #if DEBUG_KP_TOOL_WIDGET_BASE && 1 qCDebug(kpLogWidgets) << "\tRow: " << i; #endif for (int j = 0; j < m_pixmaps [i].count (); j++) { QRect rect = m_pixmapRects [i][j]; QPixmap pixmap = m_pixmaps [i][j]; #if DEBUG_KP_TOOL_WIDGET_BASE && 1 qCDebug(kpLogWidgets) << "\t\tCol: " << j << " rect=" << rect; #endif if (i == m_selectedRow && j == m_selectedCol) { painter.fillRect(rect, palette().color(QPalette::Highlight).rgb()); } #if DEBUG_KP_TOOL_WIDGET_BASE && 1 qCDebug(kpLogWidgets) << "\t\t\tdraw pixmap @ x=" << rect.x () + (rect.width () - pixmap.width ()) / 2 << " y=" - << rect.y () + (rect.height () - pixmap.height ()) / 2 - << endl; + << rect.y () + (rect.height () - pixmap.height ()) / 2; #endif painter.drawPixmap(QPoint(rect.x () + (rect.width () - pixmap.width ()) / 2, rect.y () + (rect.height () - pixmap.height ()) / 2), pixmap); } } } //--------------------------------------------------------------------- diff --git a/widgets/toolbars/options/kpToolWidgetBrush.cpp b/widgets/toolbars/options/kpToolWidgetBrush.cpp index 7fc8f888..5dbabbb4 100644 --- a/widgets/toolbars/options/kpToolWidgetBrush.cpp +++ b/widgets/toolbars/options/kpToolWidgetBrush.cpp @@ -1,298 +1,297 @@ /* Copyright (c) 2003-2007 Clarence Dang All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #define DEBUG_KP_TOOL_WIDGET_BRUSH 0 #include "widgets/toolbars/options/kpToolWidgetBrush.h" #include #include #include #include "kpLogCategories.h" #include "kpDefs.h" //--------------------------------------------------------------------- // LOREFACTOR: more OO, no arrays (use safer structs). /* sync: */ static int BrushSizes [][3] = { {8, 4, 1/*like Pen*/}, {9, 5, 2}, {9, 5, 2}, {9, 5, 2} }; #define BRUSH_SIZE_NUM_COLS (int (sizeof (::BrushSizes [0]) / sizeof (::BrushSizes [0][0]))) #define BRUSH_SIZE_NUM_ROWS (int (sizeof (::BrushSizes) / sizeof (::BrushSizes [0]))) //--------------------------------------------------------------------- static void Draw (kpImage *destImage, const QPoint &topLeft, void *userData) { - kpToolWidgetBrush::DrawPackage *pack = - static_cast (userData); + auto *pack = static_cast (userData); #if DEBUG_KP_TOOL_WIDGET_BRUSH qCDebug(kpLogWidgets) << "kptoolwidgetbrush.cpp:Draw(destImage,topLeft=" << topLeft << " pack: row=" << pack->row << " col=" << pack->col - << " color=" << (int *) pack->color.toQRgb () - << endl; + << " color=" << (int *) pack->color.toQRgb (); #endif const int size = ::BrushSizes [pack->row][pack->col]; #if DEBUG_KP_TOOL_WIDGET_BRUSH qCDebug(kpLogWidgets) << "\tsize=" << size; #endif QPainter painter(destImage); if ( size == 1 ) { painter.setPen(pack->color.toQColor()); painter.drawPoint(topLeft); return; } // sync: switch (pack->row/*shape*/) { case 0: { // work around ugly circle when using QPainter on QImage if ( size == 4 ) { // do not draw a pixel twice, as with an alpha color it will become darker painter.setPen(Qt::NoPen); painter.setBrush(pack->color.toQColor()); painter.drawRect(topLeft.x() + 1, topLeft.y(), 2, size); painter.setPen(pack->color.toQColor()); painter.drawLine(topLeft.x(), topLeft.y() + 1, topLeft.x(), topLeft.y() + 2); painter.drawLine(topLeft.x() + 3, topLeft.y() + 1, topLeft.x() + 3, topLeft.y() + 2); } else if ( size == 8 ) // size defined in BrushSizes above { // do not draw a pixel twice, as with an alpha color it will become darker painter.setPen(Qt::NoPen); painter.setBrush(pack->color.toQColor()); painter.drawRect(topLeft.x() + 2, topLeft.y(), 4, size); painter.drawRect(topLeft.x(), topLeft.y() + 2, 2, 4); painter.drawRect(topLeft.x() + 6, topLeft.y() + 2, 2, 4); painter.setPen(pack->color.toQColor()); painter.drawPoint(topLeft.x() + 1, topLeft.y() + 1); painter.drawPoint(topLeft.x() + 6, topLeft.y() + 1); painter.drawPoint(topLeft.x() + 1, topLeft.y() + 6); painter.drawPoint(topLeft.x() + 6, topLeft.y() + 6); } else { Q_ASSERT(!"illegal size"); } break; } case 1: { // only paint filling so that a color with an alpha channel does not // create a darker border due to drawing some pixels twice with composition painter.setPen(Qt::NoPen); painter.setBrush(pack->color.toQColor()); painter.drawRect(topLeft.x(), topLeft.y(), size, size); break; } case 2: { painter.setPen(pack->color.toQColor()); painter.drawLine(topLeft.x() + size - 1, topLeft.y(), topLeft.x(), topLeft.y() + size - 1); break; } case 3: { painter.setPen(pack->color.toQColor()); painter.drawLine(topLeft.x(), topLeft.y(), topLeft.x() + size - 1, topLeft.y() + size - 1); break; } default: Q_ASSERT (!"Unknown row"); break; } } //--------------------------------------------------------------------- kpToolWidgetBrush::kpToolWidgetBrush (QWidget *parent, const QString &name) : kpToolWidgetBase (parent, name) { for (int shape = 0; shape < BRUSH_SIZE_NUM_ROWS; shape++) { for (int i = 0; i < BRUSH_SIZE_NUM_COLS; i++) { const int s = ::BrushSizes [shape][i]; const int w = (width () - 2/*margin*/ - 2/*spacing*/) / BRUSH_SIZE_NUM_COLS; const int h = (height () - 2/*margin*/ - 3/*spacing*/) / BRUSH_SIZE_NUM_ROWS; Q_ASSERT (w >= s && h >= s); QImage previewPixmap (w, h, QImage::Format_ARGB32_Premultiplied); previewPixmap.fill(0); DrawPackage pack = drawFunctionDataForRowCol (kpColor::Black, shape, i); ::Draw (&previewPixmap, QPoint ((previewPixmap.width () - s) / 2, (previewPixmap.height () - s) / 2), &pack); addOption (QPixmap::fromImage(previewPixmap), brushName (shape, i)/*tooltip*/); } startNewOptionRow (); } finishConstruction (0, 0); } //--------------------------------------------------------------------- -kpToolWidgetBrush::~kpToolWidgetBrush () -{ -} +kpToolWidgetBrush::~kpToolWidgetBrush () = default; //--------------------------------------------------------------------- // private QString kpToolWidgetBrush::brushName (int shape, int whichSize) const { int s = ::BrushSizes [shape][whichSize]; - if (s == 1) + if (s == 1) { return i18n ("1x1"); + } QString shapeName; // sync: switch (shape) { case 0: shapeName = i18n ("Circle"); break; case 1: shapeName = i18n ("Square"); break; case 2: // TODO: is this really the name of a shape? :) shapeName = i18n ("Slash"); break; case 3: // TODO: is this really the name of a shape? :) shapeName = i18n ("Backslash"); break; } - if (shapeName.isEmpty ()) - return QString(); + if (shapeName.isEmpty ()) { + return {}; + } return i18n ("%1x%2 %3", s, s, shapeName); } //--------------------------------------------------------------------- // public int kpToolWidgetBrush::brushSize () const { return ::BrushSizes [selectedRow ()][selectedCol ()]; } //--------------------------------------------------------------------- // public bool kpToolWidgetBrush::brushIsDiagonalLine () const { // sync: return (selectedRow () >= 2); } //--------------------------------------------------------------------- // public kpTempImage::UserFunctionType kpToolWidgetBrush::drawFunction () const { return &::Draw; } //--------------------------------------------------------------------- // public static kpToolWidgetBrush::DrawPackage kpToolWidgetBrush::drawFunctionDataForRowCol ( const kpColor &color, int row, int col) { Q_ASSERT (row >= 0 && col >= 0); DrawPackage pack; pack.row = row; pack.col = col; pack.color = color; return pack; } //--------------------------------------------------------------------- // public kpToolWidgetBrush::DrawPackage kpToolWidgetBrush::drawFunctionData ( const kpColor &color) const { return drawFunctionDataForRowCol (color, selectedRow (), selectedCol ()); } //--------------------------------------------------------------------- // protected slot virtual [base kpToolWidgetBase] bool kpToolWidgetBrush::setSelected (int row, int col, bool saveAsDefault) { const bool ret = kpToolWidgetBase::setSelected (row, col, saveAsDefault); - if (ret) + if (ret) { emit brushChanged (); + } return ret; } //--------------------------------------------------------------------- diff --git a/widgets/toolbars/options/kpToolWidgetEraserSize.cpp b/widgets/toolbars/options/kpToolWidgetEraserSize.cpp index 430028ba..0304dbac 100644 --- a/widgets/toolbars/options/kpToolWidgetEraserSize.cpp +++ b/widgets/toolbars/options/kpToolWidgetEraserSize.cpp @@ -1,186 +1,185 @@ /* Copyright (c) 2003-2007 Clarence Dang All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #define DEBUG_KP_TOOL_WIDGET_ERASER_SIZE 0 #include "kpToolWidgetEraserSize.h" #include "imagelib/kpColor.h" #include "imagelib/kpPainter.h" #include "pixmapfx/kpPixmapFX.h" #include "tools/kpTool.h" #include "kpLogCategories.h" #include #include #include #include static int EraserSizes [] = {2, 3, 5, 9, 17, 29}; static const int NumEraserSizes = int (sizeof (::EraserSizes) / sizeof (::EraserSizes [0])); static void DrawImage (kpImage *destImage, const QPoint &topLeft, void *userData) { - kpToolWidgetEraserSize::DrawPackage *pack = - static_cast (userData); + auto *pack = static_cast (userData); const int size = ::EraserSizes [pack->selected]; kpPainter::fillRect (destImage, topLeft.x (), topLeft.y (), size, size, pack->color); } static void DrawCursor (kpImage *destImage, const QPoint &topLeft, void *userData) { ::DrawImage (destImage, topLeft, userData); - kpToolWidgetEraserSize::DrawPackage *pack = - static_cast (userData); + auto *pack = static_cast (userData); const int size = ::EraserSizes [pack->selected]; // Would 1-pixel border on all sides completely cover the color of the // eraser? - if (size <= 2) + if (size <= 2) { return; + } // Draw 1-pixel border on all sides. QPainter painter(destImage); painter.drawRect(topLeft.x(), topLeft.y(), size - 1, size - 1); } //--------------------------------------------------------------------- kpToolWidgetEraserSize::kpToolWidgetEraserSize (QWidget *parent, const QString &name) : kpToolWidgetBase (parent, name) { for (int i = 0; i < ::NumEraserSizes; i++) { - if (i == 3 || i == 5) + if (i == 3 || i == 5) { startNewOptionRow (); + } const int s = ::EraserSizes [i]; QImage previewPixmap (s, s, QImage::Format_ARGB32_Premultiplied); if (i < 3) { // HACK: kpToolWidgetBase's layout code sucks and gives uneven spacing previewPixmap = QImage ((width () - 4) / 3, 9, QImage::Format_ARGB32_Premultiplied); Q_ASSERT (previewPixmap.width () >= s && previewPixmap.height () >= s); } previewPixmap.fill(0); DrawPackage pack = drawFunctionDataForSelected (kpColor::Black, i); ::DrawImage (&previewPixmap, QPoint ((previewPixmap.width () - s) / 2, (previewPixmap.height () - s) / 2), &pack); addOption (QPixmap::fromImage(previewPixmap), i18n ("%1x%2", s, s)/*tooltip*/); } finishConstruction (1, 0); } //--------------------------------------------------------------------- -kpToolWidgetEraserSize::~kpToolWidgetEraserSize () -{ -} +kpToolWidgetEraserSize::~kpToolWidgetEraserSize () = default; //--------------------------------------------------------------------- // public int kpToolWidgetEraserSize::eraserSize () const { return ::EraserSizes[selected() < 0 ? 0 : selected()]; } // public kpTempImage::UserFunctionType kpToolWidgetEraserSize::drawFunction () const { return &::DrawImage; } // public kpTempImage::UserFunctionType kpToolWidgetEraserSize::drawCursorFunction () const { return &::DrawCursor; } //--------------------------------------------------------------------- // public static kpToolWidgetEraserSize::DrawPackage kpToolWidgetEraserSize::drawFunctionDataForSelected ( const kpColor &color, int selectedIndex) { DrawPackage pack; pack.selected = selectedIndex; pack.color = color; return pack; } //--------------------------------------------------------------------- // public kpToolWidgetEraserSize::DrawPackage kpToolWidgetEraserSize::drawFunctionData ( const kpColor &color) const { return drawFunctionDataForSelected (color, selected ()); } //--------------------------------------------------------------------- // protected slot virtual [base kpToolWidgetBase] bool kpToolWidgetEraserSize::setSelected (int row, int col, bool saveAsDefault) { const bool ret = kpToolWidgetBase::setSelected (row, col, saveAsDefault); - if (ret) + if (ret) { emit eraserSizeChanged (eraserSize ()); + } return ret; } //--------------------------------------------------------------------- diff --git a/widgets/toolbars/options/kpToolWidgetFillStyle.cpp b/widgets/toolbars/options/kpToolWidgetFillStyle.cpp index 3dff5c2c..c7003e46 100644 --- a/widgets/toolbars/options/kpToolWidgetFillStyle.cpp +++ b/widgets/toolbars/options/kpToolWidgetFillStyle.cpp @@ -1,177 +1,175 @@ /* Copyright (c) 2003-2007 Clarence Dang All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #define DEBUG_KP_TOOL_WIDGET_FILL_STYLE 0 #include "kpToolWidgetFillStyle.h" #include "imagelib/kpColor.h" #include "kpDefs.h" #include "pixmapfx/kpPixmapFX.h" #include "tools/kpTool.h" #include "kpLogCategories.h" #include #include #include //--------------------------------------------------------------------- kpToolWidgetFillStyle::kpToolWidgetFillStyle (QWidget *parent, const QString &name) : kpToolWidgetBase (parent, name) { for (int i = 0; i < FillStyleNum; i++) { QPixmap pixmap; pixmap = fillStylePixmap (static_cast (i), (width () - 2/*margin*/) * 3 / 4, (height () - 2/*margin*/ - 2/*spacing*/) * 3 / (3 * 4)); addOption (pixmap, fillStyleName (static_cast (i))/*tooltip*/); startNewOptionRow (); } finishConstruction (0, 0); } //--------------------------------------------------------------------- -kpToolWidgetFillStyle::~kpToolWidgetFillStyle () -{ -} +kpToolWidgetFillStyle::~kpToolWidgetFillStyle () = default; //--------------------------------------------------------------------- // private QPixmap kpToolWidgetFillStyle::fillStylePixmap (FillStyle fs, int w, int h) { QPixmap pixmap ((w <= 0 ? width () : w), (h <= 0 ? height () : h)); pixmap.fill(palette().color(QPalette::Window)); const int penWidth = 2; const QRect rectRect(1, 1, w - 2, h - 2); QPainter painter(&pixmap); painter.setPen(kpPixmapFX::QPainterDrawRectPen(Qt::black, penWidth)); switch ( fs ) { case NoFill: { painter.setBrush(Qt::NoBrush); break; } case FillWithBackground: { painter.setBrush(Qt::gray); break; } case FillWithForeground: { painter.setBrush(Qt::black); break; } default: ; } painter.drawRect(rectRect); painter.end(); return pixmap; } //--------------------------------------------------------------------- // private QString kpToolWidgetFillStyle::fillStyleName (FillStyle fs) const { switch (fs) { case NoFill: return i18n ("No Fill"); case FillWithBackground: return i18n ("Fill with Background Color"); case FillWithForeground: return i18n ("Fill with Foreground Color"); default: return QString(); } } //--------------------------------------------------------------------- // public kpToolWidgetFillStyle::FillStyle kpToolWidgetFillStyle::fillStyle () const { #if DEBUG_KP_TOOL_WIDGET_FILL_STYLE qCDebug(kpLogWidgets) << "kpToolWidgetFillStyle::fillStyle() selected=" - << selectedRow () - << endl; + << selectedRow (); #endif return static_cast (selectedRow ()); } //--------------------------------------------------------------------- kpColor kpToolWidgetFillStyle::drawingBackgroundColor ( const kpColor &foregroundColor, const kpColor &backgroundColor) const { switch (fillStyle ()) { default: case NoFill: return kpColor::Invalid; case FillWithBackground: return backgroundColor; case FillWithForeground: return foregroundColor; } } //--------------------------------------------------------------------- // virtual protected slot [base kpToolWidgetBase] bool kpToolWidgetFillStyle::setSelected (int row, int col, bool saveAsDefault) { const bool ret = kpToolWidgetBase::setSelected (row, col, saveAsDefault); - if (ret) + if (ret) { emit fillStyleChanged (fillStyle ()); + } return ret; } //--------------------------------------------------------------------- diff --git a/widgets/toolbars/options/kpToolWidgetLineWidth.cpp b/widgets/toolbars/options/kpToolWidgetLineWidth.cpp index 74765b32..7cd3c4c0 100644 --- a/widgets/toolbars/options/kpToolWidgetLineWidth.cpp +++ b/widgets/toolbars/options/kpToolWidgetLineWidth.cpp @@ -1,89 +1,88 @@ /* Copyright (c) 2003-2007 Clarence Dang All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include "widgets/toolbars/options/kpToolWidgetLineWidth.h" #include "imagelib/kpColor.h" #include "pixmapfx/kpPixmapFX.h" #include #include #include #include static int lineWidths [] = {1, 2, 3, 5, 8}; kpToolWidgetLineWidth::kpToolWidgetLineWidth (QWidget *parent, const QString &name) : kpToolWidgetBase (parent, name) { int numLineWidths = sizeof (lineWidths) / sizeof (lineWidths [0]); int w = (width () - 2/*margin*/) * 3 / 4; int h = (height () - 2/*margin*/ - (numLineWidths - 1)/*spacing*/) * 3 / (numLineWidths * 4); for (int i = 0; i < numLineWidths; i++) { QImage image ((w <= 0 ? width () : w), (h <= 0 ? height () : h), QImage::Format_ARGB32_Premultiplied); image.fill(QColor(Qt::transparent).rgba()); kpPixmapFX::fillRect (&image, 0, (image.height () - lineWidths [i]) / 2, image.width (), lineWidths [i], kpColor::Black); addOption (QPixmap::fromImage(image), QString::number (lineWidths [i])); startNewOptionRow (); } finishConstruction (0, 0); } -kpToolWidgetLineWidth::~kpToolWidgetLineWidth () -{ -} +kpToolWidgetLineWidth::~kpToolWidgetLineWidth () = default; int kpToolWidgetLineWidth::lineWidth () const { return lineWidths [selectedRow ()]; } // virtual protected slot [base kpToolWidgetBase] bool kpToolWidgetLineWidth::setSelected (int row, int col, bool saveAsDefault) { const bool ret = kpToolWidgetBase::setSelected (row, col, saveAsDefault); - if (ret) + if (ret) { emit lineWidthChanged (lineWidth ()); + } return ret; } diff --git a/widgets/toolbars/options/kpToolWidgetOpaqueOrTransparent.cpp b/widgets/toolbars/options/kpToolWidgetOpaqueOrTransparent.cpp index 0a0d8658..ef107afb 100644 --- a/widgets/toolbars/options/kpToolWidgetOpaqueOrTransparent.cpp +++ b/widgets/toolbars/options/kpToolWidgetOpaqueOrTransparent.cpp @@ -1,103 +1,102 @@ /* Copyright (c) 2003-2007 Clarence Dang All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #define DEBUG_KP_TOOL_WIDGET_OPAQUE_OR_TRANSPARENT 0 #include "widgets/toolbars/options/kpToolWidgetOpaqueOrTransparent.h" #include "kpLogCategories.h" #include #include //--------------------------------------------------------------------- kpToolWidgetOpaqueOrTransparent::kpToolWidgetOpaqueOrTransparent (QWidget *parent, const QString &name) : kpToolWidgetBase (parent, name) { addOption (UserIcon ("option_opaque"), i18n ("Opaque")/*tooltip*/); startNewOptionRow (); addOption (UserIcon ("option_transparent"), i18n ("Transparent")/*tooltip*/); finishConstruction (0, 0); } //--------------------------------------------------------------------- -kpToolWidgetOpaqueOrTransparent::~kpToolWidgetOpaqueOrTransparent () -{ -} +kpToolWidgetOpaqueOrTransparent::~kpToolWidgetOpaqueOrTransparent () = default; //--------------------------------------------------------------------- // public bool kpToolWidgetOpaqueOrTransparent::isOpaque () const { return (selected () == 0); } // public bool kpToolWidgetOpaqueOrTransparent::isTransparent () const { return (!isOpaque ()); } // public void kpToolWidgetOpaqueOrTransparent::setOpaque (bool yes) { #if DEBUG_KP_TOOL_WIDGET_OPAQUE_OR_TRANSPARENT && 1 qCDebug(kpLogWidgets) << "kpToolWidgetOpaqueOrTransparent::setOpaque(" << yes << ")"; #endif setSelected (yes ? 0 : 1, 0, false/*don't save*/); } // public void kpToolWidgetOpaqueOrTransparent::setTransparent (bool yes) { #if DEBUG_KP_TOOL_WIDGET_OPAQUE_OR_TRANSPARENT && 1 qCDebug(kpLogWidgets) << "kpToolWidgetOpaqueOrTransparent::setTransparent(" << yes << ")"; #endif setSelected (yes ? 1 : 0, 0, false/*don't save*/); } // protected slot virtual [base kpToolWidgetBase] bool kpToolWidgetOpaqueOrTransparent::setSelected (int row, int col, bool saveAsDefault) { #if DEBUG_KP_TOOL_WIDGET_OPAQUE_OR_TRANSPARENT && 1 qCDebug(kpLogWidgets) << "kpToolWidgetOpaqueOrTransparent::setSelected(" - << row << "," << col << ")" << endl; + << row << "," << col << ")"; #endif const bool ret = kpToolWidgetBase::setSelected (row, col, saveAsDefault); - if (ret) + if (ret) { emit isOpaqueChanged (isOpaque ()); + } return ret; } diff --git a/widgets/toolbars/options/kpToolWidgetSpraycanSize.cpp b/widgets/toolbars/options/kpToolWidgetSpraycanSize.cpp index 7a74d6f6..e0f648bd 100644 --- a/widgets/toolbars/options/kpToolWidgetSpraycanSize.cpp +++ b/widgets/toolbars/options/kpToolWidgetSpraycanSize.cpp @@ -1,119 +1,120 @@ /* Copyright (c) 2003-2007 Clarence Dang All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #define DEBUG_KP_TOOL_WIDGET_SPRAYCAN_SIZE 0 #include "kpToolWidgetSpraycanSize.h" #include "pixmapfx/kpPixmapFX.h" #include "kpLogCategories.h" #include #include #include #include #include #include static int spraycanSizes [] = {9, 17, 29}; kpToolWidgetSpraycanSize::kpToolWidgetSpraycanSize (QWidget *parent, const QString &name) : kpToolWidgetBase (parent, name) { #if DEBUG_KP_TOOL_WIDGET_SPRAYCAN_SIZE qCDebug(kpLogWidgets) << "kpToolWidgetSpraycanSize::kpToolWidgetSpraycanSize() CALLED!"; #endif for (int i = 0; i < int (sizeof (spraycanSizes) / sizeof (spraycanSizes [0])); i++) { int s = spraycanSizes [i]; QString iconName = QString ("tool_spraycan_%1x%2").arg (s).arg(s); #if DEBUG_KP_TOOL_WIDGET_SPRAYCAN_SIZE qCDebug(kpLogWidgets) << "\ticonName=" << iconName; #endif QPixmap pixmap (s, s); pixmap.fill (Qt::white); QPainter painter (&pixmap); painter.drawPixmap (0, 0, UserIcon (iconName)); painter.end (); QImage image = pixmap.toImage(); QBitmap mask (pixmap.width (), pixmap.height ()); mask.fill (Qt::color0); painter.begin (&mask); painter.setPen (Qt::color1); for (int y = 0; y < image.height (); y++) { for (int x = 0; x < image.width (); x++) { - if ((image.pixel (x, y) & RGB_MASK) == 0/*black*/) + if ((image.pixel (x, y) & RGB_MASK) == 0/*black*/) { painter.drawPoint (x, y); // mark as opaque + } } } painter.end (); pixmap.setMask (mask); addOption (pixmap, i18n ("%1x%2", s, s)/*tooltip*/); - if (i == 1) + if (i == 1) { startNewOptionRow (); + } } finishConstruction (0, 0); } -kpToolWidgetSpraycanSize::~kpToolWidgetSpraycanSize () -{ -} +kpToolWidgetSpraycanSize::~kpToolWidgetSpraycanSize () = default; // public int kpToolWidgetSpraycanSize::spraycanSize () const { return spraycanSizes[selected() < 0 ? 0 : selected()]; } // protected slot virtual [base kpToolWidgetBase] bool kpToolWidgetSpraycanSize::setSelected (int row, int col, bool saveAsDefault) { const bool ret = kpToolWidgetBase::setSelected (row, col, saveAsDefault); - if (ret) + if (ret) { emit spraycanSizeChanged (spraycanSize ()); + } return ret; }