File indexing completed on 2024-05-12 04:21:26
0001 0002 /* 0003 Copyright (c) 2003-2007 Clarence Dang <dang@kde.org> 0004 All rights reserved. 0005 0006 Redistribution and use in source and binary forms, with or without 0007 modification, are permitted provided that the following conditions 0008 are met: 0009 0010 1. Redistributions of source code must retain the above copyright 0011 notice, this list of conditions and the following disclaimer. 0012 2. Redistributions in binary form must reproduce the above copyright 0013 notice, this list of conditions and the following disclaimer in the 0014 documentation and/or other materials provided with the distribution. 0015 0016 THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 0017 IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 0018 OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 0019 IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 0020 INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 0021 NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 0022 DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 0023 THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 0024 (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 0025 THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 0026 */ 0027 0028 0029 #define DEBUG_KP_TOOL_RECTANGULAR_BASE 0 0030 0031 0032 #include "tools/rectangular/kpToolRectangularBase.h" 0033 0034 #include <QCursor> 0035 0036 #include "kpLogCategories.h" 0037 #include <KLocalizedString> 0038 0039 #include "imagelib/kpColor.h" 0040 #include "commands/kpCommandHistory.h" 0041 #include "kpDefs.h" 0042 #include "document/kpDocument.h" 0043 #include "imagelib/kpPainter.h" 0044 #include "pixmapfx/kpPixmapFX.h" 0045 #include "layers/tempImage/kpTempImage.h" 0046 #include "environments/tools/kpToolEnvironment.h" 0047 #include "commands/tools/rectangular/kpToolRectangularCommand.h" 0048 #include "widgets/toolbars/kpToolToolBar.h" 0049 #include "widgets/toolbars/options/kpToolWidgetFillStyle.h" 0050 #include "widgets/toolbars/options/kpToolWidgetLineWidth.h" 0051 #include "views/kpView.h" 0052 #include "views/manager/kpViewManager.h" 0053 0054 0055 //--------------------------------------------------------------------- 0056 0057 struct kpToolRectangularBasePrivate 0058 { 0059 kpToolRectangularBase::DrawShapeFunc drawShapeFunc{}; 0060 0061 kpToolWidgetLineWidth *toolWidgetLineWidth{}; 0062 kpToolWidgetFillStyle *toolWidgetFillStyle{}; 0063 0064 QRect toolRectangleRect; 0065 }; 0066 0067 //--------------------------------------------------------------------- 0068 0069 kpToolRectangularBase::kpToolRectangularBase ( 0070 const QString &text, 0071 const QString &description, 0072 DrawShapeFunc drawShapeFunc, 0073 int key, 0074 kpToolEnvironment *environ, QObject *parent, 0075 const QString &name) 0076 0077 : kpTool (text, description, key, environ, parent, name), 0078 d (new kpToolRectangularBasePrivate ()) 0079 { 0080 d->drawShapeFunc = drawShapeFunc; 0081 0082 d->toolWidgetLineWidth = nullptr; 0083 d->toolWidgetFillStyle = nullptr; 0084 } 0085 0086 //--------------------------------------------------------------------- 0087 0088 kpToolRectangularBase::~kpToolRectangularBase () 0089 { 0090 delete d; 0091 } 0092 0093 //--------------------------------------------------------------------- 0094 0095 0096 // private slot virtual 0097 void kpToolRectangularBase::slotLineWidthChanged () 0098 { 0099 if (hasBegunDraw ()) { 0100 updateShape (); 0101 } 0102 } 0103 0104 //--------------------------------------------------------------------- 0105 0106 // private slot virtual 0107 void kpToolRectangularBase::slotFillStyleChanged () 0108 { 0109 if (hasBegunDraw ()) { 0110 updateShape (); 0111 } 0112 } 0113 0114 //--------------------------------------------------------------------- 0115 0116 // private 0117 QString kpToolRectangularBase::haventBegunDrawUserMessage () const 0118 { 0119 return i18n ("Drag to draw."); 0120 } 0121 0122 //--------------------------------------------------------------------- 0123 0124 // virtual 0125 void kpToolRectangularBase::begin () 0126 { 0127 #if DEBUG_KP_TOOL_RECTANGULAR_BASE 0128 qCDebug(kpLogTools) << "kpToolRectangularBase::begin ()"; 0129 #endif 0130 0131 kpToolToolBar *tb = toolToolBar (); 0132 Q_ASSERT (tb); 0133 0134 #if DEBUG_KP_TOOL_RECTANGULAR_BASE 0135 qCDebug(kpLogTools) << "\ttoolToolBar=" << tb; 0136 #endif 0137 0138 d->toolWidgetLineWidth = tb->toolWidgetLineWidth (); 0139 connect (d->toolWidgetLineWidth, &kpToolWidgetLineWidth::lineWidthChanged, 0140 this, &kpToolRectangularBase::slotLineWidthChanged); 0141 d->toolWidgetLineWidth->show (); 0142 0143 d->toolWidgetFillStyle = tb->toolWidgetFillStyle (); 0144 connect (d->toolWidgetFillStyle, &kpToolWidgetFillStyle::fillStyleChanged, 0145 this, &kpToolRectangularBase::slotFillStyleChanged); 0146 d->toolWidgetFillStyle->show (); 0147 0148 viewManager ()->setCursor (QCursor (Qt::ArrowCursor)); 0149 0150 setUserMessage (haventBegunDrawUserMessage ()); 0151 } 0152 0153 //--------------------------------------------------------------------- 0154 0155 // virtual 0156 void kpToolRectangularBase::end () 0157 { 0158 #if DEBUG_KP_TOOL_RECTANGULAR_BASE 0159 qCDebug(kpLogTools) << "kpToolRectangularBase::end ()"; 0160 #endif 0161 0162 if (d->toolWidgetLineWidth) 0163 { 0164 disconnect (d->toolWidgetLineWidth, &kpToolWidgetLineWidth::lineWidthChanged, 0165 this, &kpToolRectangularBase::slotLineWidthChanged); 0166 d->toolWidgetLineWidth = nullptr; 0167 } 0168 0169 if (d->toolWidgetFillStyle) 0170 { 0171 disconnect (d->toolWidgetFillStyle, &kpToolWidgetFillStyle::fillStyleChanged, 0172 this, &kpToolRectangularBase::slotFillStyleChanged); 0173 d->toolWidgetFillStyle = nullptr; 0174 } 0175 0176 viewManager ()->unsetCursor (); 0177 } 0178 0179 //--------------------------------------------------------------------- 0180 0181 void kpToolRectangularBase::applyModifiers () 0182 { 0183 QRect rect = normalizedRect (); 0184 0185 #if DEBUG_KP_TOOL_RECTANGULAR_BASE 0186 qCDebug(kpLogTools) << "kpToolRectangularBase::applyModifiers(" << rect 0187 << ") shift=" << shiftPressed () 0188 << " ctrl=" << controlPressed () 0189 << endl; 0190 #endif 0191 0192 // user wants to startPoint () == center 0193 if (controlPressed ()) 0194 { 0195 int xdiff = qAbs (startPoint ().x () - currentPoint ().x ()); 0196 int ydiff = qAbs (startPoint ().y () - currentPoint ().y ()); 0197 rect = QRect (startPoint ().x () - xdiff, startPoint ().y () - ydiff, 0198 xdiff * 2 + 1, ydiff * 2 + 1); 0199 } 0200 0201 // user wants major axis == minor axis: 0202 // rectangle --> square 0203 // rounded rectangle --> rounded square 0204 // ellipse --> circle 0205 if (shiftPressed ()) 0206 { 0207 if (!controlPressed ()) 0208 { 0209 if (rect.width () < rect.height ()) 0210 { 0211 if (startPoint ().y () == rect.y ()) { 0212 rect.setHeight (rect.width ()); 0213 } 0214 else { 0215 rect.setY (rect.bottom () - rect.width () + 1); 0216 } 0217 } 0218 else 0219 { 0220 if (startPoint ().x () == rect.x ()) { 0221 rect.setWidth (rect.height ()); 0222 } 0223 else { 0224 rect.setX (rect.right () - rect.height () + 1); 0225 } 0226 } 0227 } 0228 // have to maintain the center 0229 else 0230 { 0231 if (rect.width () < rect.height ()) 0232 { 0233 QPoint center = rect.center (); 0234 rect.setHeight (rect.width ()); 0235 rect.moveCenter (center); 0236 } 0237 else 0238 { 0239 QPoint center = rect.center (); 0240 rect.setWidth (rect.height ()); 0241 rect.moveCenter (center); 0242 } 0243 } 0244 } 0245 0246 d->toolRectangleRect = rect; 0247 } 0248 0249 //--------------------------------------------------------------------- 0250 0251 void kpToolRectangularBase::beginDraw () 0252 { 0253 setUserMessage (cancelUserMessage ()); 0254 } 0255 0256 //--------------------------------------------------------------------- 0257 0258 0259 // private 0260 kpColor kpToolRectangularBase::drawingForegroundColor () const 0261 { 0262 return color (mouseButton ()); 0263 } 0264 0265 //--------------------------------------------------------------------- 0266 0267 // private 0268 kpColor kpToolRectangularBase::drawingBackgroundColor () const 0269 { 0270 const kpColor foregroundColor = color (mouseButton ()); 0271 const kpColor backgroundColor = color (1 - mouseButton ()); 0272 0273 return d->toolWidgetFillStyle->drawingBackgroundColor ( 0274 foregroundColor, backgroundColor); 0275 } 0276 0277 //--------------------------------------------------------------------- 0278 0279 // private 0280 void kpToolRectangularBase::updateShape () 0281 { 0282 kpImage image = document ()->getImageAt (d->toolRectangleRect); 0283 0284 // Invoke shape drawing function passed in ctor. 0285 (*d->drawShapeFunc) (&image, 0286 0, 0, d->toolRectangleRect.width (), d->toolRectangleRect.height (), 0287 drawingForegroundColor (), d->toolWidgetLineWidth->lineWidth (), 0288 drawingBackgroundColor ()); 0289 0290 kpTempImage newTempImage (false/*always display*/, 0291 kpTempImage::SetImage/*render mode*/, 0292 d->toolRectangleRect.topLeft (), 0293 image); 0294 0295 viewManager ()->setFastUpdates (); 0296 viewManager ()->setTempImage (newTempImage); 0297 viewManager ()->restoreFastUpdates (); 0298 } 0299 0300 //--------------------------------------------------------------------- 0301 0302 void kpToolRectangularBase::draw (const QPoint &, const QPoint &, const QRect &) 0303 { 0304 applyModifiers (); 0305 0306 0307 updateShape (); 0308 0309 0310 // Recover the start and end points from the transformed & normalized d->toolRectangleRect 0311 0312 // S. or S or SC or S == C 0313 // .C C 0314 if (currentPoint ().x () >= startPoint ().x () && 0315 currentPoint ().y () >= startPoint ().y ()) 0316 { 0317 setUserShapePoints (d->toolRectangleRect.topLeft (), 0318 d->toolRectangleRect.bottomRight ()); 0319 } 0320 // .C or C 0321 // S. S 0322 else if (currentPoint ().x () >= startPoint ().x () && 0323 currentPoint ().y () < startPoint ().y ()) 0324 { 0325 setUserShapePoints (d->toolRectangleRect.bottomLeft (), 0326 d->toolRectangleRect.topRight ()); 0327 } 0328 // .S or CS 0329 // C. 0330 else if (currentPoint ().x () < startPoint ().x () && 0331 currentPoint ().y () >= startPoint ().y ()) 0332 { 0333 setUserShapePoints (d->toolRectangleRect.topRight (), 0334 d->toolRectangleRect.bottomLeft ()); 0335 } 0336 // C. 0337 // .S 0338 else 0339 { 0340 setUserShapePoints (d->toolRectangleRect.bottomRight (), 0341 d->toolRectangleRect.topLeft ()); 0342 } 0343 } 0344 0345 //--------------------------------------------------------------------- 0346 0347 void kpToolRectangularBase::cancelShape () 0348 { 0349 viewManager ()->invalidateTempImage (); 0350 0351 setUserMessage (i18n ("Let go of all the mouse buttons.")); 0352 } 0353 0354 //--------------------------------------------------------------------- 0355 0356 void kpToolRectangularBase::releasedAllButtons () 0357 { 0358 setUserMessage (haventBegunDrawUserMessage ()); 0359 } 0360 0361 //--------------------------------------------------------------------- 0362 0363 void kpToolRectangularBase::endDraw (const QPoint &, const QRect &) 0364 { 0365 applyModifiers (); 0366 0367 // TODO: flicker 0368 // Later: So why can't we use kpViewManager::setQueueUpdates()? Check SVN 0369 // log to see if this method was not available at the time of the 0370 // TODO, hence justifying the TODO. 0371 // Later2: kpToolPolygonalBase, and perhaps, other shapes will have the 0372 // same problem. 0373 viewManager ()->invalidateTempImage (); 0374 0375 environ ()->commandHistory ()->addCommand ( 0376 new kpToolRectangularCommand ( 0377 text (), 0378 d->drawShapeFunc, d->toolRectangleRect, 0379 drawingForegroundColor (), d->toolWidgetLineWidth->lineWidth (), 0380 drawingBackgroundColor (), 0381 environ ()->commandEnvironment ())); 0382 0383 setUserMessage (haventBegunDrawUserMessage ()); 0384 } 0385 0386 //--------------------------------------------------------------------- 0387 0388 #include "moc_kpToolRectangularBase.cpp"