TDE graphics utilities
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

kptoolairspray.cpp 9.3KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376
  1. /*
  2. Copyright (c) 2003,2004,2005 Clarence Dang <dang@kde.org>
  3. All rights reserved.
  4. Redistribution and use in source and binary forms, with or without
  5. modification, are permitted provided that the following conditions
  6. are met:
  7. 1. Redistributions of source code must retain the above copyright
  8. notice, this list of conditions and the following disclaimer.
  9. 2. Redistributions in binary form must reproduce the above copyright
  10. notice, this list of conditions and the following disclaimer in the
  11. documentation and/or other materials provided with the distribution.
  12. THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
  13. IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
  14. OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
  15. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
  16. INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
  17. NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
  18. DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
  19. THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
  20. (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
  21. THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  22. */
  23. #define DEBUG_KP_TOOL_SPRAYCAN 0
  24. #include <stdlib.h>
  25. #include <tqbitmap.h>
  26. #include <tqpainter.h>
  27. #include <tqpen.h>
  28. #include <tqpixmap.h>
  29. #include <tqpoint.h>
  30. #include <tqpointarray.h>
  31. #include <tqrect.h>
  32. #include <tqtimer.h>
  33. #include <kdebug.h>
  34. #include <tdelocale.h>
  35. #include <kpcommandhistory.h>
  36. #include <kpdefs.h>
  37. #include <kpdocument.h>
  38. #include <kpmainwindow.h>
  39. #include <kppixmapfx.h>
  40. #include <kptoolairspray.h>
  41. #include <kptooltoolbar.h>
  42. #include <kptoolwidgetspraycansize.h>
  43. #include <kpview.h>
  44. #include <kpviewmanager.h>
  45. /*
  46. * kpToolAirSpray
  47. */
  48. kpToolAirSpray::kpToolAirSpray (kpMainWindow *mainWindow)
  49. : kpTool (i18n ("Spraycan"), i18n ("Sprays graffiti"),
  50. TQt::Key_Y,
  51. mainWindow, "tool_spraycan"),
  52. m_currentCommand (0)
  53. {
  54. m_timer = new TQTimer (this);
  55. connect (m_timer, TQT_SIGNAL (timeout ()), this, TQT_SLOT (actuallyDraw ()));
  56. }
  57. kpToolAirSpray::~kpToolAirSpray ()
  58. {
  59. delete m_currentCommand;
  60. }
  61. // private
  62. TQString kpToolAirSpray::haventBegunDrawUserMessage () const
  63. {
  64. return i18n ("Click or drag to spray graffiti.");
  65. }
  66. // public virtual
  67. void kpToolAirSpray::begin ()
  68. {
  69. kpToolToolBar *tb = toolToolBar ();
  70. m_toolWidgetSpraycanSize = 0;
  71. m_size = 10;
  72. if (tb)
  73. {
  74. m_toolWidgetSpraycanSize = tb->toolWidgetSpraycanSize ();
  75. if (m_toolWidgetSpraycanSize)
  76. {
  77. m_size = m_toolWidgetSpraycanSize->spraycanSize ();
  78. connect (m_toolWidgetSpraycanSize, TQT_SIGNAL (spraycanSizeChanged (int)),
  79. this, TQT_SLOT (slotSpraycanSizeChanged (int)));
  80. m_toolWidgetSpraycanSize->show ();
  81. }
  82. }
  83. setUserMessage (haventBegunDrawUserMessage ());
  84. }
  85. // public virtual
  86. void kpToolAirSpray::end ()
  87. {
  88. if (m_toolWidgetSpraycanSize)
  89. {
  90. disconnect (m_toolWidgetSpraycanSize, TQT_SIGNAL (spraycanSizeChanged (int)),
  91. this, TQT_SLOT (slotSpraycanSizeChanged (int)));
  92. m_toolWidgetSpraycanSize = 0;
  93. }
  94. setUserMessage (haventBegunDrawUserMessage ());
  95. }
  96. // private slot
  97. void kpToolAirSpray::slotSpraycanSizeChanged (int size)
  98. {
  99. m_size = size;
  100. }
  101. void kpToolAirSpray::beginDraw ()
  102. {
  103. m_currentCommand = new kpToolAirSprayCommand (
  104. color (m_mouseButton),
  105. m_size,
  106. mainWindow ());
  107. // without delay
  108. actuallyDraw ();
  109. // use a timer instead of reimplementing draw() (we don't draw all the time)
  110. m_timer->start (25);
  111. setUserMessage (cancelUserMessage ());
  112. }
  113. void kpToolAirSpray::draw (const TQPoint &thisPoint, const TQPoint &, const TQRect &)
  114. {
  115. // if the user is moving the spray, make the spray line continuous
  116. if (thisPoint != m_lastPoint)
  117. {
  118. // without delay
  119. actuallyDraw ();
  120. }
  121. setUserShapePoints (thisPoint);
  122. }
  123. void kpToolAirSpray::actuallyDraw ()
  124. {
  125. TQPointArray pArray (10);
  126. int numPoints = 0;
  127. TQPoint p = m_currentPoint;
  128. #if DEBUG_KP_TOOL_SPRAYCAN
  129. kdDebug () << "kpToolAirSpray::actuallyDraw() currentPoint=" << p
  130. << " size=" << m_size
  131. << endl;
  132. #endif
  133. int radius = m_size / 2;
  134. for (int i = 0; i < 10; i++)
  135. {
  136. int dx, dy;
  137. dx = (rand () % m_size) - radius;
  138. dy = (rand () % m_size) - radius;
  139. // make it look circular
  140. // OPT: can be done better
  141. if (dx * dx + dy * dy <= radius * radius)
  142. pArray [numPoints++] = TQPoint (p.x () + dx, p.y () + dy);
  143. }
  144. pArray.resize (numPoints);
  145. if (numPoints > 0)
  146. {
  147. // leave the command to draw
  148. m_currentCommand->addPoints (pArray);
  149. }
  150. }
  151. // virtual
  152. void kpToolAirSpray::cancelShape ()
  153. {
  154. #if 0
  155. endDraw (TQPoint (), TQRect ());
  156. mainWindow ()->commandHistory ()->undo ();
  157. #else
  158. m_timer->stop ();
  159. m_currentCommand->finalize ();
  160. m_currentCommand->cancel ();
  161. delete m_currentCommand;
  162. m_currentCommand = 0;
  163. #endif
  164. setUserMessage (i18n ("Let go of all the mouse buttons."));
  165. }
  166. void kpToolAirSpray::releasedAllButtons ()
  167. {
  168. setUserMessage (haventBegunDrawUserMessage ());
  169. }
  170. // virtual
  171. void kpToolAirSpray::endDraw (const TQPoint &, const TQRect &)
  172. {
  173. m_timer->stop ();
  174. m_currentCommand->finalize ();
  175. mainWindow ()->commandHistory ()->addCommand (m_currentCommand, false /* don't exec */);
  176. // don't delete - it's up to the commandHistory
  177. m_currentCommand = 0;
  178. setUserMessage (haventBegunDrawUserMessage ());
  179. }
  180. /*
  181. * kpToolAirSprayCommand
  182. */
  183. kpToolAirSprayCommand::kpToolAirSprayCommand (const kpColor &color, int size,
  184. kpMainWindow *mainWindow)
  185. : kpCommand (mainWindow),
  186. m_color (color),
  187. m_size (size),
  188. m_newPixmapPtr (0)
  189. {
  190. m_oldPixmap = *document ()->pixmap ();
  191. }
  192. kpToolAirSprayCommand::~kpToolAirSprayCommand ()
  193. {
  194. delete m_newPixmapPtr;
  195. }
  196. // public virtual [base kpCommand]
  197. TQString kpToolAirSprayCommand::name () const
  198. {
  199. return i18n ("Spraycan");
  200. }
  201. // public virtual [base kpCommand]
  202. int kpToolAirSprayCommand::size () const
  203. {
  204. return kpPixmapFX::pixmapSize (m_newPixmapPtr) +
  205. kpPixmapFX::pixmapSize (m_oldPixmap);
  206. }
  207. // Redo:
  208. //
  209. // must not call before unexecute() as m_newPixmapPtr is null
  210. // (one reason why we told addCommand() not to execute,
  211. // the other being that the dots have already been draw onto the doc)
  212. void kpToolAirSprayCommand::execute ()
  213. {
  214. if (m_newPixmapPtr)
  215. {
  216. document ()->setPixmapAt (*m_newPixmapPtr, m_boundingRect.topLeft ());
  217. // (will be regenerated in unexecute() if required)
  218. delete m_newPixmapPtr;
  219. m_newPixmapPtr = 0;
  220. }
  221. else
  222. kdError () << "kpToolAirSprayCommand::execute() has null m_newPixmapPtr" << endl;
  223. }
  224. // Undo:
  225. void kpToolAirSprayCommand::unexecute ()
  226. {
  227. if (!m_newPixmapPtr)
  228. {
  229. // the ultimate in laziness - figure out Redo info only if we Undo
  230. m_newPixmapPtr = new TQPixmap (m_boundingRect.width (), m_boundingRect.height ());
  231. *m_newPixmapPtr = document ()->getPixmapAt (m_boundingRect);
  232. }
  233. else
  234. kdError () << "kpToolAirSprayCommand::unexecute() has non-null newPixmapPtr" << endl;
  235. document ()->setPixmapAt (m_oldPixmap, m_boundingRect.topLeft ());
  236. }
  237. // public
  238. void kpToolAirSprayCommand::addPoints (const TQPointArray &points)
  239. {
  240. TQRect docRect = points.boundingRect ();
  241. #if DEBUG_KP_TOOL_SPRAYCAN
  242. kdDebug () << "kpToolAirSprayCommand::addPoints() docRect=" << docRect
  243. << " numPoints=" << points.count () << endl;
  244. for (int i = 0; i < (int) points.count (); i++)
  245. kdDebug () << "\t" << i << ": " << points [i] << endl;
  246. #endif
  247. TQPixmap pixmap = document ()->getPixmapAt (docRect);
  248. TQBitmap mask;
  249. TQPainter painter, maskPainter;
  250. if (m_color.isOpaque ())
  251. {
  252. painter.begin (&pixmap);
  253. painter.setPen (m_color.toTQColor ());
  254. }
  255. if (pixmap.mask () || m_color.isTransparent ())
  256. {
  257. mask = kpPixmapFX::getNonNullMask (pixmap);
  258. maskPainter.begin (&mask);
  259. maskPainter.setPen (m_color.maskColor ());
  260. }
  261. for (int i = 0; i < (int) points.count (); i++)
  262. {
  263. TQPoint pt (points [i].x () - docRect.x (),
  264. points [i].y () - docRect.y ());
  265. if (painter.isActive ())
  266. painter.drawPoint (pt);
  267. if (maskPainter.isActive ())
  268. maskPainter.drawPoint (pt);
  269. }
  270. if (maskPainter.isActive ())
  271. maskPainter.end ();
  272. if (painter.isActive ())
  273. painter.end ();
  274. if (!mask.isNull ())
  275. pixmap.setMask (mask);
  276. viewManager ()->setFastUpdates ();
  277. document ()->setPixmapAt (pixmap, docRect.topLeft ());
  278. viewManager ()->restoreFastUpdates ();
  279. m_boundingRect = m_boundingRect.unite (docRect);
  280. }
  281. void kpToolAirSprayCommand::finalize ()
  282. {
  283. // store only needed part of doc pixmap
  284. m_oldPixmap = kpTool::neededPixmap (m_oldPixmap, m_boundingRect);
  285. }
  286. void kpToolAirSprayCommand::cancel ()
  287. {
  288. if (m_boundingRect.isValid ())
  289. {
  290. viewManager ()->setFastUpdates ();
  291. document ()->setPixmapAt (m_oldPixmap, m_boundingRect.topLeft ());
  292. viewManager ()->restoreFastUpdates ();
  293. }
  294. }
  295. #include <kptoolairspray.moc>