summaryrefslogtreecommitdiffstats
path: root/kolourpaint/tools
diff options
context:
space:
mode:
authortoma <toma@283d02a7-25f6-0310-bc7c-ecb5cbfe19da>2009-11-25 17:56:58 +0000
committertoma <toma@283d02a7-25f6-0310-bc7c-ecb5cbfe19da>2009-11-25 17:56:58 +0000
commit47d455dd55be855e4cc691c32f687f723d9247ee (patch)
tree52e236aaa2576bdb3840ebede26619692fed6d7d /kolourpaint/tools
downloadtdegraphics-47d455dd55be855e4cc691c32f687f723d9247ee.tar.gz
tdegraphics-47d455dd55be855e4cc691c32f687f723d9247ee.zip
Copy the KDE 3.5 branch to branches/trinity for new KDE 3.5 features.
BUG:215923 git-svn-id: svn://anonsvn.kde.org/home/kde/branches/trinity/kdegraphics@1054174 283d02a7-25f6-0310-bc7c-ecb5cbfe19da
Diffstat (limited to 'kolourpaint/tools')
-rw-r--r--kolourpaint/tools/Makefile.am53
-rw-r--r--kolourpaint/tools/kptoolaction.cpp107
-rw-r--r--kolourpaint/tools/kptoolaction.h78
-rw-r--r--kolourpaint/tools/kptoolairspray.cpp376
-rw-r--r--kolourpaint/tools/kptoolairspray.h110
-rw-r--r--kolourpaint/tools/kptoolautocrop.cpp780
-rw-r--r--kolourpaint/tools/kptoolautocrop.h127
-rw-r--r--kolourpaint/tools/kptoolbrush.cpp45
-rw-r--r--kolourpaint/tools/kptoolbrush.h43
-rw-r--r--kolourpaint/tools/kptoolclear.cpp135
-rw-r--r--kolourpaint/tools/kptoolclear.h68
-rw-r--r--kolourpaint/tools/kptoolcolorpicker.cpp197
-rw-r--r--kolourpaint/tools/kptoolcolorpicker.h95
-rw-r--r--kolourpaint/tools/kptoolcolorwasher.cpp45
-rw-r--r--kolourpaint/tools/kptoolcolorwasher.h43
-rw-r--r--kolourpaint/tools/kptoolconverttograyscale.cpp106
-rw-r--r--kolourpaint/tools/kptoolconverttograyscale.h57
-rw-r--r--kolourpaint/tools/kptoolcrop.cpp335
-rw-r--r--kolourpaint/tools/kptoolcrop.h39
-rw-r--r--kolourpaint/tools/kptoolcurve.cpp47
-rw-r--r--kolourpaint/tools/kptoolcurve.h45
-rw-r--r--kolourpaint/tools/kptoolellipse.cpp45
-rw-r--r--kolourpaint/tools/kptoolellipse.h45
-rw-r--r--kolourpaint/tools/kptoolellipticalselection.cpp46
-rw-r--r--kolourpaint/tools/kptoolellipticalselection.h43
-rw-r--r--kolourpaint/tools/kptooleraser.cpp44
-rw-r--r--kolourpaint/tools/kptooleraser.h43
-rw-r--r--kolourpaint/tools/kptoolflip.cpp213
-rw-r--r--kolourpaint/tools/kptoolflip.h88
-rw-r--r--kolourpaint/tools/kptoolfloodfill.cpp261
-rw-r--r--kolourpaint/tools/kptoolfloodfill.h94
-rw-r--r--kolourpaint/tools/kptoolfreeformselection.cpp46
-rw-r--r--kolourpaint/tools/kptoolfreeformselection.h43
-rw-r--r--kolourpaint/tools/kptoolline.cpp47
-rw-r--r--kolourpaint/tools/kptoolline.h45
-rw-r--r--kolourpaint/tools/kptoolpen.cpp1145
-rw-r--r--kolourpaint/tools/kptoolpen.h160
-rw-r--r--kolourpaint/tools/kptoolpolygon.cpp895
-rw-r--r--kolourpaint/tools/kptoolpolygon.h157
-rw-r--r--kolourpaint/tools/kptoolpolyline.cpp47
-rw-r--r--kolourpaint/tools/kptoolpolyline.h46
-rw-r--r--kolourpaint/tools/kptoolpreviewdialog.cpp431
-rw-r--r--kolourpaint/tools/kptoolpreviewdialog.h131
-rw-r--r--kolourpaint/tools/kptoolrectangle.cpp638
-rw-r--r--kolourpaint/tools/kptoolrectangle.h142
-rw-r--r--kolourpaint/tools/kptoolrectselection.cpp46
-rw-r--r--kolourpaint/tools/kptoolrectselection.h43
-rw-r--r--kolourpaint/tools/kptoolresizescale.cpp1222
-rw-r--r--kolourpaint/tools/kptoolresizescale.h196
-rw-r--r--kolourpaint/tools/kptoolrotate.cpp500
-rw-r--r--kolourpaint/tools/kptoolrotate.h129
-rw-r--r--kolourpaint/tools/kptoolroundedrectangle.cpp45
-rw-r--r--kolourpaint/tools/kptoolroundedrectangle.h45
-rw-r--r--kolourpaint/tools/kptoolselection.cpp2371
-rw-r--r--kolourpaint/tools/kptoolselection.h313
-rw-r--r--kolourpaint/tools/kptoolskew.cpp449
-rw-r--r--kolourpaint/tools/kptoolskew.h121
-rw-r--r--kolourpaint/tools/kptooltext.cpp1394
-rw-r--r--kolourpaint/tools/kptooltext.h203
59 files changed, 14903 insertions, 0 deletions
diff --git a/kolourpaint/tools/Makefile.am b/kolourpaint/tools/Makefile.am
new file mode 100644
index 00000000..9c665cb1
--- /dev/null
+++ b/kolourpaint/tools/Makefile.am
@@ -0,0 +1,53 @@
+INCLUDES = -I$(srcdir)/.. -I$(srcdir)/../cursors -I$(srcdir)/../interfaces \
+ -I$(srcdir)/../pixmapfx \
+ -I$(srcdir)/../tools \
+ -I$(srcdir)/../views \
+ -I$(srcdir)/../widgets $(all_includes)
+
+noinst_LTLIBRARIES = libkolourpainttools.la
+libkolourpainttools_la_SOURCES = kptoolaction.cpp \
+ kptoolairspray.cpp \
+ kptoolautocrop.cpp \
+ kptoolbrush.cpp kptoolclear.cpp \
+ kptoolcolorpicker.cpp kptoolcolorwasher.cpp \
+ kptoolconverttograyscale.cpp \
+ kptoolcrop.cpp \
+ kptoolcurve.cpp \
+ kptoolellipse.cpp \
+ kptoolellipticalselection.cpp kptooleraser.cpp \
+ kptoolflip.cpp kptoolfloodfill.cpp \
+ kptoolfreeformselection.cpp \
+ kptoolline.cpp kptoolpen.cpp \
+ kptoolpolygon.cpp kptoolpolyline.cpp \
+ kptoolpreviewdialog.cpp \
+ kptoolrectangle.cpp kptoolrectselection.cpp \
+ kptoolresizescale.cpp kptoolrotate.cpp \
+ kptoolroundedrectangle.cpp kptoolselection.cpp \
+ kptoolskew.cpp kptooltext.cpp
+
+# TODO: Why is this needed? Isn't linking at the toplevel enough?
+libkolourpainttools_la_LIBADD = ../pixmapfx/libkolourpaintpixmapfx.la ../cursors/libkolourpaintcursors.la
+
+METASOURCES = kptoolaction.moc \
+ kptoolairspray.moc \
+ kptoolbrush.moc \
+ kptoolcolorpicker.moc \
+ kptoolcolorwasher.moc \
+ kptoolcurve.moc \
+ kptoolellipse.moc \
+ kptooleraser.moc \
+ kptoolflip.moc \
+ kptoolfloodfill.moc \
+ kptoolline.moc \
+ kptoolpen.moc \
+ kptoolpolygon.moc \
+ kptoolpolyline.moc \
+ kptoolpreviewdialog.moc \
+ kptoolrectangle.moc \
+ kptoolresizescale.moc \
+ kptoolrotate.moc \
+ kptoolroundedrectangle.moc \
+ kptoolselection.moc \
+ kptoolskew.moc \
+ kptooltext.moc
+
diff --git a/kolourpaint/tools/kptoolaction.cpp b/kolourpaint/tools/kptoolaction.cpp
new file mode 100644
index 00000000..ef5c8510
--- /dev/null
+++ b/kolourpaint/tools/kptoolaction.cpp
@@ -0,0 +1,107 @@
+
+/*
+ Copyright (c) 2003,2004,2005 Clarence Dang <dang@kde.org>
+ 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 <kptoolaction.h>
+
+#include <kptool.h>
+
+
+kpToolAction::kpToolAction (const QString &text,
+ const QString &pic, const KShortcut &shortcut,
+ const QObject *receiver, const char *slot,
+ QObject *parent, const char *name)
+ : KToggleAction (text,
+ pic, shortcut,
+ receiver, slot,
+ parent, name)
+{
+ updateToolTip ();
+}
+
+kpToolAction::~kpToolAction ()
+{
+}
+
+
+// protected
+void kpToolAction::updateToolTip ()
+{
+ const QString newToolTip =
+ kpTool::toolTipForTextAndShortcut (text (), shortcut ());
+ if (newToolTip == toolTip ())
+ return;
+
+ setToolTip (newToolTip);
+ emit toolTipChanged (newToolTip);
+}
+
+
+//
+// KToggleAction interface
+//
+
+// public slot virtual [base KAction]
+void kpToolAction::setText (const QString &text)
+{
+ KToggleAction::setText (text);
+ updateToolTip ();
+}
+
+// public slot virtual [base KAction]
+bool kpToolAction::setShortcut (const KShortcut &shortcut)
+{
+ bool ret = KToggleAction::setShortcut (shortcut);
+ updateToolTip ();
+ return ret;
+}
+
+
+//
+// KToggleAction implements kpSingleKeyTriggersActionInterface
+//
+
+// public virtual [base kpSingleKeyTriggersActionInterface]
+const char *kpToolAction::actionName () const
+{
+ return name ();
+}
+
+// public virtual [base kpSingleKeyTriggersActionInterface]
+KShortcut kpToolAction::actionShortcut () const
+{
+ return shortcut ();
+}
+
+// public virtual [base kpSingleKeyTriggersActionInterface]
+void kpToolAction::actionSetShortcut (const KShortcut &shortcut)
+{
+ setShortcut (shortcut);
+}
+
+
+#include <kptoolaction.moc>
diff --git a/kolourpaint/tools/kptoolaction.h b/kolourpaint/tools/kptoolaction.h
new file mode 100644
index 00000000..df4e407e
--- /dev/null
+++ b/kolourpaint/tools/kptoolaction.h
@@ -0,0 +1,78 @@
+
+/*
+ Copyright (c) 2003,2004,2005 Clarence Dang <dang@kde.org>
+ 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_ACTION_H
+#define KP_TOOL_ACTION_H
+
+#include <kactionclasses.h>
+
+#include <kpsinglekeytriggersaction.h>
+
+
+// Same as KToggleAction but shows the first single key trigger in the tooltip.
+class kpToolAction : public KToggleAction,
+ public kpSingleKeyTriggersActionInterface
+{
+Q_OBJECT
+
+public:
+ kpToolAction (const QString &text,
+ const QString &pic, const KShortcut &shortcut,
+ const QObject *receiver, const char *slot,
+ QObject *parent, const char *name);
+ virtual ~kpToolAction ();
+
+
+signals:
+ // Not emitted when toolTip is manually overriden by setToolTip()
+ void toolTipChanged (const QString &string);
+
+protected:
+ void updateToolTip ();
+
+
+ //
+ // KToggleAction interface
+ //
+
+public slots:
+ virtual void setText (const QString &text);
+ virtual bool setShortcut (const KShortcut &shortcut);
+
+
+ //
+ // kpSingleKeyTriggersActionInterface
+ //
+
+public:
+ virtual const char *actionName () const;
+ virtual KShortcut actionShortcut () const;
+ virtual void actionSetShortcut (const KShortcut &shortcut);
+};
+
+
+#endif // KP_TOOL_ACTION_H
diff --git a/kolourpaint/tools/kptoolairspray.cpp b/kolourpaint/tools/kptoolairspray.cpp
new file mode 100644
index 00000000..43f8bef3
--- /dev/null
+++ b/kolourpaint/tools/kptoolairspray.cpp
@@ -0,0 +1,376 @@
+
+/*
+ Copyright (c) 2003,2004,2005 Clarence Dang <dang@kde.org>
+ 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 <stdlib.h>
+
+#include <qbitmap.h>
+#include <qpainter.h>
+#include <qpen.h>
+#include <qpixmap.h>
+#include <qpoint.h>
+#include <qpointarray.h>
+#include <qrect.h>
+#include <qtimer.h>
+
+#include <kdebug.h>
+#include <klocale.h>
+
+#include <kpcommandhistory.h>
+#include <kpdefs.h>
+#include <kpdocument.h>
+#include <kpmainwindow.h>
+#include <kppixmapfx.h>
+#include <kptoolairspray.h>
+#include <kptooltoolbar.h>
+#include <kptoolwidgetspraycansize.h>
+#include <kpview.h>
+#include <kpviewmanager.h>
+
+
+/*
+ * kpToolAirSpray
+ */
+
+kpToolAirSpray::kpToolAirSpray (kpMainWindow *mainWindow)
+ : kpTool (i18n ("Spraycan"), i18n ("Sprays graffiti"),
+ Qt::Key_Y,
+ mainWindow, "tool_spraycan"),
+ m_currentCommand (0)
+{
+ m_timer = new QTimer (this);
+ connect (m_timer, SIGNAL (timeout ()), this, SLOT (actuallyDraw ()));
+}
+
+kpToolAirSpray::~kpToolAirSpray ()
+{
+ delete m_currentCommand;
+}
+
+
+// private
+QString kpToolAirSpray::haventBegunDrawUserMessage () const
+{
+ return i18n ("Click or drag to spray graffiti.");
+}
+
+// public virtual
+void kpToolAirSpray::begin ()
+{
+ kpToolToolBar *tb = toolToolBar ();
+
+ m_toolWidgetSpraycanSize = 0;
+ m_size = 10;
+
+ if (tb)
+ {
+ m_toolWidgetSpraycanSize = tb->toolWidgetSpraycanSize ();
+
+ if (m_toolWidgetSpraycanSize)
+ {
+ m_size = m_toolWidgetSpraycanSize->spraycanSize ();
+ connect (m_toolWidgetSpraycanSize, SIGNAL (spraycanSizeChanged (int)),
+ this, SLOT (slotSpraycanSizeChanged (int)));
+
+ m_toolWidgetSpraycanSize->show ();
+ }
+ }
+
+ setUserMessage (haventBegunDrawUserMessage ());
+}
+
+// public virtual
+void kpToolAirSpray::end ()
+{
+ if (m_toolWidgetSpraycanSize)
+ {
+ disconnect (m_toolWidgetSpraycanSize, SIGNAL (spraycanSizeChanged (int)),
+ this, SLOT (slotSpraycanSizeChanged (int)));
+ m_toolWidgetSpraycanSize = 0;
+ }
+
+ setUserMessage (haventBegunDrawUserMessage ());
+}
+
+// private slot
+void kpToolAirSpray::slotSpraycanSizeChanged (int size)
+{
+ m_size = size;
+}
+
+
+void kpToolAirSpray::beginDraw ()
+{
+ m_currentCommand = new kpToolAirSprayCommand (
+ color (m_mouseButton),
+ m_size,
+ mainWindow ());
+
+ // without delay
+ actuallyDraw ();
+
+ // use a timer instead of reimplementing draw() (we don't draw all the time)
+ m_timer->start (25);
+
+ setUserMessage (cancelUserMessage ());
+}
+
+void kpToolAirSpray::draw (const QPoint &thisPoint, const QPoint &, const QRect &)
+{
+ // if the user is moving the spray, make the spray line continuous
+ if (thisPoint != m_lastPoint)
+ {
+ // without delay
+ actuallyDraw ();
+ }
+
+ setUserShapePoints (thisPoint);
+}
+
+void kpToolAirSpray::actuallyDraw ()
+{
+ QPointArray pArray (10);
+ int numPoints = 0;
+
+ QPoint p = m_currentPoint;
+
+#if DEBUG_KP_TOOL_SPRAYCAN
+ kdDebug () << "kpToolAirSpray::actuallyDraw() currentPoint=" << p
+ << " size=" << m_size
+ << endl;
+#endif
+
+ int radius = m_size / 2;
+
+ for (int i = 0; i < 10; i++)
+ {
+ int dx, dy;
+
+ dx = (rand () % m_size) - radius;
+ dy = (rand () % m_size) - radius;
+
+ // make it look circular
+ // OPT: can be done better
+ if (dx * dx + dy * dy <= radius * radius)
+ pArray [numPoints++] = QPoint (p.x () + dx, p.y () + dy);
+ }
+
+ pArray.resize (numPoints);
+
+ if (numPoints > 0)
+ {
+ // leave the command to draw
+ m_currentCommand->addPoints (pArray);
+ }
+}
+
+// virtual
+void kpToolAirSpray::cancelShape ()
+{
+#if 0
+ endDraw (QPoint (), QRect ());
+ mainWindow ()->commandHistory ()->undo ();
+#else
+ m_timer->stop ();
+
+ m_currentCommand->finalize ();
+ m_currentCommand->cancel ();
+
+ delete m_currentCommand;
+ m_currentCommand = 0;
+#endif
+
+ setUserMessage (i18n ("Let go of all the mouse buttons."));
+}
+
+void kpToolAirSpray::releasedAllButtons ()
+{
+ setUserMessage (haventBegunDrawUserMessage ());
+}
+
+// virtual
+void kpToolAirSpray::endDraw (const QPoint &, const QRect &)
+{
+ m_timer->stop ();
+
+ m_currentCommand->finalize ();
+ mainWindow ()->commandHistory ()->addCommand (m_currentCommand, false /* don't exec */);
+
+ // don't delete - it's up to the commandHistory
+ m_currentCommand = 0;
+
+ setUserMessage (haventBegunDrawUserMessage ());
+}
+
+
+/*
+ * kpToolAirSprayCommand
+ */
+
+kpToolAirSprayCommand::kpToolAirSprayCommand (const kpColor &color, int size,
+ kpMainWindow *mainWindow)
+ : kpCommand (mainWindow),
+ m_color (color),
+ m_size (size),
+ m_newPixmapPtr (0)
+{
+ m_oldPixmap = *document ()->pixmap ();
+}
+
+kpToolAirSprayCommand::~kpToolAirSprayCommand ()
+{
+ delete m_newPixmapPtr;
+}
+
+
+// public virtual [base kpCommand]
+QString kpToolAirSprayCommand::name () const
+{
+ return i18n ("Spraycan");
+}
+
+
+// public virtual [base kpCommand]
+int kpToolAirSprayCommand::size () const
+{
+ return kpPixmapFX::pixmapSize (m_newPixmapPtr) +
+ kpPixmapFX::pixmapSize (m_oldPixmap);
+}
+
+
+// Redo:
+//
+// must not call before unexecute() as m_newPixmapPtr is null
+// (one reason why we told addCommand() not to execute,
+// the other being that the dots have already been draw onto the doc)
+void kpToolAirSprayCommand::execute ()
+{
+ if (m_newPixmapPtr)
+ {
+ document ()->setPixmapAt (*m_newPixmapPtr, m_boundingRect.topLeft ());
+
+ // (will be regenerated in unexecute() if required)
+ delete m_newPixmapPtr;
+ m_newPixmapPtr = 0;
+ }
+ else
+ kdError () << "kpToolAirSprayCommand::execute() has null m_newPixmapPtr" << endl;
+}
+
+// Undo:
+void kpToolAirSprayCommand::unexecute ()
+{
+ if (!m_newPixmapPtr)
+ {
+ // the ultimate in laziness - figure out Redo info only if we Undo
+ m_newPixmapPtr = new QPixmap (m_boundingRect.width (), m_boundingRect.height ());
+ *m_newPixmapPtr = document ()->getPixmapAt (m_boundingRect);
+ }
+ else
+ kdError () << "kpToolAirSprayCommand::unexecute() has non-null newPixmapPtr" << endl;
+
+ document ()->setPixmapAt (m_oldPixmap, m_boundingRect.topLeft ());
+}
+
+
+// public
+void kpToolAirSprayCommand::addPoints (const QPointArray &points)
+{
+ QRect docRect = points.boundingRect ();
+
+#if DEBUG_KP_TOOL_SPRAYCAN
+ kdDebug () << "kpToolAirSprayCommand::addPoints() docRect=" << docRect
+ << " numPoints=" << points.count () << endl;
+ for (int i = 0; i < (int) points.count (); i++)
+ kdDebug () << "\t" << i << ": " << points [i] << endl;
+#endif
+
+ QPixmap pixmap = document ()->getPixmapAt (docRect);
+ QBitmap mask;
+
+ QPainter painter, maskPainter;
+
+ if (m_color.isOpaque ())
+ {
+ painter.begin (&pixmap);
+ painter.setPen (m_color.toQColor ());
+ }
+
+ if (pixmap.mask () || m_color.isTransparent ())
+ {
+ mask = kpPixmapFX::getNonNullMask (pixmap);
+ maskPainter.begin (&mask);
+ maskPainter.setPen (m_color.maskColor ());
+ }
+
+ for (int i = 0; i < (int) points.count (); i++)
+ {
+ QPoint pt (points [i].x () - docRect.x (),
+ points [i].y () - docRect.y ());
+
+ if (painter.isActive ())
+ painter.drawPoint (pt);
+
+ if (maskPainter.isActive ())
+ maskPainter.drawPoint (pt);
+ }
+
+ if (maskPainter.isActive ())
+ maskPainter.end ();
+
+ if (painter.isActive ())
+ painter.end ();
+
+ if (!mask.isNull ())
+ pixmap.setMask (mask);
+
+ viewManager ()->setFastUpdates ();
+ document ()->setPixmapAt (pixmap, docRect.topLeft ());
+ viewManager ()->restoreFastUpdates ();
+
+ m_boundingRect = m_boundingRect.unite (docRect);
+}
+
+void kpToolAirSprayCommand::finalize ()
+{
+ // store only needed part of doc pixmap
+ m_oldPixmap = kpTool::neededPixmap (m_oldPixmap, m_boundingRect);
+}
+
+void kpToolAirSprayCommand::cancel ()
+{
+ if (m_boundingRect.isValid ())
+ {
+ viewManager ()->setFastUpdates ();
+ document ()->setPixmapAt (m_oldPixmap, m_boundingRect.topLeft ());
+ viewManager ()->restoreFastUpdates ();
+ }
+}
+
+#include <kptoolairspray.moc>
diff --git a/kolourpaint/tools/kptoolairspray.h b/kolourpaint/tools/kptoolairspray.h
new file mode 100644
index 00000000..24f02787
--- /dev/null
+++ b/kolourpaint/tools/kptoolairspray.h
@@ -0,0 +1,110 @@
+
+/*
+ Copyright (c) 2003,2004,2005 Clarence Dang <dang@kde.org>
+ 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 __kptoolairspray_h__
+#define __kptoolairspray_h__
+
+#include <kpcommandhistory.h>
+#include <kpcolor.h>
+#include <kptool.h>
+
+class QPixmap;
+class QPoint;
+class QRect;
+class QString;
+class QTimer;
+
+class kpMainWindow;
+class kpToolAirSprayCommand;
+class kpToolWidgetSpraycanSize;
+class kpViewManager;
+
+class kpToolAirSpray : public kpTool
+{
+Q_OBJECT
+
+public:
+ kpToolAirSpray (kpMainWindow *);
+ virtual ~kpToolAirSpray ();
+
+private:
+ QString haventBegunDrawUserMessage () const;
+
+public:
+ virtual void begin ();
+ virtual void end ();
+
+private slots:
+ void slotSpraycanSizeChanged (int size);
+
+public:
+ virtual void beginDraw ();
+ virtual void draw (const QPoint &thisPoint, const QPoint &, const QRect &);
+ virtual void cancelShape ();
+ virtual void releasedAllButtons ();
+ virtual void endDraw (const QPoint &, const QRect &);
+
+public slots:
+ void actuallyDraw ();
+
+private:
+ kpToolWidgetSpraycanSize *m_toolWidgetSpraycanSize;
+ kpToolAirSprayCommand *m_currentCommand;
+ QTimer *m_timer;
+ int m_size;
+};
+
+class kpToolAirSprayCommand : public kpCommand
+{
+public:
+ kpToolAirSprayCommand (const kpColor &color, int size,
+ kpMainWindow *mainWindow);
+ virtual ~kpToolAirSprayCommand ();
+
+ virtual QString name () const;
+
+ virtual int size () const;
+
+ virtual void execute ();
+ virtual void unexecute ();
+
+ // interface for KToolAirSpray
+ void addPoints (const QPointArray &points);
+ void finalize ();
+ void cancel ();
+
+private:
+ kpColor m_color;
+ int m_size;
+
+ QPixmap *m_newPixmapPtr;
+ QPixmap m_oldPixmap;
+ QRect m_boundingRect;
+};
+
+#endif // __kptoolairspray_h__
diff --git a/kolourpaint/tools/kptoolautocrop.cpp b/kolourpaint/tools/kptoolautocrop.cpp
new file mode 100644
index 00000000..244c192d
--- /dev/null
+++ b/kolourpaint/tools/kptoolautocrop.cpp
@@ -0,0 +1,780 @@
+
+/*
+ Copyright (c) 2003,2004,2005 Clarence Dang <dang@kde.org>
+ 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).
+
+#define DEBUG_KP_TOOL_AUTO_CROP 0
+
+
+#include <kptoolautocrop.h>
+
+#include <qapplication.h>
+#include <qbitmap.h>
+#include <qimage.h>
+#include <qpainter.h>
+
+#include <kdebug.h>
+#include <klocale.h>
+#include <kmessagebox.h>
+
+#include <kpcolortoolbar.h>
+#include <kpcommandhistory.h>
+#include <kpdocument.h>
+#include <kpmainwindow.h>
+#include <kppixmapfx.h>
+#include <kpselection.h>
+#include <kptool.h>
+#include <kpviewmanager.h>
+
+
+kpToolAutoCropBorder::kpToolAutoCropBorder (const QPixmap *pixmapPtr,
+ int processedColorSimilarity)
+ : m_pixmapPtr (pixmapPtr),
+ m_processedColorSimilarity (processedColorSimilarity)
+{
+ invalidate ();
+}
+
+
+// public
+int kpToolAutoCropBorder::size () const
+{
+ return sizeof (kpToolAutoCropBorder);
+}
+
+
+// public
+const QPixmap *kpToolAutoCropBorder::pixmap () const
+{
+ return m_pixmapPtr;
+}
+
+// public
+int kpToolAutoCropBorder::processedColorSimilarity () const
+{
+ return m_processedColorSimilarity;
+}
+
+// public
+QRect kpToolAutoCropBorder::rect () const
+{
+ return m_rect;
+}
+
+// public
+int kpToolAutoCropBorder::left () const
+{
+ return m_rect.left ();
+}
+
+// public
+int kpToolAutoCropBorder::right () const
+{
+ return m_rect.right ();
+}
+
+// public
+int kpToolAutoCropBorder::top () const
+{
+ return m_rect.top ();
+}
+
+// public
+int kpToolAutoCropBorder::bottom () const
+{
+ return m_rect.bottom ();
+}
+
+// public
+kpColor kpToolAutoCropBorder::referenceColor () const
+{
+ return m_referenceColor;
+}
+
+// public
+kpColor kpToolAutoCropBorder::averageColor () const
+{
+ if (!m_rect.isValid ())
+ return kpColor::invalid;
+
+ if (m_referenceColor.isTransparent ())
+ return kpColor::transparent;
+ else if (m_processedColorSimilarity == 0)
+ return m_referenceColor;
+ else
+ {
+ int numPixels = (m_rect.width () * m_rect.height ());
+ if (numPixels <= 0)
+ {
+ kdError () << "kpToolAutoCropBorder::averageColor() rect=" << m_rect << endl;
+ return kpColor::invalid;
+ }
+
+ return kpColor (m_redSum / numPixels,
+ m_greenSum / numPixels,
+ m_blueSum / numPixels);
+ }
+}
+
+bool kpToolAutoCropBorder::isSingleColor () const
+{
+ return m_isSingleColor;
+}
+
+
+// public
+bool kpToolAutoCropBorder::calculate (int isX, int dir)
+{
+#if DEBUG_KP_TOOL_AUTO_CROP && 1
+ kdDebug () << "kpToolAutoCropBorder::calculate() CALLED!" << endl;
+#endif
+ int maxX = m_pixmapPtr->width () - 1;
+ int maxY = m_pixmapPtr->height () - 1;
+
+ QImage image = kpPixmapFX::convertToImage (*m_pixmapPtr);
+ if (image.isNull ())
+ {
+ kdError () << "Border::calculate() could not convert to QImage" << endl;
+ return false;
+ }
+
+ // (sync both branches)
+ if (isX)
+ {
+ int numCols = 0;
+ int startX = (dir > 0) ? 0 : maxX;
+
+ kpColor col = kpPixmapFX::getColorAtPixel (image, startX, 0);
+ for (int x = startX;
+ x >= 0 && x <= maxX;
+ x += dir)
+ {
+ int y;
+ for (y = 0; y <= maxY; y++)
+ {
+ if (!kpPixmapFX::getColorAtPixel (image, x, y).isSimilarTo (col, m_processedColorSimilarity))
+ break;
+ }
+
+ if (y <= maxY)
+ break;
+ else
+ numCols++;
+ }
+
+ if (numCols)
+ {
+ m_rect = QRect (QPoint (startX, 0),
+ QPoint (startX + (numCols - 1) * dir, maxY)).normalize ();
+ m_referenceColor = col;
+ }
+ }
+ else
+ {
+ int numRows = 0;
+ int startY = (dir > 0) ? 0 : maxY;
+
+ kpColor col = kpPixmapFX::getColorAtPixel (image, 0, startY);
+ for (int y = startY;
+ y >= 0 && y <= maxY;
+ y += dir)
+ {
+ int x;
+ for (x = 0; x <= maxX; x++)
+ {
+ if (!kpPixmapFX::getColorAtPixel (image, x, y).isSimilarTo (col, m_processedColorSimilarity))
+ break;
+ }
+
+ if (x <= maxX)
+ break;
+ else
+ numRows++;
+ }
+
+ if (numRows)
+ {
+ m_rect = QRect (QPoint (0, startY),
+ QPoint (maxX, startY + (numRows - 1) * dir)).normalize ();
+ m_referenceColor = col;
+ }
+ }
+
+
+ if (m_rect.isValid ())
+ {
+ m_isSingleColor = true;
+
+ if (m_referenceColor.isOpaque () && 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 (image, 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 kpToolAutoCropBorder::fillsEntirePixmap () const
+{
+ return (m_rect == m_pixmapPtr->rect ());
+}
+
+// public
+bool kpToolAutoCropBorder::exists () const
+{
+ // (will use in an addition so make sure returns 1 or 0)
+ return (m_rect.isValid () ? 1 : 0);
+}
+
+// public
+void kpToolAutoCropBorder::invalidate ()
+{
+ m_rect = QRect ();
+ m_referenceColor = kpColor::invalid;
+ m_redSum = m_greenSum = m_blueSum = 0;
+ m_isSingleColor = false;
+}
+
+
+class kpSetOverrideCursorSaver
+{
+public:
+ kpSetOverrideCursorSaver (const QCursor &cursor)
+ {
+ QApplication::setOverrideCursor (cursor);
+ }
+
+ ~kpSetOverrideCursorSaver ()
+ {
+ QApplication::restoreOverrideCursor ();
+ }
+};
+
+
+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."),
+ i18n ("Cannot Remove Internal Border"),
+ "NothingToAutoCrop");
+ }
+ else
+ {
+ KMessageBox::information (mainWindow,
+ i18n ("KolourPaint cannot automatically crop the image as its"
+ " border could not be located."),
+ i18n ("Cannot Autocrop"),
+ "NothingToAutoCrop");
+ }
+}
+
+bool kpToolAutoCrop (kpMainWindow *mainWindow)
+{
+#if DEBUG_KP_TOOL_AUTO_CROP
+ kdDebug () << "kpToolAutoCrop() CALLED!" << endl;
+#endif
+
+ if (!mainWindow)
+ {
+ kdError () << "kpToolAutoCrop() passed NULL mainWindow" << endl;
+ return false;
+ }
+
+ kpDocument *doc = mainWindow->document ();
+ if (!doc)
+ {
+ kdError () << "kpToolAutoCrop() passed NULL document" << endl;
+ return false;
+ }
+
+ // OPT: if already pulled selection pixmap, no need to do it again here
+ QPixmap pixmap = doc->selection () ? doc->getSelectedPixmap () : *doc->pixmap ();
+ if (pixmap.isNull ())
+ {
+ kdError () << "kptoolAutoCrop() pased NULL pixmap" << endl;
+ return false;
+ }
+
+ kpViewManager *vm = mainWindow->viewManager ();
+ if (!vm)
+ {
+ kdError () << "kpToolAutoCrop() passed NULL vm" << endl;
+ return false;
+ }
+
+ int processedColorSimilarity = mainWindow->colorToolBar ()->processedColorSimilarity ();
+ kpToolAutoCropBorder leftBorder (&pixmap, processedColorSimilarity),
+ rightBorder (&pixmap, processedColorSimilarity),
+ topBorder (&pixmap, processedColorSimilarity),
+ botBorder (&pixmap, processedColorSimilarity);
+
+
+ kpSetOverrideCursorSaver cursorSaver (Qt::waitCursor);
+
+ // 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.fillsEntirePixmap () ||
+ !rightBorder.calculate (true/*x*/, -1/*going left*/) ||
+ rightBorder.fillsEntirePixmap () ||
+ !topBorder.calculate (false/*y*/, +1/*going down*/) ||
+ topBorder.fillsEntirePixmap () ||
+ !botBorder.calculate (false/*y*/, -1/*going up*/) ||
+ botBorder.fillsEntirePixmap () ||
+ ((numRegions = leftBorder.exists () +
+ rightBorder.exists () +
+ topBorder.exists () +
+ botBorder.exists ()) == 0))
+ {
+ #if DEBUG_KP_TOOL_AUTO_CROP
+ kdDebug () << "\tcan't find border; leftBorder.rect=" << leftBorder.rect ()
+ << " rightBorder.rect=" << rightBorder.rect ()
+ << " topBorder.rect=" << topBorder.rect ()
+ << " botBorder.rect=" << botBorder.rect ()
+ << endl;
+ #endif
+ ::showNothingToAutocropMessage (mainWindow, (bool) doc->selection ());
+ return false;
+ }
+
+#if DEBUG_KP_TOOL_AUTO_CROP
+ kdDebug () << "\tnumRegions=" << numRegions << endl;
+ kdDebug () << "\t\tleft=" << leftBorder.rect ()
+ << " refCol=" << (leftBorder.exists () ? (int *) leftBorder.referenceColor ().toQRgb () : 0)
+ << " avgCol=" << (leftBorder.exists () ? (int *) leftBorder.averageColor ().toQRgb () : 0)
+ << endl;
+ kdDebug () << "\t\tright=" << rightBorder.rect ()
+ << " refCol=" << (rightBorder.exists () ? (int *) rightBorder.referenceColor ().toQRgb () : 0)
+ << " avgCol=" << (rightBorder.exists () ? (int *) rightBorder.averageColor ().toQRgb () : 0)
+ << endl;
+ kdDebug () << "\t\ttop=" << topBorder.rect ()
+ << " refCol=" << (topBorder.exists () ? (int *) topBorder.referenceColor ().toQRgb () : 0)
+ << " avgCol=" << (topBorder.exists () ? (int *) topBorder.averageColor ().toQRgb () : 0)
+ << endl;
+ kdDebug () << "\t\tbot=" << botBorder.rect ()
+ << " refCol=" << (botBorder.exists () ? (int *) botBorder.referenceColor ().toQRgb () : 0)
+ << " avgCol=" << (botBorder.exists () ? (int *) botBorder.averageColor ().toQRgb () : 0)
+ << endl;
+#endif
+
+
+ // In case e.g. the user pastes a solid, coloured-in rectangle,
+ // we favour 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
+ {
+ #if DEBUG_KP_TOOL_AUTO_CROP
+ kdDebug () << "\tignoring left border" << endl;
+ #endif
+ 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
+ {
+ #if DEBUG_KP_TOOL_AUTO_CROP
+ kdDebug () << "\tignoring top border" << endl;
+ #endif
+ topBorder.invalidate ();
+ }
+ }
+
+
+ mainWindow->addImageOrSelectionCommand (
+ new kpToolAutoCropCommand (
+ (bool) doc->selection (),
+ leftBorder, rightBorder,
+ topBorder, botBorder,
+ mainWindow));
+
+
+ return true;
+}
+
+
+kpToolAutoCropCommand::kpToolAutoCropCommand (bool actOnSelection,
+ const kpToolAutoCropBorder &leftBorder,
+ const kpToolAutoCropBorder &rightBorder,
+ const kpToolAutoCropBorder &topBorder,
+ const kpToolAutoCropBorder &botBorder,
+ kpMainWindow *mainWindow)
+ : kpNamedCommand (name (actOnSelection, DontShowAccel), mainWindow),
+ m_actOnSelection (actOnSelection),
+ m_leftBorder (leftBorder),
+ m_rightBorder (rightBorder),
+ m_topBorder (topBorder),
+ m_botBorder (botBorder),
+ m_leftPixmap (0),
+ m_rightPixmap (0),
+ m_topPixmap (0),
+ m_botPixmap (0)
+{
+ kpDocument *doc = document ();
+ if (!doc)
+ {
+ kdError () << "kpToolAutoCropCommand::<ctor>() without doc" << endl;
+ m_oldWidth = 0;
+ m_oldHeight = 0;
+ return;
+ }
+
+ m_oldWidth = doc->width (m_actOnSelection);
+ m_oldHeight = doc->height (m_actOnSelection);
+}
+
+kpToolAutoCropCommand::~kpToolAutoCropCommand ()
+{
+ deleteUndoPixmaps ();
+}
+
+
+// public static
+QString kpToolAutoCropCommand::name (bool actOnSelection, int options)
+{
+ if (actOnSelection)
+ {
+ if (options & ShowAccel)
+ return i18n ("Remove Internal B&order");
+ else
+ return i18n ("Remove Internal Border");
+ }
+ else
+ {
+ if (options & ShowAccel)
+ return i18n ("Autocr&op");
+ else
+ return i18n ("Autocrop");
+ }
+}
+
+
+// public virtual [base kpCommand]
+int kpToolAutoCropCommand::size () const
+{
+ return m_leftBorder.size () +
+ m_rightBorder.size () +
+ m_topBorder.size () +
+ m_botBorder.size () +
+ kpPixmapFX::pixmapSize (m_leftPixmap) +
+ kpPixmapFX::pixmapSize (m_rightPixmap) +
+ kpPixmapFX::pixmapSize (m_topPixmap) +
+ kpPixmapFX::pixmapSize (m_botPixmap) +
+ m_oldSelection.size ();
+}
+
+
+// private
+void kpToolAutoCropCommand::getUndoPixmap (const kpToolAutoCropBorder &border, QPixmap **pixmap)
+{
+ kpDocument *doc = document ();
+
+#if DEBUG_KP_TOOL_AUTO_CROP && 1
+ kdDebug () << "kpToolAutoCropCommand::getUndoPixmap()" << endl;
+ kdDebug () << "\tpixmap=" << pixmap
+ << " border: rect=" << border.rect ()
+ << " isSingleColor=" << border.isSingleColor ()
+ << endl;
+#endif
+
+ if (!doc)
+ return;
+
+ if (pixmap && border.exists () && !border.isSingleColor ())
+ {
+ if (*pixmap)
+ {
+ #if DEBUG_KP_TOOL_AUTO_CROP && 1
+ kdDebug () << "\talready have *pixmap - delete it" << endl;
+ #endif
+ delete *pixmap;
+ }
+
+ *pixmap = new QPixmap (
+ kpPixmapFX::getPixmapAt (*doc->pixmap (m_actOnSelection),
+ border.rect ()));
+ }
+}
+
+
+// private
+void kpToolAutoCropCommand::getUndoPixmaps ()
+{
+ getUndoPixmap (m_leftBorder, &m_leftPixmap);
+ getUndoPixmap (m_rightBorder, &m_rightPixmap);
+ getUndoPixmap (m_topBorder, &m_topPixmap);
+ getUndoPixmap (m_botBorder, &m_botPixmap);
+}
+
+// private
+void kpToolAutoCropCommand::deleteUndoPixmaps ()
+{
+#if DEBUG_KP_TOOL_AUTO_CROP && 1
+ kdDebug () << "kpToolAutoCropCommand::deleteUndoPixmaps()" << endl;
+#endif
+
+ delete m_leftPixmap; m_leftPixmap = 0;
+ delete m_rightPixmap; m_rightPixmap = 0;
+ delete m_topPixmap; m_topPixmap = 0;
+ delete m_botPixmap; m_botPixmap = 0;
+}
+
+
+// public virtual [base kpCommand]
+void kpToolAutoCropCommand::execute ()
+{
+ if (!m_contentsRect.isValid ())
+ m_contentsRect = contentsRect ();
+
+
+ getUndoPixmaps ();
+
+
+ kpDocument *doc = document ();
+ if (!doc)
+ return;
+
+
+ QPixmap pixmapWithoutBorder =
+ kpTool::neededPixmap (*doc->pixmap (m_actOnSelection),
+ m_contentsRect);
+
+
+ if (!m_actOnSelection)
+ doc->setPixmap (pixmapWithoutBorder);
+ else
+ {
+ m_oldSelection = *doc->selection ();
+ m_oldSelection.setPixmap (QPixmap ());
+
+ // m_contentsRect is relative to the top of the sel
+ // while sel is relative to the top of the doc
+ QRect rect = m_contentsRect;
+ rect.moveBy (m_oldSelection.x (), m_oldSelection.y ());
+
+ kpSelection sel (kpSelection::Rectangle,
+ rect,
+ pixmapWithoutBorder,
+ m_oldSelection.transparency ());
+
+ doc->setSelection (sel);
+
+ if (m_mainWindow->tool ())
+ m_mainWindow->tool ()->somethingBelowTheCursorChanged ();
+ }
+}
+
+// public virtual [base kpCommand]
+void kpToolAutoCropCommand::unexecute ()
+{
+#if DEBUG_KP_TOOL_AUTO_CROP && 1
+ kdDebug () << "kpToolAutoCropCommand::unexecute()" << endl;
+#endif
+
+ kpDocument *doc = document ();
+ if (!doc)
+ return;
+
+ QPixmap pixmap (m_oldWidth, m_oldHeight);
+ QBitmap maskBitmap;
+
+ // restore the position of the centre image
+ kpPixmapFX::setPixmapAt (&pixmap, m_contentsRect,
+ *doc->pixmap (m_actOnSelection));
+
+ // draw the borders
+
+ QPainter painter (&pixmap);
+ QPainter maskPainter;
+
+ const kpToolAutoCropBorder *borders [] =
+ {
+ &m_leftBorder, &m_rightBorder,
+ &m_topBorder, &m_botBorder,
+ 0
+ };
+
+ const QPixmap *pixmaps [] =
+ {
+ m_leftPixmap, m_rightPixmap,
+ m_topPixmap, m_botPixmap,
+ 0
+ };
+
+ const QPixmap **p = pixmaps;
+ for (const kpToolAutoCropBorder **b = borders; *b; b++, p++)
+ {
+ if (!(*b)->exists ())
+ continue;
+
+ if ((*b)->isSingleColor ())
+ {
+ kpColor col = (*b)->referenceColor ();
+ #if DEBUG_KP_TOOL_AUTO_CROP && 1
+ kdDebug () << "\tdrawing border " << (*b)->rect ()
+ << " rgb=" << (int *) col.toQRgb () /* %X hack */ << endl;
+ #endif
+
+ if (col.isOpaque ())
+ {
+ painter.fillRect ((*b)->rect (), col.toQColor ());
+ }
+ else
+ {
+ if (maskBitmap.isNull ())
+ {
+ // TODO: dangerous when a painter is active on pixmap?
+ maskBitmap = kpPixmapFX::getNonNullMask (pixmap);
+ maskPainter.begin (&maskBitmap);
+ }
+
+ maskPainter.fillRect ((*b)->rect (), Qt::color0/*transparent*/);
+ }
+ }
+ else
+ {
+ #if DEBUG_KP_TOOL_AUTO_CROP && 1
+ kdDebug () << "\trestoring border pixmap " << (*b)->rect () << endl;
+ #endif
+ // **p cannot contain a single transparent pixel because
+ // if it did, all other pixels must be transparent (only
+ // transparent pixels are similar to transparent pixels)
+ // and the other branch would execute.
+ if (*p)
+ {
+ // TODO: We should really edit the mask here. Due to good
+ // luck (if "maskBitmap" is initialized above, this region
+ // will be marked as opaque in the mask; if it's not
+ // initialized, we will be opaque by default), we
+ // don't actually have to edit the mask but this is
+ // highly error-prone.
+ painter.drawPixmap ((*b)->rect (), **p);
+ }
+ }
+ }
+
+ if (maskPainter.isActive ())
+ maskPainter.end ();
+
+ painter.end ();
+
+ if (!maskBitmap.isNull ())
+ pixmap.setMask (maskBitmap);
+
+
+ if (!m_actOnSelection)
+ doc->setPixmap (pixmap);
+ else
+ {
+ kpSelection sel = m_oldSelection;
+ sel.setPixmap (pixmap);
+
+ doc->setSelection (sel);
+
+ if (m_mainWindow->tool ())
+ m_mainWindow->tool ()->somethingBelowTheCursorChanged ();
+ }
+
+
+ deleteUndoPixmaps ();
+}
+
+
+// private
+QRect kpToolAutoCropCommand::contentsRect () const
+{
+ const QPixmap *pixmap = document ()->pixmap (m_actOnSelection);
+
+ QPoint topLeft (m_leftBorder.exists () ?
+ m_leftBorder.rect ().right () + 1 :
+ 0,
+ m_topBorder.exists () ?
+ m_topBorder.rect ().bottom () + 1 :
+ 0);
+ QPoint botRight (m_rightBorder.exists () ?
+ m_rightBorder.rect ().left () - 1 :
+ pixmap->width () - 1,
+ m_botBorder.exists () ?
+ m_botBorder.rect ().top () - 1 :
+ pixmap->height () - 1);
+
+ return QRect (topLeft, botRight);
+}
diff --git a/kolourpaint/tools/kptoolautocrop.h b/kolourpaint/tools/kptoolautocrop.h
new file mode 100644
index 00000000..4d016a1d
--- /dev/null
+++ b/kolourpaint/tools/kptoolautocrop.h
@@ -0,0 +1,127 @@
+
+/*
+ Copyright (c) 2003,2004,2005 Clarence Dang <dang@kde.org>
+ 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 __kptoolautocrop_h__
+#define __kptoolautocrop_h__
+
+#include <qrect.h>
+
+#include <kpcommandhistory.h>
+
+#include <kpcolor.h>
+#include <kpselection.h>
+
+class QPixmap;
+class kpDocument;
+class kpMainWindow;
+class kpViewManager;
+
+
+// (returns true on success (even if it did nothing) or false on error)
+bool kpToolAutoCrop (kpMainWindow *mainWindow);
+
+
+class kpToolAutoCropBorder
+{
+public:
+ kpToolAutoCropBorder (const QPixmap *pixmapPtr, int processedColorSimilarity);
+
+ int size () const;
+
+ const QPixmap *pixmap () 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 fillsEntirePixmap () const;
+ bool exists () const;
+ void invalidate ();
+
+private:
+ const QPixmap *m_pixmapPtr;
+ int m_processedColorSimilarity;
+
+ QRect m_rect;
+ kpColor m_referenceColor;
+ int m_redSum, m_greenSum, m_blueSum;
+ bool m_isSingleColor;
+};
+
+
+class kpToolAutoCropCommand : public kpNamedCommand
+{
+public:
+ kpToolAutoCropCommand (bool actOnSelection,
+ const kpToolAutoCropBorder &leftBorder,
+ const kpToolAutoCropBorder &rightBorder,
+ const kpToolAutoCropBorder &topBorder,
+ const kpToolAutoCropBorder &botBorder,
+ kpMainWindow *mainWindow);
+ virtual ~kpToolAutoCropCommand ();
+
+ enum NameOptions
+ {
+ DontShowAccel = 0,
+ ShowAccel = 1
+ };
+
+ static QString name (bool actOnSelection, int options);
+
+ virtual int size () const;
+
+private:
+ void getUndoPixmap (const kpToolAutoCropBorder &border, QPixmap **pixmap);
+ void getUndoPixmaps ();
+ void deleteUndoPixmaps ();
+
+public:
+ virtual void execute ();
+ virtual void unexecute ();
+
+private:
+ QRect contentsRect () const;
+
+ bool m_actOnSelection;
+ kpToolAutoCropBorder m_leftBorder, m_rightBorder, m_topBorder, m_botBorder;
+ QPixmap *m_leftPixmap, *m_rightPixmap, *m_topPixmap, *m_botPixmap;
+
+ QRect m_contentsRect;
+ int m_oldWidth, m_oldHeight;
+ kpSelection m_oldSelection;
+};
+
+#endif // __kptoolautocrop_h__
diff --git a/kolourpaint/tools/kptoolbrush.cpp b/kolourpaint/tools/kptoolbrush.cpp
new file mode 100644
index 00000000..6e684ed9
--- /dev/null
+++ b/kolourpaint/tools/kptoolbrush.cpp
@@ -0,0 +1,45 @@
+
+/*
+ Copyright (c) 2003,2004,2005 Clarence Dang <dang@kde.org>
+ 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 <klocale.h>
+#include <kptoolbrush.h>
+
+kpToolBrush::kpToolBrush (kpMainWindow *mainWindow)
+ : kpToolPen (kpToolPen::Brush,
+ i18n ("Brush"),
+ i18n ("Draw using brushes of different shapes and sizes"),
+ Qt::Key_B,
+ mainWindow, "tool_brush")
+{
+}
+
+kpToolBrush::~kpToolBrush ()
+{
+}
+
+#include <kptoolbrush.moc>
diff --git a/kolourpaint/tools/kptoolbrush.h b/kolourpaint/tools/kptoolbrush.h
new file mode 100644
index 00000000..69498495
--- /dev/null
+++ b/kolourpaint/tools/kptoolbrush.h
@@ -0,0 +1,43 @@
+
+/*
+ Copyright (c) 2003,2004,2005 Clarence Dang <dang@kde.org>
+ 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 __kptoolbrush_h__
+#define __kptoolbrush_h__
+
+#include <kptoolpen.h>
+
+class kpToolBrush : public kpToolPen
+{
+Q_OBJECT
+
+public:
+ kpToolBrush (kpMainWindow *mainWindow);
+ virtual ~kpToolBrush ();
+};
+
+#endif // __kptoolbrush_h__
diff --git a/kolourpaint/tools/kptoolclear.cpp b/kolourpaint/tools/kptoolclear.cpp
new file mode 100644
index 00000000..230e54a3
--- /dev/null
+++ b/kolourpaint/tools/kptoolclear.cpp
@@ -0,0 +1,135 @@
+
+/*
+ Copyright (c) 2003,2004,2005 Clarence Dang <dang@kde.org>
+ 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 <kptoolclear.h>
+
+#include <qpixmap.h>
+
+#include <kdebug.h>
+#include <klocale.h>
+
+#include <kpdefs.h>
+#include <kpdocument.h>
+#include <kpmainwindow.h>
+#include <kppixmapfx.h>
+#include <kpselection.h>
+
+
+kpToolClearCommand::kpToolClearCommand (bool actOnSelection,
+ const kpColor &newColor,
+ kpMainWindow *mainWindow)
+ : kpCommand (mainWindow),
+ m_actOnSelection (actOnSelection),
+ m_newColor (newColor),
+ m_oldPixmapPtr (0)
+{
+}
+
+kpToolClearCommand::kpToolClearCommand (bool actOnSelection,
+ kpMainWindow *mainWindow)
+ : kpCommand (mainWindow),
+ m_actOnSelection (actOnSelection),
+ m_newColor (mainWindow ? mainWindow->backgroundColor () : kpColor::invalid),
+ m_oldPixmapPtr (0)
+{
+}
+
+kpToolClearCommand::~kpToolClearCommand ()
+{
+ delete m_oldPixmapPtr;
+}
+
+
+// public virtual [base kpCommand]
+QString kpToolClearCommand::name () const
+{
+ QString opName = i18n ("Clear");
+
+ if (m_actOnSelection)
+ return i18n ("Selection: %1").arg (opName);
+ else
+ return opName;
+}
+
+
+// public virtual [base kpCommand]
+int kpToolClearCommand::size () const
+{
+ return kpPixmapFX::pixmapSize (m_oldPixmapPtr);
+}
+
+
+// public virtual [base kpCommand]
+void kpToolClearCommand::execute ()
+{
+ kpDocument *doc = document ();
+ if (!doc)
+ {
+ kdError () << "kpToolClearCommand::execute() without doc" << endl;
+ return;
+ }
+
+
+ m_oldPixmapPtr = new QPixmap ();
+ *m_oldPixmapPtr = *doc->pixmap (m_actOnSelection);
+
+
+ if (m_actOnSelection)
+ {
+ // OPT: could just edit pixmap directly and signal change
+ kpSelection *sel = doc->selection ();
+
+ QPixmap newPixmap (sel->width (), sel->height ());
+ kpPixmapFX::fill (&newPixmap, m_newColor);
+ // TODO: maybe disable Image/Clear if transparent colour
+ if (m_newColor.isOpaque ())
+ newPixmap.setMask (sel->maskForOwnType ());
+
+ sel->setPixmap (newPixmap);
+ }
+ else
+ doc->fill (m_newColor);
+}
+
+// public virtual [base kpCommand]
+void kpToolClearCommand::unexecute ()
+{
+ kpDocument *doc = document ();
+ if (!doc)
+ {
+ kdError () << "kpToolClearCommand::execute() without doc" << endl;
+ return;
+ }
+
+
+ doc->setPixmap (m_actOnSelection, *m_oldPixmapPtr);
+
+
+ delete m_oldPixmapPtr;
+ m_oldPixmapPtr = 0;
+}
diff --git a/kolourpaint/tools/kptoolclear.h b/kolourpaint/tools/kptoolclear.h
new file mode 100644
index 00000000..ccf3697f
--- /dev/null
+++ b/kolourpaint/tools/kptoolclear.h
@@ -0,0 +1,68 @@
+
+/*
+ Copyright (c) 2003,2004,2005 Clarence Dang <dang@kde.org>
+ 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 __kptoolclear_h__
+#define __kptoolclear_h__
+
+#include <kpcommandhistory.h>
+
+#include <kpcolor.h>
+
+class QPixmap;
+class QString;
+
+class kpDocument;
+class kpMainWindow;
+
+
+class kpToolClearCommand : public kpCommand
+{
+public:
+ kpToolClearCommand (bool actOnSelection,
+ const kpColor &newColor,
+ kpMainWindow *mainWindow);
+ kpToolClearCommand (bool actOnSelection,
+ kpMainWindow *mainWindow);
+ virtual ~kpToolClearCommand ();
+
+ virtual QString name () const;
+
+ virtual int size () const;
+
+ virtual void execute ();
+ virtual void unexecute ();
+
+private:
+ bool m_actOnSelection;
+
+ kpColor m_newColor;
+ QPixmap *m_oldPixmapPtr;
+};
+
+
+#endif // __kptoolclear_h__
diff --git a/kolourpaint/tools/kptoolcolorpicker.cpp b/kolourpaint/tools/kptoolcolorpicker.cpp
new file mode 100644
index 00000000..1050b1cf
--- /dev/null
+++ b/kolourpaint/tools/kptoolcolorpicker.cpp
@@ -0,0 +1,197 @@
+
+/*
+ Copyright (c) 2003,2004,2005 Clarence Dang <dang@kde.org>
+ 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 <qimage.h>
+#include <qpixmap.h>
+#include <qpoint.h>
+
+#include <kdebug.h>
+#include <klocale.h>
+
+#include <kpcolortoolbar.h>
+#include <kpcommandhistory.h>
+#include <kpdefs.h>
+#include <kpdocument.h>
+#include <kpmainwindow.h>
+#include <kppixmapfx.h>
+
+
+/*
+ * kpToolColorPicker
+ */
+
+kpToolColorPicker::kpToolColorPicker (kpMainWindow *mainWindow)
+ : kpTool (i18n ("Color Picker"), i18n ("Lets you select a color from the image"),
+ Qt::Key_C,
+ mainWindow, "tool_color_picker")
+{
+}
+
+kpToolColorPicker::~kpToolColorPicker ()
+{
+}
+
+kpColor kpToolColorPicker::colorAtPixel (const QPoint &p)
+{
+#if DEBUG_KP_TOOL_COLOR_PICKER && 0
+ kdDebug () << "kpToolColorPicker::colorAtPixel" << p << endl;
+#endif
+
+ return kpPixmapFX::getColorAtPixel (*document ()->pixmap (), p);
+}
+
+
+QString kpToolColorPicker::haventBegunDrawUserMessage () const
+{
+ return i18n ("Click to select a color.");
+}
+
+void kpToolColorPicker::begin ()
+{
+ setUserMessage (haventBegunDrawUserMessage ());
+}
+
+// virtual
+void kpToolColorPicker::beginDraw ()
+{
+ m_oldColor = color (m_mouseButton);
+
+ setUserMessage (cancelUserMessage ());
+}
+
+// virtual
+void kpToolColorPicker::draw (const QPoint &thisPoint, const QPoint &, const QRect &)
+{
+ const kpColor color = colorAtPixel (thisPoint);
+
+ if (color.isValid ())
+ {
+ mainWindow ()->colorToolBar ()->setColor (m_mouseButton, color);
+ setUserShapePoints (thisPoint);
+ }
+ else
+ {
+ mainWindow ()->colorToolBar ()->setColor (m_mouseButton, m_oldColor);
+ setUserShapePoints ();
+ }
+}
+
+// virtual
+void kpToolColorPicker::cancelShape ()
+{
+ mainWindow ()->colorToolBar ()->setColor (m_mouseButton, m_oldColor);
+
+ setUserMessage (i18n ("Let go of all the mouse buttons."));
+}
+
+void kpToolColorPicker::releasedAllButtons ()
+{
+ setUserMessage (haventBegunDrawUserMessage ());
+
+}
+
+// virtual
+void kpToolColorPicker::endDraw (const QPoint &thisPoint, const QRect &)
+{
+ const kpColor color = colorAtPixel (thisPoint);
+
+ if (color.isValid ())
+ {
+ kpToolColorPickerCommand *cmd = new kpToolColorPickerCommand (
+ m_mouseButton,
+ color, m_oldColor,
+ mainWindow ());
+
+ mainWindow ()->commandHistory ()->addCommand (cmd, false /* no exec */);
+ setUserMessage (haventBegunDrawUserMessage ());
+ }
+ else
+ {
+ cancelShape ();
+ }
+}
+
+/*
+ * kpToolColorPickerCommand
+ */
+
+kpToolColorPickerCommand::kpToolColorPickerCommand (int mouseButton,
+ const kpColor &newColor,
+ const kpColor &oldColor,
+ kpMainWindow *mainWindow)
+ : kpCommand (mainWindow),
+ m_mouseButton (mouseButton),
+ m_newColor (newColor),
+ m_oldColor (oldColor)
+{
+}
+
+kpToolColorPickerCommand::~kpToolColorPickerCommand ()
+{
+}
+
+
+// public virtual [base kpCommand]
+QString kpToolColorPickerCommand::name () const
+{
+ return i18n ("Color Picker");
+}
+
+
+// public virtual [base kpCommand]
+int kpToolColorPickerCommand::size () const
+{
+ return 0;
+}
+
+
+// public virtual [base kpCommand]
+void kpToolColorPickerCommand::execute ()
+{
+ colorToolBar ()->setColor (m_mouseButton, m_newColor);
+}
+
+// public virtual [base kpCommand]
+void kpToolColorPickerCommand::unexecute ()
+{
+ colorToolBar ()->setColor (m_mouseButton, m_oldColor);
+}
+
+
+// private
+kpColorToolBar *kpToolColorPickerCommand::colorToolBar () const
+{
+ return m_mainWindow ? m_mainWindow->colorToolBar () : 0;
+}
+
+#include <kptoolcolorpicker.moc>
diff --git a/kolourpaint/tools/kptoolcolorpicker.h b/kolourpaint/tools/kptoolcolorpicker.h
new file mode 100644
index 00000000..46fc94be
--- /dev/null
+++ b/kolourpaint/tools/kptoolcolorpicker.h
@@ -0,0 +1,95 @@
+
+/*
+ Copyright (c) 2003,2004,2005 Clarence Dang <dang@kde.org>
+ 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 __kptoolcolorpicker_h__
+#define __kptoolcolorpicker_h__
+
+#include <kpcommandhistory.h>
+
+#include <kpcolor.h>
+#include <kptool.h>
+
+class QPoint;
+class QRect;
+
+class kpColorToolBar;
+
+class kpToolColorPicker : public kpTool
+{
+Q_OBJECT
+
+public:
+ kpToolColorPicker (kpMainWindow *);
+ virtual ~kpToolColorPicker ();
+
+ // generally the user goes to pick a color but wants to return to using
+ // his/her previous drawing tool
+ virtual bool returnToPreviousToolAfterEndDraw () const { return true; }
+
+private:
+ QString haventBegunDrawUserMessage () const;
+
+public:
+ virtual void begin ();
+ virtual void beginDraw ();
+ virtual void draw (const QPoint &thisPoint, const QPoint &, const QRect &);
+ virtual void cancelShape ();
+ virtual void releasedAllButtons ();
+ virtual void endDraw (const QPoint &thisPoint, const QRect &);
+
+private:
+ kpColor colorAtPixel (const QPoint &p);
+
+ kpColor m_oldColor;
+};
+
+class kpToolColorPickerCommand : public kpCommand
+{
+public:
+ kpToolColorPickerCommand (int mouseButton,
+ const kpColor &newColor, const kpColor &oldColor,
+ kpMainWindow *mainWindow);
+ virtual ~kpToolColorPickerCommand ();
+
+ virtual QString name () const;
+
+ virtual int size () const;
+
+ virtual void execute ();
+ virtual void unexecute ();
+
+private:
+ kpColorToolBar *colorToolBar () const;
+
+private:
+ int m_mouseButton;
+ kpColor m_newColor;
+ kpColor m_oldColor;
+};
+
+#endif // __kptoolcolorpicker_h__
diff --git a/kolourpaint/tools/kptoolcolorwasher.cpp b/kolourpaint/tools/kptoolcolorwasher.cpp
new file mode 100644
index 00000000..6c2d091f
--- /dev/null
+++ b/kolourpaint/tools/kptoolcolorwasher.cpp
@@ -0,0 +1,45 @@
+
+/*
+ Copyright (c) 2003,2004,2005 Clarence Dang <dang@kde.org>
+ 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 <klocale.h>
+#include <kptoolcolorwasher.h>
+
+kpToolColorWasher::kpToolColorWasher (kpMainWindow *mainWindow)
+ : kpToolPen (kpToolPen::ColorWasher,
+ i18n ("Color Eraser"),
+ i18n ("Replaces pixels of the foreground color with the background color"),
+ Qt::Key_O,
+ mainWindow, "tool_color_washer")
+{
+}
+
+kpToolColorWasher::~kpToolColorWasher ()
+{
+}
+
+#include <kptoolcolorwasher.moc>
diff --git a/kolourpaint/tools/kptoolcolorwasher.h b/kolourpaint/tools/kptoolcolorwasher.h
new file mode 100644
index 00000000..1a707c3e
--- /dev/null
+++ b/kolourpaint/tools/kptoolcolorwasher.h
@@ -0,0 +1,43 @@
+
+/*
+ Copyright (c) 2003,2004,2005 Clarence Dang <dang@kde.org>
+ 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 __kptoolcolorwasher_h__
+#define __kptoolcolorwasher_h__
+
+#include <kptoolpen.h>
+
+class kpToolColorWasher : public kpToolPen
+{
+Q_OBJECT
+
+public:
+ kpToolColorWasher (kpMainWindow *mainWindow);
+ virtual ~kpToolColorWasher ();
+};
+
+#endif // __kptoolcolorwasher_h__
diff --git a/kolourpaint/tools/kptoolconverttograyscale.cpp b/kolourpaint/tools/kptoolconverttograyscale.cpp
new file mode 100644
index 00000000..a80ef8fa
--- /dev/null
+++ b/kolourpaint/tools/kptoolconverttograyscale.cpp
@@ -0,0 +1,106 @@
+
+/*
+ Copyright (c) 2003,2004,2005 Clarence Dang <dang@kde.org>
+ 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 <qapplication.h>
+#include <qpixmap.h>
+
+#include <klocale.h>
+
+#include <kpdefs.h>
+#include <kpdocument.h>
+#include <kpmainwindow.h>
+#include <kppixmapfx.h>
+#include <kpselection.h>
+#include <kptoolconverttograyscale.h>
+
+
+kpToolConvertToGrayscaleCommand::kpToolConvertToGrayscaleCommand (bool actOnSelection,
+ kpMainWindow *mainWindow)
+ : kpCommand (mainWindow),
+ m_actOnSelection (actOnSelection),
+ m_oldPixmapPtr (0)
+{
+}
+
+kpToolConvertToGrayscaleCommand::~kpToolConvertToGrayscaleCommand ()
+{
+ delete m_oldPixmapPtr;
+}
+
+
+// public virtual [base kpCommand]
+QString kpToolConvertToGrayscaleCommand::name () const
+{
+ QString opName = i18n ("Reduce to Grayscale");
+
+ if (m_actOnSelection)
+ return i18n ("Selection: %1").arg (opName);
+ else
+ return opName;
+}
+
+
+// public virtual [base kpCommand]
+int kpToolConvertToGrayscaleCommand::size () const
+{
+ return kpPixmapFX::pixmapSize (m_oldPixmapPtr);
+}
+
+
+// public virtual [base kpCommand]
+void kpToolConvertToGrayscaleCommand::execute ()
+{
+ kpDocument *doc = document ();
+ if (!doc)
+ return;
+
+ QApplication::setOverrideCursor (Qt::waitCursor);
+
+ m_oldPixmapPtr = new QPixmap ();
+ *m_oldPixmapPtr = *doc->pixmap (m_actOnSelection);
+
+ QPixmap newPixmap = kpPixmapFX::convertToGrayscale (*doc->pixmap (m_actOnSelection));
+
+ doc->setPixmap (m_actOnSelection, newPixmap);
+
+ QApplication::restoreOverrideCursor ();
+}
+
+// public virtual [base kpCommand]
+void kpToolConvertToGrayscaleCommand::unexecute ()
+{
+ kpDocument *doc = document ();
+ if (!doc)
+ return;
+
+ doc->setPixmap (m_actOnSelection, *m_oldPixmapPtr);
+
+ delete m_oldPixmapPtr;
+ m_oldPixmapPtr = 0;
+}
+
diff --git a/kolourpaint/tools/kptoolconverttograyscale.h b/kolourpaint/tools/kptoolconverttograyscale.h
new file mode 100644
index 00000000..6ea5e515
--- /dev/null
+++ b/kolourpaint/tools/kptoolconverttograyscale.h
@@ -0,0 +1,57 @@
+
+/*
+ Copyright (c) 2003,2004,2005 Clarence Dang <dang@kde.org>
+ 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 __kptoolconverttograyscale_h__
+#define __kptoolconverttograyscale_h__
+
+#include <kpcommandhistory.h>
+
+class QPixmap;
+class QString;
+
+class kpMainWindow;
+
+class kpToolConvertToGrayscaleCommand : public kpCommand
+{
+public:
+ kpToolConvertToGrayscaleCommand (bool actOnSelection,
+ kpMainWindow *mainWindow);
+ virtual ~kpToolConvertToGrayscaleCommand ();
+
+ virtual QString name () const;
+ virtual int size () const;
+
+ virtual void execute ();
+ virtual void unexecute ();
+
+private:
+ bool m_actOnSelection;
+ QPixmap *m_oldPixmapPtr;
+};
+
+#endif // __kptoolconverttograyscale_h__
diff --git a/kolourpaint/tools/kptoolcrop.cpp b/kolourpaint/tools/kptoolcrop.cpp
new file mode 100644
index 00000000..8cc6e880
--- /dev/null
+++ b/kolourpaint/tools/kptoolcrop.cpp
@@ -0,0 +1,335 @@
+
+/*
+ Copyright (c) 2003,2004,2005 Clarence Dang <dang@kde.org>
+ 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 <kptoolcrop.h>
+
+#include <qpixmap.h>
+
+#include <kdebug.h>
+#include <klocale.h>
+
+#include <kpcolor.h>
+#include <kpcommandhistory.h>
+#include <kpdocument.h>
+#include <kpmainwindow.h>
+#include <kpselection.h>
+#include <kptoolclear.h>
+#include <kptoolresizescale.h>
+#include <kptoolselection.h>
+#include <kpviewmanager.h>
+
+
+kpSelection selectionBorderAndMovedTo0_0 (const kpSelection &sel)
+{
+ kpSelection borderSel = sel;
+
+ borderSel.setPixmap (QPixmap ()); // only interested in border
+ borderSel.moveTo (QPoint (0, 0));
+
+ return borderSel;
+}
+
+
+//
+// kpToolCropSetImageCommand
+//
+
+class kpToolCropSetImageCommand : public kpCommand
+{
+public:
+ kpToolCropSetImageCommand (kpMainWindow *mainWindow);
+ virtual ~kpToolCropSetImageCommand ();
+
+ /* (uninteresting child of macro cmd) */
+ virtual QString name () const { return QString::null; }
+
+ virtual int size () const
+ {
+ return kpPixmapFX::pixmapSize (m_oldPixmap) +
+ kpPixmapFX::selectionSize (m_fromSelection) +
+ kpPixmapFX::pixmapSize (m_pixmapIfFromSelectionDoesntHaveOne);
+ }
+
+ virtual void execute ();
+ virtual void unexecute ();
+
+protected:
+ kpColor m_backgroundColor;
+ QPixmap m_oldPixmap;
+ kpSelection m_fromSelection;
+ QPixmap m_pixmapIfFromSelectionDoesntHaveOne;
+};
+
+
+kpToolCropSetImageCommand::kpToolCropSetImageCommand (kpMainWindow *mainWindow)
+ : kpCommand (mainWindow),
+ m_backgroundColor (mainWindow ? mainWindow->backgroundColor () : kpColor::invalid),
+ m_fromSelection (*mainWindow->document ()->selection ()),
+ m_pixmapIfFromSelectionDoesntHaveOne (
+ m_fromSelection.pixmap () ?
+ QPixmap () :
+ mainWindow->document ()->getSelectedPixmap ())
+{
+}
+
+kpToolCropSetImageCommand::~kpToolCropSetImageCommand ()
+{
+}
+
+
+// public virtual [base kpCommand]
+void kpToolCropSetImageCommand::execute ()
+{
+#if DEBUG_KP_TOOL_CROP
+ kdDebug () << "kpToolCropSetImageCommand::execute()" << endl;
+#endif
+
+ viewManager ()->setQueueUpdates ();
+ {
+ m_oldPixmap = kpPixmapFX::getPixmapAt (*document ()->pixmap (),
+ QRect (0, 0, m_fromSelection.width (), m_fromSelection.height ()));
+
+
+ //
+ // 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.
+ //
+
+ QPixmap newDocPixmap (m_fromSelection.width (), m_fromSelection.height ());
+ kpPixmapFX::fill (&newDocPixmap, m_backgroundColor);
+
+ #if DEBUG_KP_TOOL_CROP
+ kdDebug () << "\tsel: rect=" << m_fromSelection.boundingRect ()
+ << " pm=" << m_fromSelection.pixmap ()
+ << endl;
+ #endif
+ QPixmap selTransparentPixmap;
+
+ if (m_fromSelection.pixmap ())
+ {
+ selTransparentPixmap = m_fromSelection.transparentPixmap ();
+ #if DEBUG_KP_TOOL_CROP
+ kdDebug () << "\thave pixmap; rect="
+ << selTransparentPixmap.rect ()
+ << endl;
+ #endif
+ }
+ else
+ {
+ selTransparentPixmap = m_pixmapIfFromSelectionDoesntHaveOne;
+ #if DEBUG_KP_TOOL_CROP
+ kdDebug () << "\tno pixmap in sel - get it; rect="
+ << selTransparentPixmap.rect ()
+ << endl;
+ #endif
+ }
+
+ kpPixmapFX::paintMaskTransparentWithBrush (&newDocPixmap,
+ QPoint (0, 0),
+ m_fromSelection.maskForOwnType ());
+
+ kpPixmapFX::paintPixmapAt (&newDocPixmap,
+ QPoint (0, 0),
+ selTransparentPixmap);
+
+
+ document ()->setPixmapAt (newDocPixmap, QPoint (0, 0));
+ document ()->selectionDelete ();
+
+
+ if (mainWindow ()->tool ())
+ m_mainWindow->tool ()->somethingBelowTheCursorChanged ();
+ }
+ viewManager ()->restoreQueueUpdates ();
+}
+
+// public virtual [base kpCommand]
+void kpToolCropSetImageCommand::unexecute ()
+{
+#if DEBUG_KP_TOOL_CROP
+ kdDebug () << "kpToolCropSetImageCommand::unexecute()" << endl;
+#endif
+
+ viewManager ()->setQueueUpdates ();
+ {
+ document ()->setPixmapAt (m_oldPixmap, QPoint (0, 0));
+ m_oldPixmap.resize (0, 0);
+
+ #if DEBUG_KP_TOOL_CROP
+ kdDebug () << "\tsel: rect=" << m_fromSelection.boundingRect ()
+ << " pm=" << m_fromSelection.pixmap ()
+ << endl;
+ #endif
+ document ()->setSelection (m_fromSelection);
+
+ if (mainWindow ()->tool ())
+ m_mainWindow->tool ()->somethingBelowTheCursorChanged ();
+ }
+ viewManager ()->restoreQueueUpdates ();
+}
+
+
+//
+// kpToolCropCommand
+//
+
+
+class kpToolCropCommand : public kpMacroCommand
+{
+public:
+ kpToolCropCommand (kpMainWindow *mainWindow);
+ virtual ~kpToolCropCommand ();
+};
+
+
+kpToolCropCommand::kpToolCropCommand (kpMainWindow *mainWindow)
+ : kpMacroCommand (i18n ("Set as Image"), mainWindow)
+{
+#if DEBUG_KP_TOOL_CROP
+ kdDebug () << "kpToolCropCommand::<ctor>()" << endl;
+#endif
+
+ if (!mainWindow ||
+ !mainWindow->document () ||
+ !mainWindow->document ()->selection ())
+ {
+ kdError () << "kpToolCropCommand::kpToolCropCommand() without sel" << endl;
+ return;
+ }
+
+ kpSelection *sel = mainWindow->document ()->selection ();
+
+
+#if DEBUG_KP_TOOL_CROP
+ kdDebug () << "\tsel: w=" << sel->width ()
+ << " h=" << sel->height ()
+ << " <- resizing doc to these dimen" << endl;
+#endif
+
+ // (must resize doc _before_ kpToolCropSetImageCommand in case doc
+ // needs to gets bigger - else pasted down pixmap may not fit)
+ addCommand (
+ new kpToolResizeScaleCommand (
+ false/*act on doc, not sel*/,
+ sel->width (), sel->height (),
+ kpToolResizeScaleCommand::Resize,
+ mainWindow));
+
+
+ if (sel->isText ())
+ {
+ #if DEBUG_KP_TOOL_CROP
+ kdDebug () << "\tisText" << endl;
+ kdDebug () << "\tclearing doc with trans cmd" << endl;
+ #endif
+ addCommand (
+ new kpToolClearCommand (
+ false/*act on doc*/,
+ kpColor::transparent,
+ mainWindow));
+
+ #if DEBUG_KP_TOOL_CROP
+ kdDebug () << "\tmoving sel to (0,0) cmd" << endl;
+ #endif
+ kpToolSelectionMoveCommand *moveCmd =
+ new kpToolSelectionMoveCommand (
+ QString::null/*uninteresting child of macro cmd*/,
+ mainWindow);
+ moveCmd->moveTo (QPoint (0, 0), true/*move on exec, not now*/);
+ moveCmd->finalize ();
+ addCommand (moveCmd);
+ }
+ else
+ {
+ #if DEBUG_KP_TOOL_CROP
+ kdDebug () << "\tis pixmap sel" << endl;
+ kdDebug () << "\tcreating SetImage cmd" << endl;
+ #endif
+ addCommand (new kpToolCropSetImageCommand (mainWindow));
+
+ #if 0
+ addCommand (
+ new kpToolSelectionCreateCommand (
+ QString::null/*uninteresting child of macro cmd*/,
+ selectionBorderAndMovedTo0_0 (*sel),
+ mainWindow));
+ #endif
+ }
+}
+
+kpToolCropCommand::~kpToolCropCommand ()
+{
+}
+
+
+void kpToolCrop (kpMainWindow *mainWindow)
+{
+ kpDocument *doc = mainWindow->document ();
+ if (!doc)
+ return;
+
+ kpSelection *sel = doc ? doc->selection () : 0;
+ if (!sel)
+ return;
+
+
+ bool selWasText = sel->isText ();
+ kpSelection borderSel = selectionBorderAndMovedTo0_0 (*sel);
+
+
+ mainWindow->addImageOrSelectionCommand (
+ new kpToolCropCommand (mainWindow),
+ true/*add create cmd*/,
+ false/*don't add pull cmd*/);
+
+
+ if (!selWasText)
+ {
+ mainWindow->commandHistory ()->addCommand (
+ new kpToolSelectionCreateCommand (
+ i18n ("Selection: Create"),
+ borderSel,
+ mainWindow));
+ }
+}
diff --git a/kolourpaint/tools/kptoolcrop.h b/kolourpaint/tools/kptoolcrop.h
new file mode 100644
index 00000000..c710a041
--- /dev/null
+++ b/kolourpaint/tools/kptoolcrop.h
@@ -0,0 +1,39 @@
+
+/*
+ Copyright (c) 2003,2004,2005 Clarence Dang <dang@kde.org>
+ 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_CROP_H
+#define KP_TOOL_CROP_H
+
+
+class kpMainWindow;
+
+
+void kpToolCrop (kpMainWindow *mainWindow);
+
+
+#endif // KP_TOOL_CROP_H
diff --git a/kolourpaint/tools/kptoolcurve.cpp b/kolourpaint/tools/kptoolcurve.cpp
new file mode 100644
index 00000000..f889c1ba
--- /dev/null
+++ b/kolourpaint/tools/kptoolcurve.cpp
@@ -0,0 +1,47 @@
+
+/*
+ Copyright (c) 2003,2004,2005 Clarence Dang <dang@kde.org>
+ 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 <kptoolcurve.h>
+
+#include <klocale.h>
+
+
+kpToolCurve::kpToolCurve (kpMainWindow *mainWindow)
+ : kpToolPolygon (Curve,
+ i18n ("Curve"),
+ i18n ("Draws curves"),
+ Qt::Key_V,
+ mainWindow, "tool_curve")
+{
+}
+
+kpToolCurve::~kpToolCurve ()
+{
+}
+
+#include <kptoolcurve.moc>
diff --git a/kolourpaint/tools/kptoolcurve.h b/kolourpaint/tools/kptoolcurve.h
new file mode 100644
index 00000000..489ce1fb
--- /dev/null
+++ b/kolourpaint/tools/kptoolcurve.h
@@ -0,0 +1,45 @@
+
+/*
+ Copyright (c) 2003,2004,2005 Clarence Dang <dang@kde.org>
+ 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 __kptoolcurve_h__
+#define __kptoolcurve_h__
+
+#include <kptoolpolygon.h>
+
+class kpMainWindow;
+
+class kpToolCurve : public kpToolPolygon
+{
+Q_OBJECT
+
+public:
+ kpToolCurve (kpMainWindow *mainWindow);
+ virtual ~kpToolCurve ();
+};
+
+#endif // __kptoolcurve_h__
diff --git a/kolourpaint/tools/kptoolellipse.cpp b/kolourpaint/tools/kptoolellipse.cpp
new file mode 100644
index 00000000..f3b31dbb
--- /dev/null
+++ b/kolourpaint/tools/kptoolellipse.cpp
@@ -0,0 +1,45 @@
+
+/*
+ Copyright (c) 2003,2004,2005 Clarence Dang <dang@kde.org>
+ 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 <klocale.h>
+#include <kptoolellipse.h>
+
+kpToolEllipse::kpToolEllipse (kpMainWindow *mainWindow)
+ : kpToolRectangle (Ellipse,
+ i18n ("Ellipse"),
+ i18n ("Draws ellipses and circles"),
+ Qt::Key_E,
+ mainWindow, "tool_ellipse")
+{
+}
+
+kpToolEllipse::~kpToolEllipse ()
+{
+}
+
+#include <kptoolellipse.moc>
diff --git a/kolourpaint/tools/kptoolellipse.h b/kolourpaint/tools/kptoolellipse.h
new file mode 100644
index 00000000..fc9bf798
--- /dev/null
+++ b/kolourpaint/tools/kptoolellipse.h
@@ -0,0 +1,45 @@
+
+/*
+ Copyright (c) 2003,2004,2005 Clarence Dang <dang@kde.org>
+ 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 __kptoolellipse_h__
+#define __kptoolellipse_h__
+
+#include <kptoolrectangle.h>
+
+class kpMainWindow;
+
+class kpToolEllipse : public kpToolRectangle
+{
+Q_OBJECT
+
+public:
+ kpToolEllipse (kpMainWindow *);
+ virtual ~kpToolEllipse ();
+};
+
+#endif // __kptoolellipse_h__
diff --git a/kolourpaint/tools/kptoolellipticalselection.cpp b/kolourpaint/tools/kptoolellipticalselection.cpp
new file mode 100644
index 00000000..13daf799
--- /dev/null
+++ b/kolourpaint/tools/kptoolellipticalselection.cpp
@@ -0,0 +1,46 @@
+
+/*
+ Copyright (c) 2003,2004,2005 Clarence Dang <dang@kde.org>
+ 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 <kptoolellipticalselection.h>
+
+#include <klocale.h>
+
+
+kpToolEllipticalSelection::kpToolEllipticalSelection (kpMainWindow *mainWindow)
+ : kpToolSelection (Ellipse,
+ i18n ("Selection (Elliptical)"),
+ i18n ("Makes an elliptical or circular selection"),
+ Qt::Key_I,
+ mainWindow, "tool_elliptical_selection")
+{
+}
+
+kpToolEllipticalSelection::~kpToolEllipticalSelection ()
+{
+}
+
diff --git a/kolourpaint/tools/kptoolellipticalselection.h b/kolourpaint/tools/kptoolellipticalselection.h
new file mode 100644
index 00000000..9dbd643e
--- /dev/null
+++ b/kolourpaint/tools/kptoolellipticalselection.h
@@ -0,0 +1,43 @@
+
+/*
+ Copyright (c) 2003,2004,2005 Clarence Dang <dang@kde.org>
+ 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 __kptoolellipticalselection_h__
+#define __kptoolellipticalselection_h__
+
+#include <kptoolselection.h>
+
+class kpMainWindow;
+
+class kpToolEllipticalSelection : public kpToolSelection
+{
+public:
+ kpToolEllipticalSelection (kpMainWindow *);
+ virtual ~kpToolEllipticalSelection ();
+};
+
+#endif // __kptoolellipticalselection_h__
diff --git a/kolourpaint/tools/kptooleraser.cpp b/kolourpaint/tools/kptooleraser.cpp
new file mode 100644
index 00000000..1acbf66e
--- /dev/null
+++ b/kolourpaint/tools/kptooleraser.cpp
@@ -0,0 +1,44 @@
+
+/*
+ Copyright (c) 2003,2004,2005 Clarence Dang <dang@kde.org>
+ 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 <klocale.h>
+#include <kptooleraser.h>
+
+kpToolEraser::kpToolEraser (kpMainWindow *mainWindow)
+ : kpToolPen (kpToolPen::Eraser,
+ i18n ("Eraser"), i18n ("Lets you rub out mistakes"),
+ Qt::Key_A,
+ mainWindow, "tool_eraser")
+{
+}
+
+kpToolEraser::~kpToolEraser ()
+{
+}
+
+#include <kptooleraser.moc>
diff --git a/kolourpaint/tools/kptooleraser.h b/kolourpaint/tools/kptooleraser.h
new file mode 100644
index 00000000..4dd7704a
--- /dev/null
+++ b/kolourpaint/tools/kptooleraser.h
@@ -0,0 +1,43 @@
+
+/*
+ Copyright (c) 2003,2004,2005 Clarence Dang <dang@kde.org>
+ 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 __kptooleraser_h__
+#define __kptooleraser_h__
+
+#include <kptoolpen.h>
+
+class kpToolEraser : public kpToolPen
+{
+Q_OBJECT
+
+public:
+ kpToolEraser (kpMainWindow *mainWindow);
+ virtual ~kpToolEraser ();
+};
+
+#endif // __kptooleraser_h__
diff --git a/kolourpaint/tools/kptoolflip.cpp b/kolourpaint/tools/kptoolflip.cpp
new file mode 100644
index 00000000..58eeb66d
--- /dev/null
+++ b/kolourpaint/tools/kptoolflip.cpp
@@ -0,0 +1,213 @@
+
+/*
+ Copyright (c) 2003,2004,2005 Clarence Dang <dang@kde.org>
+ 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 <kptoolflip.h>
+
+#include <qapplication.h>
+#include <qradiobutton.h>
+#include <qvbox.h>
+#include <qvbuttongroup.h>
+
+#include <kdebug.h>
+#include <klocale.h>
+
+#include <kpdefs.h>
+#include <kpdocument.h>
+#include <kppixmapfx.h>
+#include <kpselection.h>
+#include <kptool.h>
+#include <kpmainwindow.h>
+
+
+/*
+ * kpToolFlipCommand
+ */
+
+kpToolFlipCommand::kpToolFlipCommand (bool actOnSelection,
+ bool horiz, bool vert,
+ kpMainWindow *mainWindow)
+ : kpCommand (mainWindow),
+ m_actOnSelection (actOnSelection),
+ m_horiz (horiz), m_vert (vert)
+{
+}
+
+kpToolFlipCommand::~kpToolFlipCommand ()
+{
+}
+
+
+// public virtual [base kpCommand]
+QString kpToolFlipCommand::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
+ {
+ kdError () << "kpToolFlipCommand::name() not asked to flip" << endl;
+ return QString::null;
+ }
+#endif
+
+
+ if (m_actOnSelection)
+ return i18n ("Selection: %1").arg (opName);
+ else
+ return opName;
+}
+
+
+// public virtual [base kpCommand]
+int kpToolFlipCommand::size () const
+{
+ return 0;
+}
+
+
+// public virtual [base kpCommand]
+void kpToolFlipCommand::execute ()
+{
+ flip ();
+}
+
+// public virtual [base kpCommand]
+void kpToolFlipCommand::unexecute ()
+{
+ flip ();
+}
+
+
+// private
+void kpToolFlipCommand::flip ()
+{
+ kpDocument *doc = document ();
+ if (!doc)
+ return;
+
+
+ QApplication::setOverrideCursor (Qt::waitCursor);
+
+
+ if (m_actOnSelection)
+ {
+ doc->selection ()->flip (m_horiz, m_vert);
+ if (m_mainWindow->tool ())
+ m_mainWindow->tool ()->somethingBelowTheCursorChanged ();
+ }
+ else
+ {
+ QPixmap newPixmap = kpPixmapFX::flip (*doc->pixmap (), m_horiz, m_vert);
+
+ doc->setPixmap (newPixmap);
+ }
+
+
+ QApplication::restoreOverrideCursor ();
+}
+
+
+/*
+ * kpToolFlipDialog
+ */
+
+// private static
+bool kpToolFlipDialog::s_lastIsVerticalFlip = true;
+
+
+kpToolFlipDialog::kpToolFlipDialog (bool actOnSelection, QWidget *parent)
+ : KDialogBase (parent, 0/*name*/, true/*modal*/,
+ actOnSelection ? i18n ("Flip Selection") : i18n ("Flip Image"),
+ KDialogBase::Ok | KDialogBase::Cancel)
+{
+ QVBox *vbox = makeVBoxMainWidget ();
+
+ if (!vbox)
+ {
+ kdError () << "kpToolFlipDialog::kpToolFlipDialog() received NULL vbox" << endl;
+ }
+ else
+ {
+ QVButtonGroup *buttonGroup = new QVButtonGroup (i18n ("Direction"), vbox);
+
+ // I'm sure vert flipping is much more common than horiz flipping so make it come first
+ m_verticalFlipRadioButton = new QRadioButton (i18n ("&Vertical (upside-down)"), buttonGroup);
+ m_horizontalFlipRadioButton = new QRadioButton (i18n ("&Horizontal"), buttonGroup);
+
+ m_verticalFlipRadioButton->setChecked (s_lastIsVerticalFlip);
+ m_horizontalFlipRadioButton->setChecked (!s_lastIsVerticalFlip);
+
+ connect (m_verticalFlipRadioButton, SIGNAL (toggled (bool)),
+ this, SLOT (slotIsVerticalFlipChanged ()));
+ connect (m_horizontalFlipRadioButton, SIGNAL (toggled (bool)),
+ this, SLOT (slotIsVerticalFlipChanged ()));
+ }
+}
+
+kpToolFlipDialog::~kpToolFlipDialog ()
+{
+}
+
+
+// public slot
+void kpToolFlipDialog::slotIsVerticalFlipChanged ()
+{
+ s_lastIsVerticalFlip = m_verticalFlipRadioButton->isChecked ();
+}
+
+
+// public
+bool kpToolFlipDialog::getHorizontalFlip () const
+{
+ return m_horizontalFlipRadioButton->isChecked ();
+}
+
+// public
+bool kpToolFlipDialog::getVerticalFlip () const
+{
+ return m_verticalFlipRadioButton->isChecked ();
+}
+
+// public
+bool kpToolFlipDialog::isNoOp () const
+{
+ return !getHorizontalFlip () && !getVerticalFlip ();
+}
+
+
+#include <kptoolflip.moc>
+
diff --git a/kolourpaint/tools/kptoolflip.h b/kolourpaint/tools/kptoolflip.h
new file mode 100644
index 00000000..c287c320
--- /dev/null
+++ b/kolourpaint/tools/kptoolflip.h
@@ -0,0 +1,88 @@
+
+/*
+ Copyright (c) 2003,2004,2005 Clarence Dang <dang@kde.org>
+ 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 __kptoolflip_h__
+#define __kptoolflip_h__
+
+#include <kpcommandhistory.h>
+#include <kdialogbase.h>
+
+class QRadioButton;
+class QString;
+
+class kpDocument;
+class kpMainWindow;
+
+
+class kpToolFlipCommand : public kpCommand
+{
+public:
+ kpToolFlipCommand (bool actOnSelection,
+ bool horiz, bool vert,
+ kpMainWindow *mainWindow);
+ virtual ~kpToolFlipCommand ();
+
+ virtual QString name () const;
+
+ virtual int size () const;
+
+ virtual void execute ();
+ virtual void unexecute ();
+
+private:
+ void flip ();
+
+ bool m_actOnSelection;
+ bool m_horiz, m_vert;
+};
+
+
+class kpToolFlipDialog : public KDialogBase
+{
+Q_OBJECT
+
+public:
+ kpToolFlipDialog (bool actOnSelection, QWidget *parent);
+ ~kpToolFlipDialog ();
+
+private:
+ static bool s_lastIsVerticalFlip;
+
+public slots:
+ void slotIsVerticalFlipChanged ();
+
+public:
+ bool getHorizontalFlip () const;
+ bool getVerticalFlip () const;
+ bool isNoOp () const;
+
+private:
+ QRadioButton *m_horizontalFlipRadioButton, *m_verticalFlipRadioButton;
+};
+
+#endif // __kptoolflip_h__
diff --git a/kolourpaint/tools/kptoolfloodfill.cpp b/kolourpaint/tools/kptoolfloodfill.cpp
new file mode 100644
index 00000000..bb17d701
--- /dev/null
+++ b/kolourpaint/tools/kptoolfloodfill.cpp
@@ -0,0 +1,261 @@
+
+/*
+ Copyright (c) 2003,2004,2005 Clarence Dang <dang@kde.org>
+ 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 <kptoolfloodfill.h>
+
+#include <qapplication.h>
+#include <qcursor.h>
+#include <qpainter.h>
+#include <qpixmap.h>
+
+#include <kdebug.h>
+#include <klocale.h>
+
+#include <kpcommandhistory.h>
+#include <kpdefs.h>
+#include <kpdocument.h>
+#include <kpmainwindow.h>
+#include <kpview.h>
+#include <kpviewmanager.h>
+
+
+/*
+ * kpToolFloodFill
+ */
+
+kpToolFloodFill::kpToolFloodFill (kpMainWindow *mainWindow)
+ : kpTool (i18n ("Flood Fill"), i18n ("Fills regions in the image"),
+ Qt::Key_F,
+ mainWindow, "tool_flood_fill"),
+ m_currentCommand (0)
+{
+}
+
+kpToolFloodFill::~kpToolFloodFill ()
+{
+}
+
+QString kpToolFloodFill::haventBegunDrawUserMessage () const
+{
+ return i18n ("Click to fill a region.");
+}
+
+void kpToolFloodFill::begin ()
+{
+ setUserMessage (haventBegunDrawUserMessage ());
+}
+
+// virtual
+void kpToolFloodFill::beginDraw ()
+{
+#if DEBUG_KP_TOOL_FLOOD_FILL && 1
+ kdDebug () << "kpToolFloodFill::beginDraw()" << endl;
+#endif
+
+ QApplication::setOverrideCursor (Qt::waitCursor);
+
+ // Flood Fill is an expensive CPU operation so we only fill at a
+ // mouse click (beginDraw ()), not on mouse move (virtually draw())
+ m_currentCommand = new kpToolFloodFillCommand (m_currentPoint.x (), m_currentPoint.y (),
+ color (m_mouseButton), processedColorSimilarity (),
+ mainWindow ());
+
+ if (m_currentCommand->prepareColorToChange ())
+ {
+ #if DEBUG_KP_TOOL_FLOOD_FILL && 1
+ kdDebug () << "\tperforming new-doc-corner-case check" << endl;
+ #endif
+ if (document ()->url ().isEmpty () && !document ()->isModified ())
+ {
+ m_currentCommand->setFillEntirePixmap ();
+ m_currentCommand->execute ();
+ }
+ else if (m_currentCommand->prepare ())
+ {
+ m_currentCommand->execute ();
+ }
+ else
+ {
+ kdError () << "kpToolFloodFill::beginDraw() could not fill!" << endl;
+ }
+ }
+ else
+ {
+ kdError () << "kpToolFloodFill::beginDraw() could not prepareColorToChange!" << endl;
+ }
+
+ QApplication::restoreOverrideCursor ();
+
+ setUserMessage (cancelUserMessage ());
+}
+
+// virtual
+void kpToolFloodFill::draw (const QPoint &thisPoint, const QPoint &, const QRect &)
+{
+ setUserShapePoints (thisPoint);
+}
+
+// virtual
+void kpToolFloodFill::cancelShape ()
+{
+#if 0
+ endDraw (QPoint (), QRect ());
+ mainWindow ()->commandHistory ()->undo ();
+#else
+ m_currentCommand->unexecute ();
+
+ delete m_currentCommand;
+ m_currentCommand = 0;
+#endif
+
+ setUserMessage (i18n ("Let go of all the mouse buttons."));
+}
+
+void kpToolFloodFill::releasedAllButtons ()
+{
+ setUserMessage (haventBegunDrawUserMessage ());
+}
+
+// virtual
+void kpToolFloodFill::endDraw (const QPoint &, const QRect &)
+{
+ mainWindow ()->commandHistory ()->addCommand (m_currentCommand,
+ false /* no exec - we already did it up there */);
+
+ // don't delete
+ m_currentCommand = 0;
+ setUserMessage (haventBegunDrawUserMessage ());
+}
+
+
+/*
+ * kpToolFloodFillCommand
+ */
+
+kpToolFloodFillCommand::kpToolFloodFillCommand (int x, int y,
+ const kpColor &color, int processedColorSimilarity,
+ kpMainWindow *mainWindow)
+ : kpCommand (mainWindow),
+ kpFloodFill (document ()->pixmap (), x, y, color, processedColorSimilarity),
+ m_fillEntirePixmap (false)
+{
+}
+
+kpToolFloodFillCommand::~kpToolFloodFillCommand ()
+{
+}
+
+
+// public virtual [base kpCommand]
+QString kpToolFloodFillCommand::name () const
+{
+ return i18n ("Flood Fill");
+}
+
+// public virtual [base kpCommand]
+int kpToolFloodFillCommand::size () const
+{
+ return kpFloodFill::size () + kpPixmapFX::pixmapSize (m_oldPixmap);
+}
+
+
+void kpToolFloodFillCommand::setFillEntirePixmap (bool yes)
+{
+ m_fillEntirePixmap = yes;
+}
+
+
+// virtual
+void kpToolFloodFillCommand::execute ()
+{
+#if DEBUG_KP_TOOL_FLOOD_FILL && 1
+ kdDebug () << "kpToolFloodFillCommand::execute() m_fillEntirePixmap=" << m_fillEntirePixmap << endl;
+#endif
+
+ kpDocument *doc = document ();
+ if (!doc)
+ return;
+
+
+ if (m_fillEntirePixmap)
+ {
+ doc->fill (kpFloodFill::color ());
+ }
+ else
+ {
+ QRect rect = kpFloodFill::boundingRect ();
+ if (rect.isValid ())
+ {
+ QApplication::setOverrideCursor (QCursor::waitCursor);
+
+ m_oldPixmap = doc->getPixmapAt (rect);
+
+ kpFloodFill::fill ();
+ doc->slotContentsChanged (rect);
+
+ QApplication::restoreOverrideCursor ();
+ }
+ else
+ {
+ #if DEBUG_KP_TOOL_FLOOD_FILL && 1
+ kdDebug () << "\tinvalid boundingRect - must be NOP case" << endl;
+ #endif
+ }
+ }
+}
+
+// virtual
+void kpToolFloodFillCommand::unexecute ()
+{
+ kpDocument *doc = document ();
+ if (!doc)
+ return;
+
+
+ if (m_fillEntirePixmap)
+ {
+ doc->fill (kpFloodFill::colorToChange ());
+ }
+ else
+ {
+ QRect rect = kpFloodFill::boundingRect ();
+ if (rect.isValid ())
+ {
+ doc->setPixmapAt (m_oldPixmap, rect.topLeft ());
+
+ m_oldPixmap.resize (0, 0);
+
+ doc->slotContentsChanged (rect);
+ }
+ }
+}
+
+#include <kptoolfloodfill.moc>
diff --git a/kolourpaint/tools/kptoolfloodfill.h b/kolourpaint/tools/kptoolfloodfill.h
new file mode 100644
index 00000000..a2eeaa5a
--- /dev/null
+++ b/kolourpaint/tools/kptoolfloodfill.h
@@ -0,0 +1,94 @@
+
+/*
+ Copyright (c) 2003,2004,2005 Clarence Dang <dang@kde.org>
+ 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 __kptoolfloodfill_h__
+#define __kptoolfloodfill_h__
+
+#include <qpixmap.h>
+
+#include <kpcommandhistory.h>
+
+#include <kpfloodfill.h>
+#include <kptool.h>
+
+
+class QString;
+
+class kpColor;
+
+class kpMainWindow;
+class kpToolFloodFillCommand;
+
+
+class kpToolFloodFill : public kpTool
+{
+Q_OBJECT
+
+public:
+ kpToolFloodFill (kpMainWindow *);
+ virtual ~kpToolFloodFill ();
+
+private:
+ QString haventBegunDrawUserMessage () const;
+
+public:
+ virtual void begin ();
+ virtual void beginDraw ();
+ virtual void draw (const QPoint &thisPoint, const QPoint &, const QRect &);
+ virtual void cancelShape ();
+ virtual void releasedAllButtons ();
+ virtual void endDraw (const QPoint &, const QRect &);
+
+private:
+ kpToolFloodFillCommand *m_currentCommand;
+};
+
+
+class kpToolFloodFillCommand : public kpCommand, public kpFloodFill
+{
+public:
+ kpToolFloodFillCommand (int x, int y,
+ const kpColor &color, int processedColorSimilarity,
+ kpMainWindow *mainWindow);
+ virtual ~kpToolFloodFillCommand ();
+
+ virtual QString name () const;
+
+ virtual int size () const;
+
+ void setFillEntirePixmap (bool yes = true);
+
+ virtual void execute ();
+ virtual void unexecute ();
+
+private:
+ QPixmap m_oldPixmap;
+ bool m_fillEntirePixmap;
+};
+
+#endif // __kptoolfloodfill_h__
diff --git a/kolourpaint/tools/kptoolfreeformselection.cpp b/kolourpaint/tools/kptoolfreeformselection.cpp
new file mode 100644
index 00000000..7c736728
--- /dev/null
+++ b/kolourpaint/tools/kptoolfreeformselection.cpp
@@ -0,0 +1,46 @@
+
+/*
+ Copyright (c) 2003,2004,2005 Clarence Dang <dang@kde.org>
+ 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 <kptoolfreeformselection.h>
+
+#include <klocale.h>
+
+
+kpToolFreeFormSelection::kpToolFreeFormSelection (kpMainWindow *mainWindow)
+ : kpToolSelection (kpToolSelection::FreeForm,
+ i18n ("Selection (Free-Form)"),
+ i18n ("Makes a free-form selection"),
+ Qt::Key_M,
+ mainWindow, "tool_free_form_selection")
+{
+}
+
+kpToolFreeFormSelection::~kpToolFreeFormSelection ()
+{
+}
+
diff --git a/kolourpaint/tools/kptoolfreeformselection.h b/kolourpaint/tools/kptoolfreeformselection.h
new file mode 100644
index 00000000..28f1e5ec
--- /dev/null
+++ b/kolourpaint/tools/kptoolfreeformselection.h
@@ -0,0 +1,43 @@
+
+/*
+ Copyright (c) 2003,2004,2005 Clarence Dang <dang@kde.org>
+ 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 __kptoolfreeformselection_h__
+#define __kptoolfreeformselection_h__
+
+#include <kptoolselection.h>
+
+class kpMainWindow;
+
+class kpToolFreeFormSelection : public kpToolSelection
+{
+public:
+ kpToolFreeFormSelection (kpMainWindow *);
+ virtual ~kpToolFreeFormSelection ();
+};
+
+#endif // __kptoolfreeformselection_h__
diff --git a/kolourpaint/tools/kptoolline.cpp b/kolourpaint/tools/kptoolline.cpp
new file mode 100644
index 00000000..809824d9
--- /dev/null
+++ b/kolourpaint/tools/kptoolline.cpp
@@ -0,0 +1,47 @@
+
+/*
+ Copyright (c) 2003,2004,2005 Clarence Dang <dang@kde.org>
+ 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 <kptoolline.h>
+
+#include <klocale.h>
+
+
+kpToolLine::kpToolLine (kpMainWindow *mainWindow)
+ : kpToolPolygon (Line,
+ i18n ("Line"),
+ i18n ("Draws lines"),
+ Qt::Key_L,
+ mainWindow, "tool_line")
+{
+}
+
+kpToolLine::~kpToolLine ()
+{
+}
+
+#include <kptoolline.moc>
diff --git a/kolourpaint/tools/kptoolline.h b/kolourpaint/tools/kptoolline.h
new file mode 100644
index 00000000..7a956245
--- /dev/null
+++ b/kolourpaint/tools/kptoolline.h
@@ -0,0 +1,45 @@
+
+/*
+ Copyright (c) 2003,2004,2005 Clarence Dang <dang@kde.org>
+ 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 __kptoolline_h__
+#define __kptoolline_h__
+
+#include <kptoolpolygon.h>
+
+class kpMainWindow;
+
+class kpToolLine : public kpToolPolygon
+{
+Q_OBJECT
+
+public:
+ kpToolLine (kpMainWindow *);
+ virtual ~kpToolLine ();
+};
+
+#endif // __kptoolline_h__
diff --git a/kolourpaint/tools/kptoolpen.cpp b/kolourpaint/tools/kptoolpen.cpp
new file mode 100644
index 00000000..eb731ceb
--- /dev/null
+++ b/kolourpaint/tools/kptoolpen.cpp
@@ -0,0 +1,1145 @@
+
+/*
+ Copyright (c) 2003,2004,2005 Clarence Dang <dang@kde.org>
+ 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_PEN 0
+
+#include <qapplication.h>
+#include <qbitmap.h>
+#include <qcursor.h>
+#include <qimage.h>
+#include <qpainter.h>
+#if DEBUG_KP_TOOL_PEN
+ #include <qdatetime.h>
+#endif
+
+#include <kdebug.h>
+#include <klocale.h>
+
+#include <kpcolor.h>
+#include <kpcommandhistory.h>
+#include <kpcursorprovider.h>
+#include <kptoolpen.h>
+#include <kpdefs.h>
+#include <kpdocument.h>
+#include <kpmainwindow.h>
+#include <kppixmapfx.h>
+#include <kptemppixmap.h>
+#include <kptoolclear.h>
+#include <kptooltoolbar.h>
+#include <kptoolwidgetbrush.h>
+#include <kptoolwidgeterasersize.h>
+#include <kpviewmanager.h>
+
+/*
+ * kpToolPen
+ */
+
+kpToolPen::kpToolPen (Mode mode,
+ const QString &text, const QString &description,
+ int key,
+ kpMainWindow *mainWindow, const char *name)
+ : kpTool (text, description, key, mainWindow, name),
+ m_mode (mode),
+ m_toolWidgetBrush (0),
+ m_toolWidgetEraserSize (0),
+ m_currentCommand (0)
+{
+}
+
+kpToolPen::kpToolPen (kpMainWindow *mainWindow)
+ : kpTool (i18n ("Pen"), i18n ("Draws dots and freehand strokes"),
+ Qt::Key_P,
+ mainWindow, "tool_pen"),
+ m_mode (Pen),
+ m_toolWidgetBrush (0),
+ m_toolWidgetEraserSize (0),
+ m_currentCommand (0)
+{
+}
+
+void kpToolPen::setMode (Mode mode)
+{
+ int usesPixmaps = (mode & (DrawsPixmaps | WashesPixmaps));
+ int usesBrushes = (mode & (SquareBrushes | DiverseBrushes));
+
+ if ((usesPixmaps && !usesBrushes) ||
+ (usesBrushes && !usesPixmaps))
+ {
+ kdError () << "kpToolPen::setMode() passed invalid mode" << endl;
+ return;
+ }
+
+ m_mode = mode;
+}
+
+kpToolPen::~kpToolPen ()
+{
+}
+
+
+// private
+QString kpToolPen::haventBegunDrawUserMessage () const
+{
+ switch (m_mode)
+ {
+ case Pen:
+ case Brush:
+ return i18n ("Click to draw dots or drag to draw strokes.");
+ return i18n ("Click to draw dots or drag to draw strokes.");
+ case Eraser:
+ return i18n ("Click or drag to erase.");
+ case ColorWasher:
+ return i18n ("Click or drag to erase pixels of the foreground color.");
+ default:
+ return QString::null;
+ }
+}
+
+// virtual
+void kpToolPen::begin ()
+{
+ m_toolWidgetBrush = 0;
+ m_brushIsDiagonalLine = false;
+
+ kpToolToolBar *tb = toolToolBar ();
+ if (!tb)
+ return;
+
+ if (m_mode & SquareBrushes)
+ {
+ m_toolWidgetEraserSize = tb->toolWidgetEraserSize ();
+ connect (m_toolWidgetEraserSize, SIGNAL (eraserSizeChanged (int)),
+ this, SLOT (slotEraserSizeChanged (int)));
+ m_toolWidgetEraserSize->show ();
+
+ slotEraserSizeChanged (m_toolWidgetEraserSize->eraserSize ());
+
+ viewManager ()->setCursor (kpCursorProvider::lightCross ());
+ }
+
+ if (m_mode & DiverseBrushes)
+ {
+ m_toolWidgetBrush = tb->toolWidgetBrush ();
+ connect (m_toolWidgetBrush, SIGNAL (brushChanged (const QPixmap &, bool)),
+ this, SLOT (slotBrushChanged (const QPixmap &, bool)));
+ m_toolWidgetBrush->show ();
+
+ slotBrushChanged (m_toolWidgetBrush->brush (),
+ m_toolWidgetBrush->brushIsDiagonalLine ());
+
+ viewManager ()->setCursor (kpCursorProvider::lightCross ());
+ }
+
+ setUserMessage (haventBegunDrawUserMessage ());
+}
+
+// virtual
+void kpToolPen::end ()
+{
+ if (m_toolWidgetEraserSize)
+ {
+ disconnect (m_toolWidgetEraserSize, SIGNAL (eraserSizeChanged (int)),
+ this, SLOT (slotEraserSizeChanged (int)));
+ m_toolWidgetEraserSize = 0;
+ }
+
+ if (m_toolWidgetBrush)
+ {
+ disconnect (m_toolWidgetBrush, SIGNAL (brushChanged (const QPixmap &, bool)),
+ this, SLOT (slotBrushChanged (const QPixmap &, bool)));
+ m_toolWidgetBrush = 0;
+ }
+
+ kpViewManager *vm = viewManager ();
+ if (vm)
+ {
+ if (vm->tempPixmap () && vm->tempPixmap ()->isBrush ())
+ vm->invalidateTempPixmap ();
+
+ if (m_mode & (SquareBrushes | DiverseBrushes))
+ vm->unsetCursor ();
+ }
+
+ // save memory
+ for (int i = 0; i < 2; i++)
+ m_brushPixmap [i].resize (0, 0);
+ m_cursorPixmap.resize (0, 0);
+}
+
+// virtual
+void kpToolPen::beginDraw ()
+{
+ switch (m_mode)
+ {
+ case Pen:
+ m_currentCommand = new kpToolPenCommand (i18n ("Pen"), mainWindow ());
+ break;
+ case Brush:
+ m_currentCommand = new kpToolPenCommand (i18n ("Brush"), mainWindow ());
+ break;
+ case Eraser:
+ m_currentCommand = new kpToolPenCommand (i18n ("Eraser"), mainWindow ());
+ break;
+ case ColorWasher:
+ m_currentCommand = new kpToolPenCommand (i18n ("Color Eraser"), mainWindow ());
+ break;
+
+ default:
+ m_currentCommand = new kpToolPenCommand (i18n ("Custom Pen or Brush"), mainWindow ());
+ break;
+ }
+
+ // we normally show the Brush pix in the foreground colour but if the
+ // user starts drawing in the background color, we don't want to leave
+ // the cursor in the foreground colour -- just hide it in all cases
+ // to avoid confusion
+ viewManager ()->invalidateTempPixmap ();
+
+ setUserMessage (cancelUserMessage ());
+}
+
+// virtual
+void kpToolPen::hover (const QPoint &point)
+{
+#if DEBUG_KP_TOOL_PEN && 0
+ kdDebug () << "kpToolPen::hover(" << point << ")"
+ << " hasBegun=" << hasBegun ()
+ << " hasBegunDraw=" << hasBegunDraw ()
+ << " cursorPixmap.isNull=" << m_cursorPixmap.isNull ()
+ << endl;
+#endif
+ if (point != KP_INVALID_POINT && !m_cursorPixmap.isNull ())
+ {
+ // (for hotPoint() as m_mouseButton is not normally defined in hover())
+ m_mouseButton = 0;
+
+ kpTempPixmap::RenderMode renderMode;
+ QPixmap cursorPixmapForTempPixmap = m_cursorPixmap;
+
+ if (m_mode & SquareBrushes)
+ renderMode = kpTempPixmap::SetPixmap;
+ else if (m_mode & DiverseBrushes)
+ {
+ if (color (0).isOpaque ())
+ renderMode = kpTempPixmap::PaintPixmap;
+ else
+ {
+ renderMode = kpTempPixmap::PaintMaskTransparentWithBrush;
+ cursorPixmapForTempPixmap = kpPixmapFX::getNonNullMask (m_cursorPixmap);
+ }
+ }
+
+ viewManager ()->setFastUpdates ();
+
+ viewManager ()->setTempPixmap (
+ kpTempPixmap (true/*brush*/,
+ renderMode,
+ hotPoint (),
+ cursorPixmapForTempPixmap));
+
+ viewManager ()->restoreFastUpdates ();
+ }
+
+#if DEBUG_KP_TOOL_PEN && 0
+ if (document ()->rect ().contains (point))
+ {
+ QImage image = kpPixmapFX::convertToImage (*document ()->pixmap ());
+
+ QRgb v = image.pixel (point.x (), point.y ());
+ kdDebug () << "(" << point << "): r=" << qRed (v)
+ << " g=" << qGreen (v)
+ << " b=" << qBlue (v)
+ << " a=" << qAlpha (v)
+ << endl;
+ }
+#endif
+
+ setUserShapePoints (point);
+}
+
+bool kpToolPen::wash (QPainter *painter, QPainter *maskPainter,
+ const QImage &image,
+ const kpColor &colorToReplace,
+ const QRect &imageRect, int plotx, int ploty)
+{
+ return wash (painter, maskPainter, image, colorToReplace, imageRect, hotRect (plotx, ploty));
+}
+
+bool kpToolPen::wash (QPainter *painter, QPainter *maskPainter,
+ const QImage &image,
+ const kpColor &colorToReplace,
+ const QRect &imageRect, const QRect &drawRect)
+{
+ bool didSomething = false;
+
+#if DEBUG_KP_TOOL_PEN && 0
+ kdDebug () << "kpToolPen::wash(imageRect=" << imageRect
+ << ",drawRect=" << drawRect
+ << ")" << endl;
+#endif
+
+// make use of scanline coherence
+#define FLUSH_LINE() \
+{ \
+ if (painter && painter->isActive ()) \
+ painter->drawLine (startDrawX, y, x - 1, y); \
+ if (maskPainter && maskPainter->isActive ()) \
+ maskPainter->drawLine (startDrawX, y, x - 1, 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++)
+ {
+ #if DEBUG_KP_TOOL_PEN && 0
+ fprintf (stderr, "y=%i x=%i colorAtPixel=%08X colorToReplace=%08X ... ",
+ y, x,
+ kpPixmapFX::getColorAtPixel (image, QPoint (x, y)).toQRgb (),
+ colorToReplace.toQRgb ());
+ #endif
+ if (kpPixmapFX::getColorAtPixel (image, QPoint (x, y)).isSimilarTo (colorToReplace, processedColorSimilarity ()))
+ {
+ #if DEBUG_KP_TOOL_PEN && 0
+ fprintf (stderr, "similar\n");
+ #endif
+ if (startDrawX < 0)
+ startDrawX = x;
+ }
+ else
+ {
+ #if DEBUG_KP_TOOL_PEN && 0
+ fprintf (stderr, "different\n");
+ #endif
+ if (startDrawX >= 0)
+ FLUSH_LINE ();
+ }
+ }
+
+ if (startDrawX >= 0)
+ FLUSH_LINE ();
+ }
+
+#undef FLUSH_LINE
+
+ return didSomething;
+}
+
+// virtual
+void kpToolPen::globalDraw ()
+{
+ // it's easiest to reimplement globalDraw() here rather than in
+ // all the relevant subclasses
+
+ if (m_mode == Eraser)
+ {
+ #if DEBUG_KP_TOOL_PEN
+ kdDebug () << "kpToolPen::globalDraw() eraser" << endl;
+ #endif
+ mainWindow ()->commandHistory ()->addCommand (
+ new kpToolClearCommand (false/*act on doc, not sel*/, mainWindow ()));
+ }
+ else if (m_mode == ColorWasher)
+ {
+ #if DEBUG_KP_TOOL_PEN
+ kdDebug () << "kpToolPen::globalDraw() colour eraser" << endl;
+ #endif
+ if (foregroundColor () == backgroundColor () && processedColorSimilarity () == 0)
+ return;
+
+ QApplication::setOverrideCursor (Qt::waitCursor);
+
+ kpToolPenCommand *cmd = new kpToolPenCommand (
+ i18n ("Color Eraser"), mainWindow ());
+
+ QPainter painter, maskPainter;
+ QBitmap maskBitmap;
+
+ if (backgroundColor ().isOpaque ())
+ {
+ painter.begin (document ()->pixmap ());
+ painter.setPen (backgroundColor ().toQColor ());
+ }
+
+ if (backgroundColor ().isTransparent () ||
+ document ()->pixmap ()->mask ())
+ {
+ maskBitmap = kpPixmapFX::getNonNullMask (*document ()->pixmap ());
+ maskPainter.begin (&maskBitmap);
+
+ maskPainter.setPen (backgroundColor ().maskColor ());
+ }
+
+ const QImage image = kpPixmapFX::convertToImage (*document ()->pixmap ());
+ QRect rect = document ()->rect ();
+
+ const bool didSomething = wash (&painter, &maskPainter, image,
+ foregroundColor ()/*replace foreground*/,
+ rect, rect);
+
+ // flush
+ if (painter.isActive ())
+ painter.end ();
+
+ if (maskPainter.isActive ())
+ maskPainter.end ();
+
+ if (didSomething)
+ {
+ if (!maskBitmap.isNull ())
+ document ()->pixmap ()->setMask (maskBitmap);
+
+
+ document ()->slotContentsChanged (rect);
+
+
+ cmd->updateBoundingRect (rect);
+ cmd->finalize ();
+
+ mainWindow ()->commandHistory ()->addCommand (cmd, false /* don't exec */);
+
+ // don't delete - it's up to the commandHistory
+ cmd = 0;
+ }
+ else
+ {
+ #if DEBUG_KP_TOOL_PEN
+ kdDebug () << "\tisNOP" << endl;
+ #endif
+ delete cmd;
+ cmd = 0;
+ }
+
+ QApplication::restoreOverrideCursor ();
+ }
+}
+
+// virtual
+// TODO: refactor!
+void kpToolPen::draw (const QPoint &thisPoint, const QPoint &lastPoint, const QRect &)
+{
+ if ((m_mode & WashesPixmaps) && (foregroundColor () == backgroundColor ()) && processedColorSimilarity () == 0)
+ return;
+
+ // sync: remember to restoreFastUpdates() in all exit paths
+ viewManager ()->setFastUpdates ();
+
+ if (m_brushIsDiagonalLine ? currentPointCardinallyNextToLast () : currentPointNextToLast ())
+ {
+ if (m_mode & DrawsPixels)
+ {
+ QPixmap pixmap (1, 1);
+
+ const kpColor c = color (m_mouseButton);
+
+ // OPT: this seems hopelessly inefficient
+ if (c.isOpaque ())
+ {
+ pixmap.fill (c.toQColor ());
+ }
+ else
+ {
+ QBitmap mask (1, 1);
+ mask.fill (Qt::color0/*transparent*/);
+
+ pixmap.setMask (mask);
+ }
+
+ // draw onto doc
+ document ()->setPixmapAt (pixmap, thisPoint);
+
+ m_currentCommand->updateBoundingRect (thisPoint);
+ }
+ // Brush & Eraser
+ else if (m_mode & DrawsPixmaps)
+ {
+ if (color (m_mouseButton).isOpaque ())
+ document ()->paintPixmapAt (m_brushPixmap [m_mouseButton], hotPoint ());
+ else
+ {
+ kpPixmapFX::paintMaskTransparentWithBrush (document ()->pixmap (),
+ hotPoint (),
+ kpPixmapFX::getNonNullMask (m_brushPixmap [m_mouseButton]));
+ document ()->slotContentsChanged (hotRect ());
+ }
+
+ m_currentCommand->updateBoundingRect (hotRect ());
+ }
+ else if (m_mode & WashesPixmaps)
+ {
+ #if DEBUG_KP_TOOL_PEN
+ kdDebug () << "Washing pixmap (immediate)" << endl;
+ QTime timer;
+ #endif
+ QRect rect = hotRect ();
+ #if DEBUG_KP_TOOL_PEN
+ timer.start ();
+ #endif
+ QPixmap pixmap = document ()->getPixmapAt (rect);
+ #if DEBUG_KP_TOOL_PEN
+ kdDebug () << "\tget from doc: " << timer.restart () << "ms" << endl;
+ #endif
+ const QImage image = kpPixmapFX::convertToImage (pixmap);
+ #if DEBUG_KP_TOOL_PEN
+ kdDebug () << "\tconvert to image: " << timer.restart () << "ms" << endl;
+ #endif
+ QPainter painter, maskPainter;
+ QBitmap maskBitmap;
+
+ if (color (m_mouseButton).isOpaque ())
+ {
+ painter.begin (&pixmap);
+ painter.setPen (color (m_mouseButton).toQColor ());
+ }
+
+ if (color (m_mouseButton).isTransparent () ||
+ pixmap.mask ())
+ {
+ maskBitmap = kpPixmapFX::getNonNullMask (pixmap);
+ maskPainter.begin (&maskBitmap);
+ maskPainter.setPen (color (m_mouseButton).maskColor ());
+ }
+
+ bool didSomething = wash (&painter, &maskPainter,
+ image,
+ color (1 - m_mouseButton)/*color to replace*/,
+ rect, rect);
+
+ if (painter.isActive ())
+ painter.end ();
+
+ if (maskPainter.isActive ())
+ maskPainter.end ();
+
+ if (didSomething)
+ {
+ if (!maskBitmap.isNull ())
+ pixmap.setMask (maskBitmap);
+
+ #if DEBUG_KP_TOOL_PEN
+ kdDebug () << "\twashed: " << timer.restart () << "ms" << endl;
+ #endif
+ document ()->setPixmapAt (pixmap, hotPoint ());
+ #if DEBUG_KP_TOOL_PEN
+ kdDebug () << "\tset doc: " << timer.restart () << "ms" << endl;
+ #endif
+ m_currentCommand->updateBoundingRect (hotRect ());
+ #if DEBUG_KP_TOOL_PEN
+ kdDebug () << "\tupdate boundingRect: " << timer.restart () << "ms" << endl;
+ kdDebug () << "\tdone" << endl;
+ #endif
+ }
+
+ #if DEBUG_KP_TOOL_PEN && 1
+ kdDebug () << endl;
+ #endif
+ }
+ }
+ // in reality, the system is too slow to give us all the MouseMove events
+ // so we "interpolate" the missing points :)
+ else
+ {
+ // find bounding rectangle
+ QRect rect = QRect (thisPoint, lastPoint).normalize ();
+ if (m_mode != DrawsPixels)
+ rect = neededRect (rect, m_brushPixmap [m_mouseButton].width ());
+
+ #if DEBUG_KP_TOOL_PEN
+ if (m_mode & WashesPixmaps)
+ {
+ kdDebug () << "Washing pixmap (w=" << rect.width ()
+ << ",h=" << rect.height () << ")" << endl;
+ }
+ QTime timer;
+ int convAndWashTime;
+ #endif
+
+ const kpColor c = color (m_mouseButton);
+ bool transparent = c.isTransparent ();
+
+ QPixmap pixmap = document ()->getPixmapAt (rect);
+ QBitmap maskBitmap;
+
+ QPainter painter, maskPainter;
+
+ if (m_mode & (DrawsPixels | WashesPixmaps))
+ {
+ if (!transparent)
+ {
+ painter.begin (&pixmap);
+ painter.setPen (c.toQColor ());
+ }
+
+ if (transparent || pixmap.mask ())
+ {
+ maskBitmap = kpPixmapFX::getNonNullMask (pixmap);
+ maskPainter.begin (&maskBitmap);
+ maskPainter.setPen (c.maskColor ());
+ }
+ }
+
+ QImage image;
+ if (m_mode & WashesPixmaps)
+ {
+ #if DEBUG_KP_TOOL_PEN
+ timer.start ();
+ #endif
+ image = kpPixmapFX::convertToImage (pixmap);
+ #if DEBUG_KP_TOOL_PEN
+ convAndWashTime = timer.restart ();
+ kdDebug () << "\tconvert to image: " << convAndWashTime << " ms" << endl;
+ #endif
+ }
+
+ bool didSomething = false;
+
+ if (m_mode & DrawsPixels)
+ {
+ QPoint sp = lastPoint - rect.topLeft (), ep = thisPoint - rect.topLeft ();
+ if (painter.isActive ())
+ painter.drawLine (sp, ep);
+
+ if (maskPainter.isActive ())
+ maskPainter.drawLine (sp, ep);
+
+ didSomething = true;
+ }
+ // Brush & Eraser
+ else if (m_mode & (DrawsPixmaps | WashesPixmaps))
+ {
+ kpColor colorToReplace;
+
+ if (m_mode & WashesPixmaps)
+ colorToReplace = color (1 - m_mouseButton);
+
+ // Sweeps a pixmap along a line (modified Bresenham's line algorithm,
+ // see MODIFIED comment below).
+ //
+ // Derived from the zSprite2 Graphics Engine
+
+ const int x1 = (thisPoint - rect.topLeft ()).x (),
+ y1 = (thisPoint - rect.topLeft ()).y (),
+ x2 = (lastPoint - rect.topLeft ()).x (),
+ y2 = (lastPoint - rect.topLeft ()).y ();
+
+ // Difference of x and y values
+ int dx = x2 - x1;
+ int dy = y2 - y1;
+
+ // Absolute values of differences
+ int ix = kAbs (dx);
+ int iy = kAbs (dy);
+
+ // Larger of the x and y differences
+ int inc = ix > iy ? ix : iy;
+
+ // Plot location
+ int plotx = x1;
+ int ploty = y1;
+
+ int x = 0;
+ int y = 0;
+
+ if (m_mode & WashesPixmaps)
+ {
+ if (wash (&painter, &maskPainter, image,
+ colorToReplace,
+ rect, plotx + rect.left (), ploty + rect.top ()))
+ {
+ didSomething = true;
+ }
+ }
+ else
+ {
+ if (!transparent)
+ {
+ kpPixmapFX::paintPixmapAt (&pixmap,
+ hotPoint (plotx, ploty),
+ m_brushPixmap [m_mouseButton]);
+ }
+ else
+ {
+ kpPixmapFX::paintMaskTransparentWithBrush (&pixmap,
+ hotPoint (plotx, ploty),
+ kpPixmapFX::getNonNullMask (m_brushPixmap [m_mouseButton]));
+ }
+
+ didSomething = true;
+ }
+
+ for (int i = 0; i <= inc; i++)
+ {
+ // oldplotx is equally as valid but would look different
+ // (but nobody will notice which one it is)
+ int oldploty = ploty;
+ int plot = 0;
+
+ x += ix;
+ y += iy;
+
+ if (x > inc)
+ {
+ plot++;
+ x -= inc;
+
+ if (dx < 0)
+ plotx--;
+ else
+ plotx++;
+ }
+
+ if (y > inc)
+ {
+ plot++;
+ y -= inc;
+
+ if (dy < 0)
+ ploty--;
+ else
+ ploty++;
+ }
+
+ if (plot)
+ {
+ if (m_brushIsDiagonalLine && 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 (m_mode & WashesPixmaps)
+ {
+ if (wash (&painter, &maskPainter, image,
+ colorToReplace,
+ rect, plotx + rect.left (), oldploty + rect.top ()))
+ {
+ didSomething = true;
+ }
+ }
+ else
+ {
+ if (!transparent)
+ {
+ kpPixmapFX::paintPixmapAt (&pixmap,
+ hotPoint (plotx, oldploty),
+ m_brushPixmap [m_mouseButton]);
+ }
+ else
+ {
+ kpPixmapFX::paintMaskTransparentWithBrush (&pixmap,
+ hotPoint (plotx, oldploty),
+ kpPixmapFX::getNonNullMask (m_brushPixmap [m_mouseButton]));
+ }
+
+ didSomething = true;
+ }
+ }
+
+ if (m_mode & WashesPixmaps)
+ {
+ if (wash (&painter, &maskPainter, image,
+ colorToReplace,
+ rect, plotx + rect.left (), ploty + rect.top ()))
+ {
+ didSomething = true;
+ }
+ }
+ else
+ {
+ if (!transparent)
+ {
+ kpPixmapFX::paintPixmapAt (&pixmap,
+ hotPoint (plotx, ploty),
+ m_brushPixmap [m_mouseButton]);
+ }
+ else
+ {
+ kpPixmapFX::paintMaskTransparentWithBrush (&pixmap,
+ hotPoint (plotx, ploty),
+ kpPixmapFX::getNonNullMask (m_brushPixmap [m_mouseButton]));
+ }
+
+ didSomething = true;
+ }
+ }
+ }
+
+ }
+
+ if (painter.isActive ())
+ painter.end ();
+
+ if (maskPainter.isActive ())
+ maskPainter.end ();
+
+ #if DEBUG_KP_TOOL_PEN
+ if (m_mode & WashesPixmaps)
+ {
+ int ms = timer.restart ();
+ kdDebug () << "\ttried to wash: " << ms << "ms"
+ << " (" << (ms ? (rect.width () * rect.height () / ms) : -1234)
+ << " pixels/ms)"
+ << endl;
+ convAndWashTime += ms;
+ }
+ #endif
+
+
+ if (didSomething)
+ {
+ if (!maskBitmap.isNull ())
+ pixmap.setMask (maskBitmap);
+
+ // draw onto doc
+ document ()->setPixmapAt (pixmap, rect.topLeft ());
+
+ #if DEBUG_KP_TOOL_PEN
+ if (m_mode & WashesPixmaps)
+ {
+ int ms = timer.restart ();
+ kdDebug () << "\tset doc: " << ms << "ms" << endl;
+ convAndWashTime += ms;
+ }
+ #endif
+
+ m_currentCommand->updateBoundingRect (rect);
+
+ #if DEBUG_KP_TOOL_PEN
+ if (m_mode & WashesPixmaps)
+ {
+ int ms = timer.restart ();
+ kdDebug () << "\tupdate boundingRect: " << ms << "ms" << endl;
+ convAndWashTime += ms;
+ kdDebug () << "\tdone (" << (convAndWashTime ? (rect.width () * rect.height () / convAndWashTime) : -1234)
+ << " pixels/ms)"
+ << endl;
+ }
+ #endif
+ }
+
+ #if DEBUG_KP_TOOL_PEN
+ if (m_mode & WashesPixmaps)
+ kdDebug () << endl;
+ #endif
+ }
+
+ viewManager ()->restoreFastUpdates ();
+ setUserShapePoints (thisPoint);
+}
+
+// virtual
+void kpToolPen::cancelShape ()
+{
+ m_currentCommand->finalize ();
+ m_currentCommand->cancel ();
+
+ delete m_currentCommand;
+ m_currentCommand = 0;
+
+ updateBrushCursor (false/*no recalc*/);
+
+ setUserMessage (i18n ("Let go of all the mouse buttons."));
+}
+
+void kpToolPen::releasedAllButtons ()
+{
+ setUserMessage (haventBegunDrawUserMessage ());
+}
+
+// virtual
+void kpToolPen::endDraw (const QPoint &, const QRect &)
+{
+ m_currentCommand->finalize ();
+ mainWindow ()->commandHistory ()->addCommand (m_currentCommand, false /* don't exec */);
+
+ // don't delete - it's up to the commandHistory
+ m_currentCommand = 0;
+
+ updateBrushCursor (false/*no recalc*/);
+
+ setUserMessage (haventBegunDrawUserMessage ());
+}
+
+
+// TODO: maybe the base should be virtual?
+kpColor kpToolPen::color (int which)
+{
+#if DEBUG_KP_TOOL_PEN && 0
+ kdDebug () << "kpToolPen::color (" << which << ")" << endl;
+#endif
+
+ // Pen & Brush
+ if ((m_mode & SwappedColors) == 0)
+ return kpTool::color (which);
+ // only the (Color) Eraser uses the opposite color
+ else
+ return kpTool::color (which ? 0 : 1); // don't trust !0 == 1
+}
+
+// virtual private slot
+void kpToolPen::slotForegroundColorChanged (const kpColor &col)
+{
+#if DEBUG_KP_TOOL_PEN
+ kdDebug () << "kpToolPen::slotForegroundColorChanged()" << endl;
+#endif
+ if (col.isOpaque ())
+ m_brushPixmap [(m_mode & SwappedColors) ? 1 : 0].fill (col.toQColor ());
+
+ updateBrushCursor ();
+}
+
+// virtual private slot
+void kpToolPen::slotBackgroundColorChanged (const kpColor &col)
+{
+#if DEBUG_KP_TOOL_PEN
+ kdDebug () << "kpToolPen::slotBackgroundColorChanged()" << endl;
+#endif
+
+ if (col.isOpaque ())
+ m_brushPixmap [(m_mode & SwappedColors) ? 0 : 1].fill (col.toQColor ());
+
+ updateBrushCursor ();
+}
+
+// private slot
+void kpToolPen::slotBrushChanged (const QPixmap &pixmap, bool isDiagonalLine)
+{
+#if DEBUG_KP_TOOL_PEN
+ kdDebug () << "kpToolPen::slotBrushChanged()" << endl;
+#endif
+ for (int i = 0; i < 2; i++)
+ {
+ m_brushPixmap [i] = pixmap;
+ if (color (i).isOpaque ())
+ m_brushPixmap [i].fill (color (i).toQColor ());
+ }
+
+ m_brushIsDiagonalLine = isDiagonalLine;
+
+ updateBrushCursor ();
+}
+
+// private slot
+void kpToolPen::slotEraserSizeChanged (int size)
+{
+#if DEBUG_KP_TOOL_PEN
+ kdDebug () << "KpToolPen::slotEraserSizeChanged(size=" << size << ")" << endl;
+#endif
+
+ for (int i = 0; i < 2; i++)
+ {
+ // Note: No matter what, the eraser's brush pixmap is never given
+ // a mask.
+ //
+ // With a transparent color, since we don't fill anything, the
+ // resize by itself will leave us with garbage pixels. This
+ // doesn't matter because:
+ //
+ // 1. The hover cursor will ask kpToolWidgetEraserSize for a proper
+ // cursor pixmap.
+ // 2. We will draw using kpPixmapFX::paintMaskTransparentWithBrush()
+ // which only cares about the opaqueness.
+ m_brushPixmap [i].resize (size, size);
+ if (color (i).isOpaque ())
+ m_brushPixmap [i].fill (color (i).toQColor ());
+ }
+
+ updateBrushCursor ();
+}
+
+QPoint kpToolPen::hotPoint () const
+{
+ return hotPoint (m_currentPoint);
+}
+
+QPoint kpToolPen::hotPoint (int x, int y) const
+{
+ return hotPoint (QPoint (x, y));
+}
+
+QPoint kpToolPen::hotPoint (const QPoint &point) const
+{
+ /*
+ * e.g.
+ * Width 5:
+ * 0 1 2 3 4
+ * ^
+ * |
+ * Center
+ */
+ return point -
+ QPoint (m_brushPixmap [m_mouseButton].width () / 2,
+ m_brushPixmap [m_mouseButton].height () / 2);
+}
+
+QRect kpToolPen::hotRect () const
+{
+ return hotRect (m_currentPoint);
+}
+
+QRect kpToolPen::hotRect (int x, int y) const
+{
+ return hotRect (QPoint (x, y));
+}
+
+QRect kpToolPen::hotRect (const QPoint &point) const
+{
+ QPoint topLeft = hotPoint (point);
+ return QRect (topLeft.x (),
+ topLeft.y (),
+ m_brushPixmap [m_mouseButton].width (),
+ m_brushPixmap [m_mouseButton].height ());
+}
+
+// private
+void kpToolPen::updateBrushCursor (bool recalc)
+{
+#if DEBUG_KP_TOOL_PEN && 1
+ kdDebug () << "kpToolPen::updateBrushCursor(recalc=" << recalc << ")" << endl;
+#endif
+
+ if (recalc)
+ {
+ if (m_mode & SquareBrushes)
+ m_cursorPixmap = m_toolWidgetEraserSize->cursorPixmap (color (0));
+ else if (m_mode & DiverseBrushes)
+ m_cursorPixmap = m_brushPixmap [0];
+ }
+
+ hover (hasBegun () ? m_currentPoint : currentPoint ());
+}
+
+
+/*
+ * kpToolPenCommand
+ */
+
+kpToolPenCommand::kpToolPenCommand (const QString &name, kpMainWindow *mainWindow)
+ : kpNamedCommand (name, mainWindow),
+ m_pixmap (*document ()->pixmap ())
+{
+}
+
+kpToolPenCommand::~kpToolPenCommand ()
+{
+}
+
+
+// public virtual [base kpCommand]
+int kpToolPenCommand::size () const
+{
+ return kpPixmapFX::pixmapSize (m_pixmap);
+}
+
+
+// public virtual [base kpCommand]
+void kpToolPenCommand::execute ()
+{
+ swapOldAndNew ();
+}
+
+// public virtual [base kpCommand]
+void kpToolPenCommand::unexecute ()
+{
+ swapOldAndNew ();
+}
+
+
+// private
+void kpToolPenCommand::swapOldAndNew ()
+{
+ if (m_boundingRect.isValid ())
+ {
+ QPixmap oldPixmap = document ()->getPixmapAt (m_boundingRect);
+
+ document ()->setPixmapAt (m_pixmap, m_boundingRect.topLeft ());
+
+ m_pixmap = oldPixmap;
+ }
+}
+
+// public
+void kpToolPenCommand::updateBoundingRect (const QPoint &point)
+{
+ updateBoundingRect (QRect (point, point));
+}
+
+// public
+void kpToolPenCommand::updateBoundingRect (const QRect &rect)
+{
+#if DEBUG_KP_TOOL_PEN & 0
+ kdDebug () << "kpToolPenCommand::updateBoundingRect() existing="
+ << m_boundingRect
+ << " plus="
+ << rect
+ << endl;
+#endif
+ m_boundingRect = m_boundingRect.unite (rect);
+#if DEBUG_KP_TOOL_PEN & 0
+ kdDebug () << "\tresult=" << m_boundingRect << endl;
+#endif
+}
+
+// public
+void kpToolPenCommand::finalize ()
+{
+ if (m_boundingRect.isValid ())
+ {
+ // store only needed part of doc pixmap
+ m_pixmap = kpTool::neededPixmap (m_pixmap, m_boundingRect);
+ }
+ else
+ {
+ m_pixmap.resize (0, 0);
+ }
+}
+
+// public
+void kpToolPenCommand::cancel ()
+{
+ if (m_boundingRect.isValid ())
+ {
+ viewManager ()->setFastUpdates ();
+ document ()->setPixmapAt (m_pixmap, m_boundingRect.topLeft ());
+ viewManager ()->restoreFastUpdates ();
+ }
+}
+
+#include <kptoolpen.moc>
diff --git a/kolourpaint/tools/kptoolpen.h b/kolourpaint/tools/kptoolpen.h
new file mode 100644
index 00000000..f57eb367
--- /dev/null
+++ b/kolourpaint/tools/kptoolpen.h
@@ -0,0 +1,160 @@
+
+/*
+ Copyright (c) 2003,2004,2005 Clarence Dang <dang@kde.org>
+ 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 __kptoolpen_h__
+#define __kptoolpen_h__
+
+#include <qpixmap.h>
+#include <qrect.h>
+
+#include <kpcommandhistory.h>
+#include <kptool.h>
+
+class QPoint;
+class QString;
+
+class kpColor;
+class kpMainWindow;
+class kpToolPenCommand;
+class kpToolWidgetBrush;
+class kpToolWidgetEraserSize;
+class kpViewManager;
+
+class kpToolPen : public kpTool
+{
+Q_OBJECT
+
+public:
+ enum Mode
+ {
+ // tool properties
+ DrawsPixels = (1 << 0), DrawsPixmaps = (1 << 1), WashesPixmaps = (1 << 2),
+ NoBrushes = 0, SquareBrushes = (1 << 3), DiverseBrushes = (1 << 4),
+ NormalColors = 0, SwappedColors = (1 << 5),
+
+ // tools:
+ //
+ // Pen = draws pixels, "interpolates" by "sweeping" pixels along a line (no brushes)
+ // Brush = draws pixmaps, "interpolates" by "sweeping" pixmaps along a line (interesting brushes)
+ // Eraser = Brush but with foreground & background colors swapped (a few square brushes)
+ // Color Washer = Brush that replaces/washes the foreground color with the background color
+ //
+ // (note the capitalization of "brush" here :))
+ Pen = DrawsPixels | NoBrushes | NormalColors,
+ Brush = DrawsPixmaps | DiverseBrushes | NormalColors,
+ Eraser = DrawsPixmaps | SquareBrushes | SwappedColors,
+ ColorWasher = WashesPixmaps | SquareBrushes | SwappedColors
+ };
+
+ kpToolPen (Mode mode, const QString &text, const QString &description,
+ int key,
+ kpMainWindow *mainWindow, const char *name);
+ kpToolPen (kpMainWindow *mainWindow);
+ virtual ~kpToolPen ();
+
+ void setMode (Mode mode);
+
+private:
+ QString haventBegunDrawUserMessage () const;
+
+public:
+ virtual void begin ();
+ virtual void end ();
+
+ virtual void beginDraw ();
+ virtual void hover (const QPoint &point);
+ virtual void globalDraw ();
+ virtual void draw (const QPoint &thisPoint, const QPoint &lastPoint, const QRect &);
+ virtual void cancelShape ();
+ virtual void releasedAllButtons ();
+ virtual void endDraw (const QPoint &, const QRect &);
+
+private slots:
+ virtual void slotForegroundColorChanged (const kpColor &col);
+ virtual void slotBackgroundColorChanged (const kpColor &col);
+
+ void slotBrushChanged (const QPixmap &pixmap, bool isDiagonalLine);
+ void slotEraserSizeChanged (int size);
+
+private:
+ bool wash (QPainter *painter, QPainter *maskPainter,
+ const QImage &image,
+ const kpColor &colorToReplace,
+ const QRect &imageRect, int plotx, int ploty);
+ bool wash (QPainter *painter, QPainter *maskPainter,
+ const QImage &image,
+ const kpColor &colorToReplace,
+ const QRect &imageRect, const QRect &drawRect);
+
+ kpColor color (int which);
+
+ QPoint hotPoint () const;
+ QPoint hotPoint (int x, int y) const;
+ QPoint hotPoint (const QPoint &point) const;
+ QRect hotRect () const;
+ QRect hotRect (int x, int y) const;
+ QRect hotRect (const QPoint &point) const;
+
+ Mode m_mode;
+
+ void updateBrushCursor (bool recalc = true);
+
+ kpToolWidgetBrush *m_toolWidgetBrush;
+ kpToolWidgetEraserSize *m_toolWidgetEraserSize;
+ QPixmap m_brushPixmap [2];
+ QPixmap m_cursorPixmap;
+ bool m_brushIsDiagonalLine;
+
+ kpToolPenCommand *m_currentCommand;
+};
+
+class kpToolPenCommand : public kpNamedCommand
+{
+public:
+ kpToolPenCommand (const QString &name, kpMainWindow *mainWindow);
+ virtual ~kpToolPenCommand ();
+
+ virtual int size () const;
+
+ virtual void execute ();
+ virtual void unexecute ();
+
+ // interface for KToolPen
+ void updateBoundingRect (const QPoint &point);
+ void updateBoundingRect (const QRect &rect);
+ void finalize ();
+ void cancel ();
+
+private:
+ void swapOldAndNew ();
+
+ QPixmap m_pixmap;
+ QRect m_boundingRect;
+};
+
+#endif // __kptoolpen_h__
diff --git a/kolourpaint/tools/kptoolpolygon.cpp b/kolourpaint/tools/kptoolpolygon.cpp
new file mode 100644
index 00000000..fb68745c
--- /dev/null
+++ b/kolourpaint/tools/kptoolpolygon.cpp
@@ -0,0 +1,895 @@
+
+/*
+ Copyright (c) 2003,2004,2005 Clarence Dang <dang@kde.org>
+ 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 <kptoolpolygon.h>
+
+#include <float.h>
+#include <math.h>
+
+#include <qbitmap.h>
+#include <qcursor.h>
+#include <qlayout.h>
+#include <qpainter.h>
+#include <qpoint.h>
+#include <qpushbutton.h>
+#include <qrect.h>
+#include <qtooltip.h>
+#include <qvbuttongroup.h>
+
+#include <kdebug.h>
+#include <klocale.h>
+
+#include <kpcommandhistory.h>
+#include <kpdocument.h>
+#include <kpdefs.h>
+#include <kpmainwindow.h>
+#include <kppixmapfx.h>
+#include <kptemppixmap.h>
+#include <kptooltoolbar.h>
+#include <kptoolwidgetlinewidth.h>
+#include <kpviewmanager.h>
+
+
+#if DEBUG_KP_TOOL_POLYGON
+static const char *pointArrayToString (const QPointArray &pointArray)
+{
+ static char string [1000];
+ string [0] = '\0';
+
+ for (QPointArray::ConstIterator it = pointArray.begin ();
+ it != pointArray.end ();
+ it++)
+ {
+ QString ps = QString (" (%1, %2)").arg ((*it).x ()).arg ((*it).y ());
+ const char *pss = ps.latin1 ();
+ if (strlen (string) + strlen (pss) + 1 > sizeof (string) / sizeof (string [0]))
+ break;
+ strcat (string, pss);
+ }
+
+ return string;
+}
+#endif
+
+
+static QPen makeMaskPen (const kpColor &color, int lineWidth, Qt::PenStyle lineStyle)
+{
+ return QPen (color.maskColor (),
+ lineWidth == 1 ? 0/*closer to looking width 1*/ : lineWidth, lineStyle,
+ Qt::RoundCap, Qt::RoundJoin);
+}
+
+static QPen makePen (const kpColor &color, int lineWidth, Qt::PenStyle lineStyle)
+{
+ if (color.isOpaque ())
+ {
+ return QPen (color.toQColor (),
+ lineWidth == 1 ? 0/*closer to looking width 1*/ : lineWidth, lineStyle,
+ Qt::RoundCap, Qt::RoundJoin);
+ }
+ else
+ return Qt::NoPen;
+}
+
+static QBrush makeMaskBrush (const kpColor &foregroundColor,
+ const kpColor &backgroundColor,
+ kpToolWidgetFillStyle *toolWidgetFillStyle)
+{
+ if (toolWidgetFillStyle)
+ return toolWidgetFillStyle->maskBrush (foregroundColor, backgroundColor);
+ else
+ return Qt::NoBrush;
+}
+
+static QBrush makeBrush (const kpColor &foregroundColor,
+ const kpColor &backgroundColor,
+ kpToolWidgetFillStyle *toolWidgetFillStyle)
+{
+ if (toolWidgetFillStyle)
+ return toolWidgetFillStyle->brush (foregroundColor, backgroundColor);
+ else
+ return Qt::NoBrush;
+}
+
+static bool only1PixelInPointArray (const QPointArray &points)
+{
+ if (points.count () == 0)
+ return false;
+
+ for (int i = 1; i < (int) points.count (); i++)
+ {
+ if (points [i] != points [0])
+ return false;
+ }
+
+ return true;
+}
+
+static QPixmap pixmap (const QPixmap &oldPixmap,
+ const QPointArray &points, const QRect &rect,
+ const kpColor &foregroundColor, kpColor backgroundColor,
+ int lineWidth, Qt::PenStyle lineStyle,
+ kpToolWidgetFillStyle *toolWidgetFillStyle,
+ enum kpToolPolygon::Mode mode, bool final = true)
+{
+ //
+ // figure out points to draw relative to topLeft of oldPixmap
+
+ QPointArray pointsInRect = points;
+ pointsInRect.detach ();
+ pointsInRect.translate (-rect.x (), -rect.y ());
+
+#if DEBUG_KP_TOOL_POLYGON && 0
+ kdDebug () << "kptoolpolygon.cpp: pixmap(): points=" << pointArrayToString (points) << endl;
+#endif
+
+
+ //
+ // draw
+
+ QPen pen = makePen (foregroundColor, lineWidth, lineStyle),
+ maskPen = makeMaskPen (foregroundColor, lineWidth, lineStyle);
+ QBrush brush = makeBrush (foregroundColor, backgroundColor, toolWidgetFillStyle),
+ maskBrush = makeMaskBrush (foregroundColor, backgroundColor, toolWidgetFillStyle);
+
+ QPixmap pixmap = oldPixmap;
+ QBitmap maskBitmap;
+
+ QPainter painter, maskPainter;
+
+ if (pixmap.mask () ||
+ (maskPen.style () != Qt::NoPen &&
+ maskPen.color () == Qt::color0/*transparent*/) ||
+ (maskBrush.style () != Qt::NoBrush &&
+ maskBrush.color () == Qt::color0/*transparent*/))
+ {
+ maskBitmap = kpPixmapFX::getNonNullMask (pixmap);
+ maskPainter.begin (&maskBitmap);
+ maskPainter.setPen (maskPen);
+ maskPainter.setBrush (maskBrush);
+
+ #if DEBUG_KP_TOOL_POLYGON && 0
+ kdDebug () << "\tmaskPainter begin because:" << endl
+ << "\t\tpixmap.mask=" << pixmap.mask () << endl
+ << "\t\t(maskPenStyle!=NoPen)=" << (maskPen.style () != Qt::NoPen) << endl
+ << "\t\t(maskPenColor==trans)=" << (maskPen.color () == Qt::color0) << endl
+ << "\t\t(maskBrushStyle!=NoBrush)=" << (maskBrush.style () != Qt::NoBrush) << endl
+ << "\t\t(maskBrushColor==trans)=" << (maskBrush.color () == Qt::color0) << endl;
+ #endif
+ }
+
+ if (pen.style () != Qt::NoPen ||
+ brush.style () != Qt::NoBrush)
+ {
+ painter.begin (&pixmap);
+ painter.setPen (pen);
+ painter.setBrush (brush);
+
+ #if DEBUG_KP_TOOL_POLYGON && 0
+ kdDebug () << "\tpainter begin pen.rgb="
+ << (int *) painter.pen ().color ().rgb ()
+ << endl;
+ #endif
+ }
+
+#define PAINTER_CALL(cmd) \
+{ \
+ if (painter.isActive ()) \
+ painter . cmd ; \
+ \
+ if (maskPainter.isActive ()) \
+ maskPainter . cmd ; \
+}
+
+ // SYNC: Qt bug
+ if (only1PixelInPointArray (pointsInRect))
+ {
+ PAINTER_CALL (drawPoint (pointsInRect [0]));
+ }
+ else
+ {
+ switch (mode)
+ {
+ case kpToolPolygon::Line:
+ case kpToolPolygon::Polyline:
+ PAINTER_CALL (drawPolyline (pointsInRect));
+ break;
+ case kpToolPolygon::Polygon:
+ // TODO: why aren't the ends rounded?
+ PAINTER_CALL (drawPolygon (pointsInRect));
+
+ if (!final && 0/*HACK for TODO*/)
+ {
+ int count = pointsInRect.count ();
+
+ if (count > 2)
+ {
+ if (painter.isActive ())
+ {
+ QPen XORpen = painter.pen ();
+ XORpen.setColor (Qt::white);
+
+ painter.setPen (XORpen);
+ painter.setRasterOp (Qt::XorROP);
+ }
+
+ if (maskPainter.isActive ())
+ {
+ QPen XORpen = maskPainter.pen ();
+
+ // TODO???
+ #if 0
+ if (kpTool::isColorTransparent (foregroundColor))
+ XORpen.setColor (Qt::color1/*opaque*/);
+ else
+ XORpen.setColor (Qt::color0/*transparent*/);
+ #endif
+
+ maskPainter.setPen (XORpen);
+ }
+
+ PAINTER_CALL (drawLine (pointsInRect [0], pointsInRect [count - 1]));
+ }
+ }
+ break;
+ case kpToolPolygon::Curve:
+ int numPoints = pointsInRect.count ();
+ QPointArray pa (4);
+
+ pa [0] = pointsInRect [0];
+ pa [3] = pointsInRect [1];
+
+ switch (numPoints)
+ {
+ case 2:
+ pa [1] = pointsInRect [0];
+ pa [2] = pointsInRect [1];
+ break;
+ case 3:
+ pa [1] = pa [2] = pointsInRect [2];
+ break;
+ case 4:
+ pa [1] = pointsInRect [2];
+ pa [2] = pointsInRect [3];
+ }
+
+ PAINTER_CALL (drawCubicBezier (pa));
+ }
+ }
+#undef PAINTER_CALL
+
+ if (painter.isActive ())
+ painter.end ();
+
+ if (maskPainter.isActive ())
+ maskPainter.end ();
+
+ if (!maskBitmap.isNull ())
+ pixmap.setMask (maskBitmap);
+
+ return pixmap;
+}
+
+
+/*
+ * kpToolPolygon
+ */
+
+kpToolPolygon::kpToolPolygon (Mode mode,
+ const QString &text, const QString &description,
+ int key,
+ kpMainWindow *mainWindow, const char *name)
+ : kpTool (text, description, key, mainWindow, name),
+ m_mode (mode),
+ m_toolWidgetFillStyle (0),
+ m_toolWidgetLineWidth (0)
+{
+}
+
+kpToolPolygon::kpToolPolygon (kpMainWindow *mainWindow)
+ : kpTool (i18n ("Polygon"), i18n ("Draws polygons"),
+ Qt::Key_G,
+ mainWindow, "tool_polygon"),
+ m_mode (Polygon),
+ m_toolWidgetFillStyle (0),
+ m_toolWidgetLineWidth (0)
+{
+}
+
+kpToolPolygon::~kpToolPolygon ()
+{
+}
+
+void kpToolPolygon::setMode (Mode m)
+{
+ m_mode = m;
+}
+
+
+// private
+QString kpToolPolygon::haventBegunShapeUserMessage () const
+{
+ switch (m_mode)
+ {
+ case Line:
+ return i18n ("Drag to draw.");
+ case Polygon:
+ case Polyline:
+ return i18n ("Drag to draw the first line.");
+ case Curve:
+ return i18n ("Drag out the start and end points.");
+ default:
+ return QString::null;
+ }
+}
+
+// virtual
+void kpToolPolygon::begin ()
+{
+ kpToolToolBar *tb = toolToolBar ();
+
+#if DEBUG_KP_TOOL_POLYGON
+ kdDebug () << "kpToolPolygon::begin() tb=" << tb << endl;
+#endif
+
+ if (tb)
+ {
+ if (m_mode == Polygon)
+ m_toolWidgetFillStyle = tb->toolWidgetFillStyle ();
+ else
+ m_toolWidgetFillStyle = 0;
+
+ m_toolWidgetLineWidth = tb->toolWidgetLineWidth ();
+
+ if (m_toolWidgetFillStyle)
+ {
+ connect (m_toolWidgetFillStyle, SIGNAL (fillStyleChanged (kpToolWidgetFillStyle::FillStyle)),
+ this, SLOT (slotFillStyleChanged (kpToolWidgetFillStyle::FillStyle)));
+ }
+ connect (m_toolWidgetLineWidth, SIGNAL (lineWidthChanged (int)),
+ this, SLOT (slotLineWidthChanged (int)));
+
+ if (m_toolWidgetFillStyle)
+ m_toolWidgetFillStyle->show ();
+ m_toolWidgetLineWidth->show ();
+
+ m_lineWidth = m_toolWidgetLineWidth->lineWidth ();
+ }
+ else
+ {
+ m_toolWidgetFillStyle = 0;
+ m_toolWidgetLineWidth = 0;
+
+ m_lineWidth = 1;
+ }
+
+ viewManager ()->setCursor (QCursor (CrossCursor));
+
+ m_originatingMouseButton = -1;
+
+ setUserMessage (haventBegunShapeUserMessage ());
+}
+
+// virtual
+void kpToolPolygon::end ()
+{
+ endShape ();
+
+ if (m_toolWidgetFillStyle)
+ {
+ disconnect (m_toolWidgetFillStyle, SIGNAL (fillStyleChanged (kpToolWidgetFillStyle::FillStyle)),
+ this, SLOT (slotFillStyleChanged (kpToolWidgetFillStyle::FillStyle)));
+ m_toolWidgetFillStyle = 0;
+ }
+
+ if (m_toolWidgetLineWidth)
+ {
+ disconnect (m_toolWidgetLineWidth, SIGNAL (lineWidthChanged (int)),
+ this, SLOT (slotLineWidthChanged (int)));
+ m_toolWidgetLineWidth = 0;
+ }
+
+ viewManager ()->unsetCursor ();
+}
+
+
+void kpToolPolygon::beginDraw ()
+{
+#if DEBUG_KP_TOOL_POLYGON
+ kdDebug () << "kpToolPolygon::beginDraw() m_points=" << pointArrayToString (m_points)
+ << ", startPoint=" << m_startPoint << endl;
+#endif
+
+ bool endedShape = false;
+
+ // starting with a line...
+ if (m_points.count () == 0)
+ {
+ m_originatingMouseButton = m_mouseButton;
+ m_points.putPoints (m_points.count (), 2,
+ m_startPoint.x (), m_startPoint.y (),
+ m_startPoint.x (), m_startPoint.y ());
+ }
+ // continuing poly*
+ else
+ {
+ if (m_mouseButton != m_originatingMouseButton)
+ {
+ m_mouseButton = m_originatingMouseButton;
+ endShape ();
+ endedShape = true;
+ }
+ else
+ {
+ int count = m_points.count ();
+ m_points.putPoints (count, 1,
+ m_startPoint.x (), m_startPoint.y ());
+
+ // start point = last end point;
+ // _not_ the new/current start point
+ // (which is disregarded in a poly* as only the end points count
+ // after the initial line)
+ //
+ // Curve Tool ignores m_startPoint (doesn't call applyModifiers())
+ // after the initial has been defined.
+ m_startPoint = m_points [count - 1];
+ }
+ }
+
+#if DEBUG_KP_TOOL_POLYGON
+ kdDebug () << "\tafterwards, m_points=" << pointArrayToString (m_points) << endl;
+#endif
+
+ if (!endedShape)
+ {
+ switch (m_mode)
+ {
+ case Line:
+ case Curve:
+ case Polygon:
+ case Polyline:
+ setUserMessage (cancelUserMessage ());
+ break;
+
+ default:
+ kdError () << "kpToolPolygon::beginDraw() shape" << endl;
+ break;
+ }
+ }
+}
+
+// private
+void kpToolPolygon::applyModifiers ()
+{
+ int count = m_points.count ();
+
+ m_toolLineStartPoint = m_startPoint; /* also correct for poly* tool (see beginDraw()) */
+ m_toolLineEndPoint = m_currentPoint;
+
+#if DEBUG_KP_TOOL_POLYGON && 1
+ kdDebug () << "kpToolPolygon::applyModifiers() #pts=" << count
+ << " line: startPt=" << m_toolLineStartPoint
+ << " endPt=" << m_toolLineEndPoint
+ << " modifiers: shift=" << m_shiftPressed
+ << " alt=" << m_altPressed
+ << " ctrl=" << m_controlPressed
+ << endl;
+#endif
+
+ // angles
+ if (m_shiftPressed || m_controlPressed)
+ {
+ int diffx = m_toolLineEndPoint.x () - m_toolLineStartPoint.x ();
+ int diffy = m_toolLineEndPoint.y () - m_toolLineStartPoint.y ();
+
+ double ratio;
+ if (diffx == 0)
+ ratio = DBL_MAX;
+ else
+ ratio = fabs (double (diffy) / double (diffx));
+ #if DEBUG_KP_TOOL_POLYGON && 1
+ kdDebug () << "\tdiffx=" << diffx << " diffy=" << diffy
+ << " ratio=" << ratio
+ << endl;
+ #endif
+
+ // Shift = 0, 45, 90
+ // Alt = 0, 30, 60, 90
+ // Shift + Alt = 0, 30, 45, 60, 90
+ double angles [10]; // "ought to be enough for anybody"
+ int numAngles = 0;
+ angles [numAngles++] = 0;
+ if (m_controlPressed)
+ angles [numAngles++] = KP_PI / 6;
+ if (m_shiftPressed)
+ angles [numAngles++] = KP_PI / 4;
+ if (m_controlPressed)
+ angles [numAngles++] = KP_PI / 3;
+ angles [numAngles++] = KP_PI / 2;
+
+ double angle = angles [numAngles - 1];
+ for (int i = 0; i < numAngles - 1; i++)
+ {
+ double acceptingRatio = tan ((angles [i] + angles [i + 1]) / 2.0);
+ if (ratio < acceptingRatio)
+ {
+ angle = angles [i];
+ break;
+ }
+ }
+
+ // horizontal (dist from start !maintained)
+ if (fabs (KP_RADIANS_TO_DEGREES (angle) - 0)
+ < kpPixmapFX::AngleInDegreesEpsilon)
+ {
+ m_toolLineEndPoint = QPoint (m_toolLineEndPoint.x (), m_toolLineStartPoint.y ());
+ }
+ // vertical (dist from start !maintained)
+ else if (fabs (KP_RADIANS_TO_DEGREES (angle) - 90)
+ < kpPixmapFX::AngleInDegreesEpsilon)
+ {
+ m_toolLineEndPoint = QPoint (m_toolLineStartPoint.x (), m_toolLineEndPoint.y ());
+ }
+ // diagonal (dist from start maintained)
+ else
+ {
+ const double dist = sqrt (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
+
+ m_toolLineEndPoint = QPoint (m_toolLineStartPoint.x () + newdx,
+ m_toolLineStartPoint.y () + newdy);
+
+ #if DEBUG_KP_TOOL_POLYGON && 1
+ kdDebug () << "\t\tdiagonal line: dist=" << dist
+ << " angle=" << (angle * 180 / KP_PI)
+ << " endPoint=" << m_toolLineEndPoint
+ << endl;
+ #endif
+ }
+ } // if (m_shiftPressed || m_controlPressed) {
+
+ // centring
+ if (m_altPressed && 0/*ALT is unreliable*/)
+ {
+ // start = start - diff
+ // = start - (end - start)
+ // = start - end + start
+ // = 2 * start - end
+ if (count == 2)
+ m_toolLineStartPoint += (m_toolLineStartPoint - m_toolLineEndPoint);
+ else
+ m_toolLineEndPoint += (m_toolLineEndPoint - m_toolLineStartPoint);
+ } // if (m_altPressed) {
+
+ m_points [count - 2] = m_toolLineStartPoint;
+ m_points [count - 1] = m_toolLineEndPoint;
+
+ m_toolLineRect = kpTool::neededRect (QRect (m_toolLineStartPoint, m_toolLineEndPoint).normalize (),
+ m_lineWidth);
+}
+
+// virtual
+void kpToolPolygon::draw (const QPoint &, const QPoint &, const QRect &)
+{
+ if (m_points.count () == 0)
+ return;
+
+#if DEBUG_KP_TOOL_POLYGON
+ kdDebug () << "kpToolPolygon::draw() m_points=" << pointArrayToString (m_points)
+ << ", endPoint=" << m_currentPoint << endl;
+#endif
+
+ bool drawingALine = (m_mode != Curve) ||
+ (m_mode == Curve && m_points.count () == 2);
+
+ if (drawingALine)
+ applyModifiers ();
+ else
+ m_points [m_points.count () - 1] = m_currentPoint;
+
+#if DEBUG_KP_TOOL_POLYGON
+ kdDebug () << "\tafterwards, m_points=" << pointArrayToString (m_points) << endl;
+#endif
+
+ updateShape ();
+
+ if (drawingALine)
+ setUserShapePoints (m_toolLineStartPoint, m_toolLineEndPoint);
+ else
+ setUserShapePoints (m_currentPoint);
+}
+
+// private slot
+void kpToolPolygon::updateShape ()
+{
+ if (m_points.count () == 0)
+ return;
+
+ QRect boundingRect = kpTool::neededRect (m_points.boundingRect (), m_lineWidth);
+
+#if DEBUG_KP_TOOL_POLYGON
+ kdDebug () << "kpToolPolygon::updateShape() boundingRect="
+ << boundingRect
+ << " lineWidth="
+ << m_lineWidth
+ << endl;
+#endif
+
+ QPixmap oldPixmap = document ()->getPixmapAt (boundingRect);
+ QPixmap newPixmap = pixmap (oldPixmap,
+ m_points, boundingRect,
+ color (m_mouseButton), color (1 - m_mouseButton),
+ m_lineWidth, Qt::SolidLine,
+ m_toolWidgetFillStyle,
+ m_mode, false/*not final*/);
+
+ viewManager ()->setFastUpdates ();
+ viewManager ()->setTempPixmap (kpTempPixmap (false/*always display*/,
+ kpTempPixmap::SetPixmap/*render mode*/,
+ boundingRect.topLeft (),
+ newPixmap));
+ viewManager ()->restoreFastUpdates ();
+}
+
+// virtual
+void kpToolPolygon::cancelShape ()
+{
+#if 0
+ endDraw (QPoint (), QRect ());
+ commandHistory ()->undo ();
+#else
+ viewManager ()->invalidateTempPixmap ();
+#endif
+ m_points.resize (0);
+
+ setUserMessage (i18n ("Let go of all the mouse buttons."));
+}
+
+void kpToolPolygon::releasedAllButtons ()
+{
+ if (!hasBegunShape ())
+ setUserMessage (haventBegunShapeUserMessage ());
+
+ // --- else case already handled by endDraw() ---
+}
+
+// virtual
+void kpToolPolygon::endDraw (const QPoint &, const QRect &)
+{
+#if DEBUG_KP_TOOL_POLYGON
+ kdDebug () << "kpToolPolygon::endDraw() m_points=" << pointArrayToString (m_points) << endl;
+#endif
+
+ if (m_points.count () == 0)
+ return;
+
+ if (m_mode == Line ||
+ (m_mode == Curve && m_points.count () >= 4) ||
+ m_points.count () >= 50)
+ {
+ endShape ();
+ }
+ else
+ {
+ switch (m_mode)
+ {
+ case Line:
+ kdError () << "kpToolPolygon::endDraw() - line not ended" << endl;
+ setUserMessage ();
+ break;
+
+ case Polygon:
+ case Polyline:
+ if (m_points.isEmpty ())
+ {
+ kdError () << "kpToolPolygon::endDraw() exception - poly without points" << endl;
+ setUserMessage ();
+ }
+ else
+ {
+ if (m_mouseButton == 0)
+ {
+ setUserMessage (i18n ("Left drag another line or right click to finish."));
+ }
+ else
+ {
+ setUserMessage (i18n ("Right drag another line or left click to finish."));
+ }
+ }
+
+ break;
+
+ case Curve:
+ if (m_points.size () == 2)
+ {
+ if (m_mouseButton == 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."));
+ }
+ }
+ else if (m_points.size () == 3)
+ {
+ if (m_mouseButton == 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."));
+ }
+ }
+ else
+ {
+ kdError () << "kpToolPolygon::endDraw() exception - points" << endl;
+ setUserMessage ();
+ }
+
+ break;
+
+ default:
+ kdError () << "kpToolPolygon::endDraw() - clueless" << endl;
+ setUserMessage ();
+ break;
+ }
+ }
+}
+
+// public virtual
+void kpToolPolygon::endShape (const QPoint &, const QRect &)
+{
+#if DEBUG_KP_TOOL_POLYGON
+ kdDebug () << "kpToolPolygon::endShape() m_points=" << pointArrayToString (m_points) << endl;
+#endif
+
+ if (!hasBegunShape ())
+ return;
+
+ viewManager ()->invalidateTempPixmap ();
+
+ QRect boundingRect = kpTool::neededRect (m_points.boundingRect (), m_lineWidth);
+
+ kpToolPolygonCommand *lineCommand =
+ new kpToolPolygonCommand
+ (text (),
+ m_points, boundingRect,
+ color (m_mouseButton), color (1 - m_mouseButton),
+ m_lineWidth, Qt::SolidLine,
+ m_toolWidgetFillStyle,
+ document ()->getPixmapAt (boundingRect),
+ m_mode,
+ mainWindow ());
+
+ commandHistory ()->addCommand (lineCommand);
+
+ m_points.resize (0);
+ setUserMessage (haventBegunShapeUserMessage ());
+
+}
+
+// public virtual
+bool kpToolPolygon::hasBegunShape () const
+{
+ return (m_points.count () > 0);
+}
+
+
+// public slot
+void kpToolPolygon::slotLineWidthChanged (int width)
+{
+ m_lineWidth = width;
+ updateShape ();
+}
+
+// public slot
+void kpToolPolygon::slotFillStyleChanged (kpToolWidgetFillStyle::FillStyle /*fillStyle*/)
+{
+ updateShape ();
+}
+
+// virtual protected slot
+void kpToolPolygon::slotForegroundColorChanged (const kpColor &)
+{
+ updateShape ();
+}
+
+// virtual protected slot
+void kpToolPolygon::slotBackgroundColorChanged (const kpColor &)
+{
+ updateShape ();
+}
+
+
+/*
+ * kpToolPolygonCommand
+ */
+
+kpToolPolygonCommand::kpToolPolygonCommand (const QString &name,
+ const QPointArray &points,
+ const QRect &normalizedRect,
+ const kpColor &foregroundColor, const kpColor &backgroundColor,
+ int lineWidth, Qt::PenStyle lineStyle,
+ kpToolWidgetFillStyle *toolWidgetFillStyle,
+ const QPixmap &originalArea,
+ enum kpToolPolygon::Mode mode,
+ kpMainWindow *mainWindow)
+ : kpNamedCommand (name, mainWindow),
+ m_points (points),
+ m_normalizedRect (normalizedRect),
+ m_foregroundColor (foregroundColor), m_backgroundColor (backgroundColor),
+ m_lineWidth (lineWidth), m_lineStyle (lineStyle),
+ m_toolWidgetFillStyle (toolWidgetFillStyle),
+ m_originalArea (originalArea),
+ m_mode (mode)
+{
+ m_points.detach ();
+}
+
+kpToolPolygonCommand::~kpToolPolygonCommand ()
+{
+}
+
+
+// public virtual [base kpCommand]
+int kpToolPolygonCommand::size () const
+{
+ return kpPixmapFX::pointArraySize (m_points) +
+ kpPixmapFX::pixmapSize (m_originalArea);
+}
+
+
+// public virtual [base kpCommand]
+void kpToolPolygonCommand::execute ()
+{
+ QPixmap p = pixmap (m_originalArea,
+ m_points, m_normalizedRect,
+ m_foregroundColor, m_backgroundColor,
+ m_lineWidth, m_lineStyle,
+ m_toolWidgetFillStyle,
+ m_mode);
+ document ()->setPixmapAt (p, m_normalizedRect.topLeft ());
+}
+
+// public virtual [base kpCommand]
+void kpToolPolygonCommand::unexecute ()
+{
+ document ()->setPixmapAt (m_originalArea, m_normalizedRect.topLeft ());
+}
+
+#include <kptoolpolygon.moc>
diff --git a/kolourpaint/tools/kptoolpolygon.h b/kolourpaint/tools/kptoolpolygon.h
new file mode 100644
index 00000000..456dc4c0
--- /dev/null
+++ b/kolourpaint/tools/kptoolpolygon.h
@@ -0,0 +1,157 @@
+
+/*
+ Copyright (c) 2003,2004,2005 Clarence Dang <dang@kde.org>
+ 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 __kptoolpolygon_h__
+#define __kptoolpolygon_h__
+
+#include <qbrush.h>
+#include <qpen.h>
+#include <qobject.h>
+#include <qpixmap.h>
+#include <qpoint.h>
+#include <qpointarray.h>
+#include <qrect.h>
+
+#include <kpcommandhistory.h>
+
+#include <kpcolor.h>
+#include <kptool.h>
+#include <kptoolwidgetfillstyle.h>
+
+class QMouseEvent;
+class QPen;
+class QPoint;
+class QRect;
+class QString;
+
+class kpView;
+class kpDocument;
+class kpMainWindow;
+
+class kpToolWidgetFillStyle;
+class kpToolWidgetLineWidth;
+class kpViewManager;
+
+class kpToolPolygon : public kpTool
+{
+Q_OBJECT
+
+public:
+ enum Mode
+ {
+ Polygon, Polyline, Line, Curve
+ };
+
+ kpToolPolygon (Mode mode, const QString &text, const QString &description,
+ int key,
+ kpMainWindow *mainWindow, const char *name);
+ kpToolPolygon (kpMainWindow *mainWindow);
+ virtual ~kpToolPolygon ();
+
+ void setMode (Mode mode);
+
+ virtual bool careAboutModifierState () const { return true; }
+
+private:
+ QString haventBegunShapeUserMessage () const;
+
+public:
+ virtual void begin ();
+ virtual void end ();
+
+ virtual void beginDraw ();
+ virtual void draw (const QPoint &, const QPoint &, const QRect &);
+ virtual void cancelShape ();
+ virtual void releasedAllButtons ();
+ virtual void endDraw (const QPoint &, const QRect &);
+ virtual void endShape (const QPoint & = QPoint (), const QRect & = QRect ());
+
+ virtual bool hasBegunShape () const;
+
+public slots:
+ void slotLineWidthChanged (int width);
+ void slotFillStyleChanged (kpToolWidgetFillStyle::FillStyle fillStyle);
+
+protected slots:
+ virtual void slotForegroundColorChanged (const kpColor &);
+ virtual void slotBackgroundColorChanged (const kpColor &);
+
+private slots:
+ void updateShape ();
+
+private:
+ Mode m_mode;
+
+ kpToolWidgetFillStyle *m_toolWidgetFillStyle;
+
+ int m_lineWidth;
+ kpToolWidgetLineWidth *m_toolWidgetLineWidth;
+
+ int m_originatingMouseButton;
+
+ void applyModifiers ();
+
+ QPoint m_toolLineStartPoint, m_toolLineEndPoint;
+ QRect m_toolLineRect;
+
+ QPointArray m_points;
+};
+
+class kpToolPolygonCommand : public kpNamedCommand
+{
+public:
+ kpToolPolygonCommand (const QString &name,
+ const QPointArray &points,
+ const QRect &normalizedRect,
+ const kpColor &foregroundColor, const kpColor &backgroundColor,
+ int lineWidth, Qt::PenStyle lineStyle,
+ kpToolWidgetFillStyle *toolWidgetFillStyle,
+ const QPixmap &originalArea,
+ kpToolPolygon::Mode mode,
+ kpMainWindow *mainWindow);
+ virtual ~kpToolPolygonCommand ();
+
+ virtual int size () const;
+
+ virtual void execute ();
+ virtual void unexecute ();
+
+private:
+ QPointArray m_points;
+ QRect m_normalizedRect;
+
+ kpColor m_foregroundColor, m_backgroundColor;
+ int m_lineWidth;
+ Qt::PenStyle m_lineStyle;
+ kpToolWidgetFillStyle *m_toolWidgetFillStyle;
+
+ QPixmap m_originalArea;
+ kpToolPolygon::Mode m_mode;
+};
+
+#endif // __kptoolpolygon_h__
diff --git a/kolourpaint/tools/kptoolpolyline.cpp b/kolourpaint/tools/kptoolpolyline.cpp
new file mode 100644
index 00000000..6299b5b7
--- /dev/null
+++ b/kolourpaint/tools/kptoolpolyline.cpp
@@ -0,0 +1,47 @@
+
+/*
+ Copyright (c) 2003,2004,2005 Clarence Dang <dang@kde.org>
+ 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 <kptoolpolyline.h>
+
+#include <klocale.h>
+
+
+kpToolPolyline::kpToolPolyline (kpMainWindow *mainWindow)
+ : kpToolPolygon (Polyline,
+ i18n ("Connected Lines"),
+ i18n ("Draws connected lines"),
+ Qt::Key_N,
+ mainWindow, "tool_polyline")
+{
+}
+
+kpToolPolyline::~kpToolPolyline ()
+{
+}
+
+#include <kptoolpolyline.moc>
diff --git a/kolourpaint/tools/kptoolpolyline.h b/kolourpaint/tools/kptoolpolyline.h
new file mode 100644
index 00000000..f76a3959
--- /dev/null
+++ b/kolourpaint/tools/kptoolpolyline.h
@@ -0,0 +1,46 @@
+
+/*
+ Copyright (c) 2003,2004,2005 Clarence Dang <dang@kde.org>
+ 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 __kptoolpolyline_h__
+#define __kptoolpolyline_h__
+
+#include <kptoolpolygon.h>
+
+class kpMainWindow;
+
+class kpToolPolyline : public kpToolPolygon
+{
+Q_OBJECT
+
+public:
+ kpToolPolyline (kpMainWindow *);
+ virtual ~kpToolPolyline ();
+};
+
+#endif // __kptoolpolyline_h__
+
diff --git a/kolourpaint/tools/kptoolpreviewdialog.cpp b/kolourpaint/tools/kptoolpreviewdialog.cpp
new file mode 100644
index 00000000..23149232
--- /dev/null
+++ b/kolourpaint/tools/kptoolpreviewdialog.cpp
@@ -0,0 +1,431 @@
+
+/*
+ Copyright (c) 2003,2004,2005 Clarence Dang <dang@kde.org>
+ 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_PREVIEW_DIALOG 0
+
+#include <kptoolpreviewdialog.h>
+
+#include <qapplication.h>
+#include <qlayout.h>
+#include <qgroupbox.h>
+#include <qlabel.h>
+#include <qpushbutton.h>
+
+#include <kdebug.h>
+#include <klocale.h>
+
+#include <kpcolor.h>
+#include <kpdocument.h>
+#include <kpmainwindow.h>
+#include <kppixmapfx.h>
+#include <kpresizesignallinglabel.h>
+#include <kpselection.h>
+
+
+kpToolPreviewDialog::kpToolPreviewDialog (Features features,
+ bool reserveTopRow,
+ const QString &caption,
+ const QString &afterActionText,
+ bool actOnSelection,
+ kpMainWindow *parent,
+ const char *name)
+ : KDialogBase (parent, name, true/*modal*/,
+ caption,
+ KDialogBase::Ok | KDialogBase::Cancel),
+ m_afterActionText (afterActionText),
+ m_actOnSelection (actOnSelection),
+ m_mainWindow (parent),
+ m_dimensionsGroupBox (0),
+ m_afterTransformDimensionsLabel (0),
+ m_previewGroupBox (0),
+ m_previewPixmapLabel (0),
+ m_gridLayout (0)
+{
+ QWidget *baseWidget = new QWidget (this);
+ setMainWidget (baseWidget);
+
+
+ if (document ())
+ {
+ m_oldWidth = document ()->width (actOnSelection);
+ m_oldHeight = document ()->height (actOnSelection);
+ }
+ else
+ {
+ m_oldWidth = m_oldHeight = 1;
+ }
+
+
+ if (features & Dimensions)
+ createDimensionsGroupBox ();
+
+ if (features & Preview)
+ createPreviewGroupBox ();
+
+
+ m_gridLayout = new QGridLayout (baseWidget, 4, 2,
+ 0/*margin*/, spacingHint ());
+ 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->setColStretch (1, 1);
+ }
+ else if (m_dimensionsGroupBox)
+ {
+ m_gridLayout->addMultiCellWidget (m_dimensionsGroupBox,
+ m_gridNumRows, m_gridNumRows, 0, 1);
+ }
+ else if (m_previewGroupBox)
+ {
+ m_gridLayout->addMultiCellWidget (m_previewGroupBox,
+ m_gridNumRows, m_gridNumRows, 0, 1);
+ }
+
+ m_gridLayout->setRowStretch (m_gridNumRows, 1);
+ m_gridNumRows++;;
+ }
+}
+
+kpToolPreviewDialog::~kpToolPreviewDialog ()
+{
+}
+
+
+// private
+void kpToolPreviewDialog::createDimensionsGroupBox ()
+{
+ m_dimensionsGroupBox = new QGroupBox (i18n ("Dimensions"), mainWidget ());
+
+ QLabel *originalLabel = new QLabel (i18n ("Original:"), m_dimensionsGroupBox);
+ QString originalDimensions;
+ if (document ())
+ {
+ originalDimensions = i18n ("%1 x %2")
+ .arg (m_oldWidth)
+ .arg (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++)
+ originalDimensions += " ";
+ }
+ QLabel *originalDimensionsLabel = new QLabel (originalDimensions, m_dimensionsGroupBox);
+
+ QLabel *afterTransformLabel = new QLabel (m_afterActionText, m_dimensionsGroupBox);
+ m_afterTransformDimensionsLabel = new QLabel (m_dimensionsGroupBox);
+
+
+ QGridLayout *dimensionsLayout = new QGridLayout (m_dimensionsGroupBox,
+ 2, 2,
+ marginHint () * 2, spacingHint ());
+
+ 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 kpToolPreviewDialog::createPreviewGroupBox ()
+{
+ m_previewGroupBox = new QGroupBox (i18n ("Preview"), mainWidget ());
+
+ m_previewPixmapLabel = new kpResizeSignallingLabel (m_previewGroupBox);
+ m_previewPixmapLabel->setMinimumSize (150, 110);
+ connect (m_previewPixmapLabel, SIGNAL (resized ()),
+ this, SLOT (updatePreview ()));
+
+ QPushButton *updatePushButton = new QPushButton (i18n ("&Update"),
+ m_previewGroupBox);
+ connect (updatePushButton, SIGNAL (clicked ()),
+ this, SLOT (slotUpdateWithWaitCursor ()));
+
+
+ QVBoxLayout *previewLayout = new QVBoxLayout (m_previewGroupBox,
+ marginHint () * 2,
+ QMAX (1, spacingHint () / 2));
+
+ previewLayout->addWidget (m_previewPixmapLabel, 1/*stretch*/);
+ previewLayout->addWidget (updatePushButton, 0/*stretch*/, Qt::AlignHCenter);
+}
+
+
+// protected
+kpDocument *kpToolPreviewDialog::document () const
+{
+ return m_mainWindow ? m_mainWindow->document () : 0;
+}
+
+
+// protected
+void kpToolPreviewDialog::addCustomWidgetToFront (QWidget *w)
+{
+ m_gridLayout->addMultiCellWidget (w, 0, 0, 0, 1);
+}
+
+// protected
+void kpToolPreviewDialog::addCustomWidget (QWidget *w)
+{
+ m_gridLayout->addMultiCellWidget (w, m_gridNumRows, m_gridNumRows, 0, 1);
+ m_gridNumRows++;
+}
+
+
+// private
+void kpToolPreviewDialog::updateDimensions ()
+{
+ if (!m_dimensionsGroupBox)
+ return;
+
+ kpDocument *doc = document ();
+ if (!doc)
+ return;
+
+ QSize newDim = newDimensions ();
+#if DEBUG_KP_TOOL_PREVIEW_DIALOG
+ kdDebug () << "kpToolPreviewDialog::updateDimensions(): newDim=" << newDim << endl;
+#endif
+
+ QString newDimString = i18n ("%1 x %2")
+ .arg (newDim.width ())
+ .arg (newDim.height ());
+ m_afterTransformDimensionsLabel->setText (newDimString);
+}
+
+
+// public static
+double kpToolPreviewDialog::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 kpToolPreviewDialog::scaleDimension (int dimension, double scale, int min, int max)
+{
+ return QMAX (min,
+ QMIN (max,
+ qRound (dimension * scale)));
+}
+
+
+// private
+void kpToolPreviewDialog::updateShrukenDocumentPixmap ()
+{
+#if DEBUG_KP_TOOL_PREVIEW_DIALOG
+ kdDebug () << "kpToolPreviewDialog::updateShrukenDocumentPixmap()"
+ << " shrunkenDocPixmap.size="
+ << m_shrunkenDocumentPixmap.size ()
+ << " previewPixmapLabelSizeWhenUpdatedPixmap="
+ << m_previewPixmapLabelSizeWhenUpdatedPixmap
+ << " previewPixmapLabel.size="
+ << m_previewPixmapLabel->size ()
+ << endl;
+#endif
+
+ if (!m_previewGroupBox)
+ return;
+
+
+ kpDocument *doc = document ();
+ if (!doc || !doc->pixmap ())
+ {
+ kdError () << "kpToolPreviewDialog::updateShrunkenDocumentPixmap() doc="
+ << doc << endl;
+ return;
+ }
+
+ if (m_shrunkenDocumentPixmap.isNull () ||
+ m_previewPixmapLabel->size () != m_previewPixmapLabelSizeWhenUpdatedPixmap)
+ {
+ #if DEBUG_KP_TOOL_PREVIEW_DIALOG
+ kdDebug () << "\tupdating shrunkenDocPixmap" << endl;
+ #endif
+
+ // 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);
+
+ QPixmap pixmap;
+
+ if (m_actOnSelection)
+ {
+ kpSelection sel = *doc->selection ();
+ if (!sel.pixmap ())
+ sel.setPixmap (doc->getSelectedPixmap ());
+
+ pixmap = sel.transparentPixmap ();
+ }
+ else
+ {
+ pixmap = *doc->pixmap ();
+ }
+
+ m_shrunkenDocumentPixmap = kpPixmapFX::scale (
+ pixmap,
+ scaleDimension (m_oldWidth,
+ keepsAspectScale,
+ 1, m_previewPixmapLabel->width ()),
+ scaleDimension (m_oldHeight,
+ keepsAspectScale,
+ 1, m_previewPixmapLabel->height ()));
+ #if 0
+ m_shrunkenDocumentPixmap = kpPixmapFX::scale (
+ m_actOnSelection ? doc->getSelectedPixmap () : *doc->pixmap (),
+ m_previewPixmapLabel->width (),
+ m_previewPixmapLabel->height ());
+ #endif
+
+ m_previewPixmapLabelSizeWhenUpdatedPixmap = m_previewPixmapLabel->size ();
+ }
+}
+
+
+// private
+void kpToolPreviewDialog::updatePreview ()
+{
+#if DEBUG_KP_TOOL_PREVIEW_DIALOG
+ kdDebug () << "kpToolPreviewDialog::updatePreview()" << endl;
+#endif
+
+ if (!m_previewGroupBox)
+ return;
+
+
+ kpDocument *doc = document ();
+ if (!doc)
+ return;
+
+ updateShrukenDocumentPixmap ();
+
+ 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
+ QPixmap transformedShrunkenDocumentPixmap =
+ transformPixmap (m_shrunkenDocumentPixmap, targetWidth, targetHeight);
+
+ QPixmap previewPixmap (m_previewPixmapLabel->width (),
+ m_previewPixmapLabel->height ());
+ kpPixmapFX::fill (&previewPixmap, kpColor::transparent);
+ kpPixmapFX::setPixmapAt (&previewPixmap,
+ (previewPixmap.width () - transformedShrunkenDocumentPixmap.width ()) / 2,
+ (previewPixmap.height () - transformedShrunkenDocumentPixmap.height ()) / 2,
+ transformedShrunkenDocumentPixmap);
+
+#if DEBUG_KP_TOOL_PREVIEW_DIALOG
+ kdDebug () << "kpToolPreviewDialog::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 ()
+ << endl;
+#endif
+
+ m_previewPixmapLabel->setPixmap (previewPixmap);
+
+ // immediate update esp. for expensive previews
+ m_previewPixmapLabel->repaint (false/*no erase*/);
+
+#if DEBUG_KP_TOOL_PREVIEW_DIALOG
+ kdDebug () << "\tafter QLabel::setPixmap() previewPixmapLabel: w="
+ << m_previewPixmapLabel->width ()
+ << " h="
+ << m_previewPixmapLabel->height ()
+ << endl;
+#endif
+ }
+}
+
+
+// protected slot virtual
+void kpToolPreviewDialog::slotUpdate ()
+{
+#if DEBUG_KP_TOOL_PREVIEW_DIALOG
+ kdDebug () << "kpToolPreviewDialog::slotUpdate()" << endl;
+#endif
+ updateDimensions ();
+ updatePreview ();
+}
+
+// protected slot virtual
+void kpToolPreviewDialog::slotUpdateWithWaitCursor ()
+{
+#if DEBUG_KP_TOOL_PREVIEW_DIALOG
+ kdDebug () << "kpToolPreviewDialog::slotUpdateWithWaitCursor()"
+ << endl;
+#endif
+
+ QApplication::setOverrideCursor (Qt::waitCursor);
+
+ slotUpdate ();
+
+ QApplication::restoreOverrideCursor ();
+}
+
+
+#include <kptoolpreviewdialog.moc>
diff --git a/kolourpaint/tools/kptoolpreviewdialog.h b/kolourpaint/tools/kptoolpreviewdialog.h
new file mode 100644
index 00000000..35efdc38
--- /dev/null
+++ b/kolourpaint/tools/kptoolpreviewdialog.h
@@ -0,0 +1,131 @@
+
+/*
+ Copyright (c) 2003,2004,2005 Clarence Dang <dang@kde.org>
+ 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_preview_dialog_h__
+#define __kp_tool_preview_dialog_h__
+
+
+#include <qpixmap.h>
+
+#include <kdialogbase.h>
+
+
+class QLabel;
+class QGridLayout;
+class QGroupBox;
+
+class kpDocument;
+class kpMainWindow;
+class kpResizeSignallingLabel;
+
+
+class kpToolPreviewDialog : public KDialogBase
+{
+Q_OBJECT
+
+public:
+ enum Features
+ {
+ Dimensions = 1, Preview = 2,
+ AllFeatures = Dimensions | Preview
+ };
+
+ // You must call slotUpdate() in your constructor
+ kpToolPreviewDialog (Features features,
+ bool reserveTopRow,
+ // e.g. "Skew (Image|Selection)"
+ const QString &caption,
+ // (in the Dimensions Group Box) e.g. "After Skew:"
+ const QString &afterActionText,
+ bool actOnSelection,
+ kpMainWindow *parent,
+ const char *name = 0);
+ virtual ~kpToolPreviewDialog ();
+
+private:
+ void createDimensionsGroupBox ();
+ void createPreviewGroupBox ();
+
+public:
+ virtual bool isNoOp () const = 0;
+
+protected:
+ kpDocument *document () const;
+
+ // All widgets must have mainWidget() as their parent
+ void addCustomWidgetToFront (QWidget *w); // see <reserveTopRow> in ctor
+ void addCustomWidget (QWidget *w);
+ void addCustomWidgetToBack (QWidget *w)
+ {
+ addCustomWidget (w);
+ }
+
+ virtual QSize newDimensions () const = 0;
+ virtual QPixmap transformPixmap (const QPixmap &pixmap,
+ int targetWidth, int targetHeight) const = 0;
+
+private:
+ void updateDimensions ();
+
+public:
+ static double aspectScale (int newWidth, int newHeight,
+ int oldWidth, int oldHeight);
+ static int scaleDimension (int dimension, double scale, int min, int max);
+
+private:
+ void updateShrukenDocumentPixmap ();
+
+protected slots:
+ void updatePreview ();
+
+ // Call this whenever a value (e.g. an angle) changes
+ // and the Dimensions & Preview need to be updated
+ virtual void slotUpdate ();
+
+ virtual void slotUpdateWithWaitCursor ();
+
+protected:
+ QString m_afterActionText;
+ bool m_actOnSelection;
+ kpMainWindow *m_mainWindow;
+
+ int m_oldWidth, m_oldHeight;
+
+ QGroupBox *m_dimensionsGroupBox;
+ QLabel *m_afterTransformDimensionsLabel;
+
+ QGroupBox *m_previewGroupBox;
+ kpResizeSignallingLabel *m_previewPixmapLabel;
+ QSize m_previewPixmapLabelSizeWhenUpdatedPixmap;
+ QPixmap m_shrunkenDocumentPixmap;
+
+ QGridLayout *m_gridLayout;
+ int m_gridNumRows;
+};
+
+
+#endif // __kp_tool_preview_dialog_h__
diff --git a/kolourpaint/tools/kptoolrectangle.cpp b/kolourpaint/tools/kptoolrectangle.cpp
new file mode 100644
index 00000000..275db667
--- /dev/null
+++ b/kolourpaint/tools/kptoolrectangle.cpp
@@ -0,0 +1,638 @@
+
+/*
+ Copyright (c) 2003,2004,2005 Clarence Dang <dang@kde.org>
+ 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_RECTANGLE 0
+
+#include <qbitmap.h>
+#include <qcursor.h>
+#include <qevent.h>
+#include <qpainter.h>
+
+#include <kdebug.h>
+#include <klocale.h>
+
+#include <kpcolor.h>
+#include <kpcommandhistory.h>
+#include <kpdefs.h>
+#include <kpdocument.h>
+#include <kpmainwindow.h>
+#include <kppixmapfx.h>
+#include <kptemppixmap.h>
+#include <kptoolrectangle.h>
+#include <kptooltoolbar.h>
+#include <kptoolwidgetfillstyle.h>
+#include <kptoolwidgetlinewidth.h>
+#include <kpview.h>
+#include <kpviewmanager.h>
+
+static QPixmap pixmap (const kpToolRectangle::Mode mode,
+ kpDocument *document, const QRect &rect,
+ const QPoint &startPoint, const QPoint &endPoint,
+ const QPen &pen, const QPen &maskPen,
+ const QBrush &brush, const QBrush &maskBrush)
+{
+ QPixmap pixmap = document->getPixmapAt (rect);
+ QBitmap maskBitmap;
+
+ QPainter painter, maskPainter;
+
+#if DEBUG_KP_TOOL_RECTANGLE && 1
+ kdDebug () << "pixmap: rect=" << rect
+ << " startPoint=" << startPoint
+ << " endPoint=" << endPoint
+ << endl;
+ kdDebug () << "\tm: p=" << (maskPen.style () != Qt::NoPen)
+ << " b=" << (maskBrush.style () != Qt::NoBrush)
+ << " o: p=" << (pen.style () != Qt::NoPen)
+ << " b=" << (brush.style () != Qt::NoBrush)
+ << endl;
+ kdDebug () << "\tmaskPen.color()=" << (int *) maskPen.color ().rgb ()
+ << " transparent=" << (int *) Qt::color0.rgb ()/*transparent*/
+ << endl;
+#endif
+
+ if (pixmap.mask () ||
+ (maskPen.style () != Qt::NoPen &&
+ maskPen.color () == Qt::color0/*transparent*/) ||
+ (maskBrush.style () != Qt::NoBrush &&
+ maskBrush.color () == Qt::color0/*transparent*/))
+ {
+ maskBitmap = kpPixmapFX::getNonNullMask (pixmap);
+ maskPainter.begin (&maskBitmap);
+ maskPainter.setPen (maskPen);
+ maskPainter.setBrush (maskBrush);
+ }
+
+ if (pen.style () != Qt::NoPen ||
+ brush.style () != Qt::NoBrush)
+ {
+ painter.begin (&pixmap);
+ painter.setPen (pen);
+ painter.setBrush (brush);
+ }
+
+#define PAINTER_CALL(cmd) \
+{ \
+ if (painter.isActive ()) \
+ painter . cmd ; \
+ \
+ if (maskPainter.isActive ()) \
+ maskPainter . cmd ; \
+}
+
+ if (startPoint != endPoint)
+ {
+ #if DEBUG_KP_TOOL_RECTANGLE && 1
+ kdDebug () << "\tdraw shape" << endl;
+ #endif
+
+ // TODO: Rectangle of pen width 1, height 1 and width X is rendered
+ // as width X - 1.
+ switch (mode)
+ {
+ case kpToolRectangle::Rectangle:
+ PAINTER_CALL (drawRect (QRect (startPoint - rect.topLeft (), endPoint - rect.topLeft ())));
+ break;
+ case kpToolRectangle::RoundedRectangle:
+ PAINTER_CALL (drawRoundRect (QRect (startPoint - rect.topLeft (), endPoint - rect.topLeft ())));
+ break;
+ case kpToolRectangle::Ellipse:
+ PAINTER_CALL (drawEllipse (QRect (startPoint - rect.topLeft (), endPoint - rect.topLeft ())));
+ break;
+ default:
+ kdError () << "kptoolrectangle.cpp::pixmap() passed unknown mode: " << int (mode) << endl;
+ break;
+ }
+ }
+ else
+ {
+ #if DEBUG_KP_TOOL_RECTANGLE && 1
+ kdDebug () << "\tstartPoint == endPoint" << endl;
+ #endif
+ // SYNC: Work around Qt bug: can't draw 1x1 rectangle
+ // Not strictly correct for border width > 1
+ // but better than not drawing at all
+ PAINTER_CALL (drawPoint (startPoint - rect.topLeft ()));
+ }
+#undef PAINTER_CALL
+
+ if (painter.isActive ())
+ painter.end ();
+
+ if (maskPainter.isActive ())
+ maskPainter.end ();
+
+ if (!maskBitmap.isNull ())
+ pixmap.setMask (maskBitmap);
+
+ return pixmap;
+}
+
+
+/*
+ * kpToolRectangle
+ */
+
+kpToolRectangle::kpToolRectangle (Mode mode,
+ const QString &text,
+ const QString &description,
+ int key,
+ kpMainWindow *mainWindow,
+ const char *name)
+ : kpTool (text, description, key, mainWindow, name),
+ m_mode (mode),
+ m_toolWidgetLineWidth (0),
+ m_toolWidgetFillStyle (0)
+{
+}
+
+kpToolRectangle::kpToolRectangle (kpMainWindow *mainWindow)
+ : kpTool (i18n ("Rectangle"), i18n ("Draws rectangles and squares"),
+ Qt::Key_R,
+ mainWindow, "tool_rectangle"),
+ m_mode (Rectangle),
+ m_toolWidgetLineWidth (0),
+ m_toolWidgetFillStyle (0)
+{
+}
+
+kpToolRectangle::~kpToolRectangle ()
+{
+}
+
+void kpToolRectangle::setMode (Mode mode)
+{
+ m_mode = mode;
+}
+
+
+// private
+void kpToolRectangle::updatePens ()
+{
+ for (int i = 0; i < 2; i++)
+ updatePen (i);
+}
+
+// private
+void kpToolRectangle::updateBrushes ()
+{
+ for (int i = 0; i < 2; i++)
+ updateBrush (i);
+}
+
+// virtual private slot
+void kpToolRectangle::slotForegroundColorChanged (const kpColor &)
+{
+#if DEBUG_KP_TOOL_RECTANGLE
+ kdDebug () << "kpToolRectangle::slotForegroundColorChanged()" << endl;
+#endif
+ updatePen (0);
+ updateBrush (0); // brush may be in foreground color
+ updateBrush (1);
+}
+
+// virtual private slot
+void kpToolRectangle::slotBackgroundColorChanged (const kpColor &)
+{
+#if DEBUG_KP_TOOL_RECTANGLE
+ kdDebug () << "kpToolRectangle::slotBackgroundColorChanged()" << endl;
+ kdDebug () << "\tm_toolWidgetFillStyle=" << m_toolWidgetFillStyle << endl;
+#endif
+ updatePen (1);
+ updateBrush (0);
+ updateBrush (1); // brush may be in background color
+}
+
+// private
+void kpToolRectangle::updatePen (int mouseButton)
+{
+ QColor maskPenColor = color (mouseButton).maskColor ();
+
+ if (!m_toolWidgetLineWidth)
+ {
+ if (color (mouseButton).isOpaque ())
+ m_pen [mouseButton] = QPen (color (mouseButton).toQColor ());
+ else
+ m_pen [mouseButton] = Qt::NoPen;
+ m_maskPen [mouseButton] = QPen (maskPenColor);
+ }
+ else
+ {
+ if (color (mouseButton).isOpaque ())
+ {
+ m_pen [mouseButton] = QPen (color (mouseButton).toQColor (),
+ m_toolWidgetLineWidth->lineWidth (),
+ Qt::SolidLine);
+ }
+ else
+ m_pen [mouseButton] = Qt::NoPen;
+ m_maskPen [mouseButton] = QPen (maskPenColor,
+ m_toolWidgetLineWidth->lineWidth (),
+ Qt::SolidLine);
+ }
+}
+
+void kpToolRectangle::updateBrush (int mouseButton)
+{
+#if DEBUG_KP_TOOL_RECTANGLE
+ kdDebug () << "kpToolRectangle::brush () mouseButton=" << mouseButton
+ << " m_toolWidgetFillStyle=" << m_toolWidgetFillStyle
+ << endl;
+#endif
+ if (m_toolWidgetFillStyle)
+ {
+ m_brush [mouseButton] = m_toolWidgetFillStyle->brush (
+ color (mouseButton)/*foreground colour*/,
+ color (1 - mouseButton)/*background colour*/);
+
+ m_maskBrush [mouseButton] = m_toolWidgetFillStyle->maskBrush (
+ color (mouseButton)/*foreground colour*/,
+ color (1 - mouseButton)/*background colour*/);
+ }
+ else
+ {
+ m_brush [mouseButton] = Qt::NoBrush;
+ m_maskBrush [mouseButton] = Qt::NoBrush;
+ }
+}
+
+
+// private slot virtual
+void kpToolRectangle::slotLineWidthChanged ()
+{
+ updatePens ();
+
+ if (hasBegunDraw ())
+ updateShape ();
+}
+
+// private slot virtual
+void kpToolRectangle::slotFillStyleChanged ()
+{
+ updateBrushes ();
+
+ if (hasBegunDraw ())
+ updateShape ();
+}
+
+
+// private
+QString kpToolRectangle::haventBegunDrawUserMessage () const
+{
+ return i18n ("Drag to draw.");
+}
+
+// virtual
+void kpToolRectangle::begin ()
+{
+#if DEBUG_KP_TOOL_RECTANGLE
+ kdDebug () << "kpToolRectangle::begin ()" << endl;
+#endif
+
+ kpToolToolBar *tb = toolToolBar ();
+
+#if DEBUG_KP_TOOL_RECTANGLE
+ kdDebug () << "\ttoolToolBar=" << tb << endl;
+#endif
+
+ if (tb)
+ {
+ m_toolWidgetLineWidth = tb->toolWidgetLineWidth ();
+ connect (m_toolWidgetLineWidth, SIGNAL (lineWidthChanged (int)),
+ this, SLOT (slotLineWidthChanged ()));
+ m_toolWidgetLineWidth->show ();
+
+ updatePens ();
+
+
+ m_toolWidgetFillStyle = tb->toolWidgetFillStyle ();
+ connect (m_toolWidgetFillStyle, SIGNAL (fillStyleChanged (kpToolWidgetFillStyle::FillStyle)),
+ this, SLOT (slotFillStyleChanged ()));
+ m_toolWidgetFillStyle->show ();
+
+ updateBrushes ();
+ }
+
+#if DEBUG_KP_TOOL_RECTANGLE
+ kdDebug () << "\t\tm_toolWidgetFillStyle=" << m_toolWidgetFillStyle << endl;
+#endif
+
+ viewManager ()->setCursor (QCursor (CrossCursor));
+
+ setUserMessage (haventBegunDrawUserMessage ());
+}
+
+// virtual
+void kpToolRectangle::end ()
+{
+#if DEBUG_KP_TOOL_RECTANGLE
+ kdDebug () << "kpToolRectangle::end ()" << endl;
+#endif
+
+ if (m_toolWidgetLineWidth)
+ {
+ disconnect (m_toolWidgetLineWidth, SIGNAL (lineWidthChanged (int)),
+ this, SLOT (slotLineWidthChanged ()));
+ m_toolWidgetLineWidth = 0;
+ }
+
+ if (m_toolWidgetFillStyle)
+ {
+ disconnect (m_toolWidgetFillStyle, SIGNAL (fillStyleChanged (kpToolWidgetFillStyle::FillStyle)),
+ this, SLOT (slotFillStyleChanged ()));
+ m_toolWidgetFillStyle = 0;
+ }
+
+ viewManager ()->unsetCursor ();
+}
+
+void kpToolRectangle::applyModifiers ()
+{
+ QRect rect = QRect (m_startPoint, m_currentPoint).normalize ();
+
+#if DEBUG_KP_TOOL_RECTANGLE
+ kdDebug () << "kpToolRectangle::applyModifiers(" << rect
+ << ") shift=" << m_shiftPressed
+ << " ctrl=" << m_controlPressed
+ << endl;
+#endif
+
+ // user wants to m_startPoint == centre
+ if (m_controlPressed)
+ {
+ int xdiff = kAbs (m_startPoint.x () - m_currentPoint.x ());
+ int ydiff = kAbs (m_startPoint.y () - m_currentPoint.y ());
+ rect = QRect (m_startPoint.x () - xdiff, m_startPoint.y () - ydiff,
+ xdiff * 2 + 1, ydiff * 2 + 1);
+ }
+
+ // user wants major axis == minor axis:
+ // rectangle --> square
+ // rounded rectangle --> rounded square
+ // ellipse --> circle
+ if (m_shiftPressed)
+ {
+ if (!m_controlPressed)
+ {
+ if (rect.width () < rect.height ())
+ {
+ if (m_startPoint.y () == rect.y ())
+ rect.setHeight (rect.width ());
+ else
+ rect.setY (rect.bottom () - rect.width () + 1);
+ }
+ else
+ {
+ if (m_startPoint.x () == rect.x ())
+ rect.setWidth (rect.height ());
+ else
+ rect.setX (rect.right () - rect.height () + 1);
+ }
+ }
+ // have to maintain the centre
+ 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);
+ }
+ }
+ }
+
+ m_toolRectangleStartPoint = rect.topLeft ();
+ m_toolRectangleEndPoint = rect.bottomRight ();
+
+ m_toolRectangleRectWithoutLineWidth = rect;
+ m_toolRectangleRect = kpTool::neededRect (rect, QMAX (m_pen [m_mouseButton].width (),
+ m_maskPen [m_mouseButton].width ()));
+}
+
+void kpToolRectangle::beginDraw ()
+{
+ setUserMessage (cancelUserMessage ());
+}
+
+void kpToolRectangle::updateShape ()
+{
+ viewManager ()->setFastUpdates ();
+
+ QPixmap newPixmap = pixmap (m_mode, document (), m_toolRectangleRect,
+ m_toolRectangleStartPoint, m_toolRectangleEndPoint,
+ m_pen [m_mouseButton], m_maskPen [m_mouseButton],
+ m_brush [m_mouseButton], m_maskBrush [m_mouseButton]);
+ kpTempPixmap newTempPixmap (false/*always display*/,
+ kpTempPixmap::SetPixmap/*render mode*/,
+ m_toolRectangleRect.topLeft (),
+ newPixmap);
+ viewManager ()->setTempPixmap (newTempPixmap);
+
+ viewManager ()->restoreFastUpdates ();
+}
+
+void kpToolRectangle::draw (const QPoint &, const QPoint &, const QRect &)
+{
+ applyModifiers ();
+
+
+ updateShape ();
+
+
+ // Recover the start and end points from the transformed & normalized m_toolRectangleRect
+
+ // S. or S or SC or S == C
+ // .C C
+ if (m_currentPoint.x () >= m_startPoint.x () &&
+ m_currentPoint.y () >= m_startPoint.y ())
+ {
+ setUserShapePoints (m_toolRectangleRectWithoutLineWidth.topLeft (),
+ m_toolRectangleRectWithoutLineWidth.bottomRight ());
+ }
+ // .C or C
+ // S. S
+ else if (m_currentPoint.x () >= m_startPoint.x () &&
+ m_currentPoint.y () < m_startPoint.y ())
+ {
+ setUserShapePoints (m_toolRectangleRectWithoutLineWidth.bottomLeft (),
+ m_toolRectangleRectWithoutLineWidth.topRight ());
+ }
+ // .S or CS
+ // C.
+ else if (m_currentPoint.x () < m_startPoint.x () &&
+ m_currentPoint.y () >= m_startPoint.y ())
+ {
+ setUserShapePoints (m_toolRectangleRectWithoutLineWidth.topRight (),
+ m_toolRectangleRectWithoutLineWidth.bottomLeft ());
+ }
+ // C.
+ // .S
+ else
+ {
+ setUserShapePoints (m_toolRectangleRectWithoutLineWidth.bottomRight (),
+ m_toolRectangleRectWithoutLineWidth.topLeft ());
+ }
+}
+
+void kpToolRectangle::cancelShape ()
+{
+#if 0
+ endDraw (m_currentPoint, QRect (m_startPoint, m_currentPoint).normalize ());
+ mainWindow ()->commandHistory ()->undo ();
+#else
+ viewManager ()->invalidateTempPixmap ();
+#endif
+
+ setUserMessage (i18n ("Let go of all the mouse buttons."));
+}
+
+void kpToolRectangle::releasedAllButtons ()
+{
+ setUserMessage (haventBegunDrawUserMessage ());
+}
+
+void kpToolRectangle::endDraw (const QPoint &, const QRect &)
+{
+ applyModifiers ();
+
+ // TODO: flicker
+ viewManager ()->invalidateTempPixmap ();
+
+ mainWindow ()->commandHistory ()->addCommand (
+ new kpToolRectangleCommand
+ (m_mode,
+ m_pen [m_mouseButton], m_maskPen [m_mouseButton],
+ m_brush [m_mouseButton], m_maskBrush [m_mouseButton],
+ m_toolRectangleRect, m_toolRectangleStartPoint, m_toolRectangleEndPoint,
+ mainWindow ()));
+
+ setUserMessage (haventBegunDrawUserMessage ());
+}
+
+
+/*
+ * kpToolRectangleCommand
+ */
+
+kpToolRectangleCommand::kpToolRectangleCommand (kpToolRectangle::Mode mode,
+ const QPen &pen, const QPen &maskPen,
+ const QBrush &brush, const QBrush &maskBrush,
+ const QRect &rect,
+ const QPoint &startPoint, const QPoint &endPoint,
+ kpMainWindow *mainWindow)
+ : kpCommand (mainWindow),
+ m_mode (mode),
+ m_pen (pen), m_maskPen (maskPen),
+ m_brush (brush), m_maskBrush (maskBrush),
+ m_rect (rect),
+ m_startPoint (startPoint),
+ m_endPoint (endPoint),
+ m_oldPixmapPtr (0)
+{
+}
+
+kpToolRectangleCommand::~kpToolRectangleCommand ()
+{
+ delete m_oldPixmapPtr;
+}
+
+
+// public virtual [base kpCommand]
+QString kpToolRectangleCommand::name () const
+{
+ switch (m_mode)
+ {
+ case kpToolRectangle::Rectangle:
+ return i18n ("Rectangle");
+ case kpToolRectangle::RoundedRectangle:
+ return i18n ("Rounded Rectangle");
+ case kpToolRectangle::Ellipse:
+ return i18n ("Ellipse");
+ default:
+ kdError () << "kpToolRectangleCommand::name() passed unknown mode: " << int (m_mode) << endl;
+ return QString::null;
+ }
+}
+
+
+// public virtual [base kpCommand]
+int kpToolRectangleCommand::size () const
+{
+ return kpPixmapFX::pixmapSize (m_oldPixmapPtr);
+}
+
+
+// public virtual [base kpCommand]
+void kpToolRectangleCommand::execute ()
+{
+ kpDocument *doc = document ();
+ if (!doc)
+ return;
+
+ // store Undo info
+ if (!m_oldPixmapPtr)
+ {
+ // OPT: I can do better with no brush
+ m_oldPixmapPtr = new QPixmap ();
+ *m_oldPixmapPtr = doc->getPixmapAt (m_rect);
+ }
+ else
+ kdError () << "kpToolRectangleCommand::execute() m_oldPixmapPtr not null" << endl;
+
+ doc->setPixmapAt (pixmap (m_mode, doc,
+ m_rect, m_startPoint, m_endPoint,
+ m_pen, m_maskPen,
+ m_brush, m_maskBrush),
+ m_rect.topLeft ());
+}
+
+// public virtual [base kpCommand]
+void kpToolRectangleCommand::unexecute ()
+{
+ kpDocument *doc = document ();
+ if (!doc)
+ return;
+
+ if (m_oldPixmapPtr)
+ {
+ doc->setPixmapAt (*m_oldPixmapPtr, m_rect.topLeft ());
+
+ delete m_oldPixmapPtr;
+ m_oldPixmapPtr = 0;
+ }
+ else
+ kdError () << "kpToolRectangleCommand::unexecute() m_oldPixmapPtr null" << endl;
+}
+
+#include <kptoolrectangle.moc>
diff --git a/kolourpaint/tools/kptoolrectangle.h b/kolourpaint/tools/kptoolrectangle.h
new file mode 100644
index 00000000..0fcf5ff4
--- /dev/null
+++ b/kolourpaint/tools/kptoolrectangle.h
@@ -0,0 +1,142 @@
+
+/*
+ Copyright (c) 2003,2004,2005 Clarence Dang <dang@kde.org>
+ 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 __kptoolrectangle_h__
+#define __kptoolrectangle_h__
+
+#include <qbrush.h>
+#include <qpen.h>
+#include <qpixmap.h>
+#include <qpoint.h>
+#include <qrect.h>
+
+#include <kpcommandhistory.h>
+
+#include <kptool.h>
+
+class QString;
+
+class kpColor;
+class kpMainWindow;
+class kpToolWidgetFillStyle;
+class kpToolWidgetLineWidth;
+class kpViewManager;
+
+class kpToolRectangle : public kpTool
+{
+Q_OBJECT
+
+public:
+ // it turns out that these shapes are all really the same thing
+ // (same options, same feel) - the only real difference is the
+ // drawing functions (a one line change)
+ enum Mode {Rectangle, RoundedRectangle, Ellipse};
+
+ kpToolRectangle (Mode mode,
+ const QString &text, const QString &description,
+ int key,
+ kpMainWindow *mainWindow,
+ const char *name);
+ kpToolRectangle (kpMainWindow *);
+ virtual ~kpToolRectangle ();
+
+ void setMode (Mode mode);
+
+ virtual bool careAboutModifierState () const { return true; }
+
+private:
+ QString haventBegunDrawUserMessage () const;
+
+public:
+ virtual void begin ();
+ virtual void end ();
+
+ virtual void beginDraw ();
+private:
+ void updateShape ();
+public:
+ virtual void draw (const QPoint &, const QPoint &, const QRect &);
+ virtual void cancelShape ();
+ virtual void releasedAllButtons ();
+ virtual void endDraw (const QPoint &, const QRect &);
+
+private slots:
+ void updatePens ();
+ void updateBrushes ();
+
+ virtual void slotForegroundColorChanged (const kpColor &);
+ virtual void slotBackgroundColorChanged (const kpColor &);
+
+ virtual void slotLineWidthChanged ();
+ virtual void slotFillStyleChanged ();
+
+private:
+ Mode m_mode;
+
+ kpToolWidgetLineWidth *m_toolWidgetLineWidth;
+ kpToolWidgetFillStyle *m_toolWidgetFillStyle;
+
+ void updatePen (int mouseButton);
+ QPen m_pen [2], m_maskPen [2];
+
+ void updateBrush (int mouseButton);
+ QBrush m_brush [2], m_maskBrush [2];
+
+ void applyModifiers ();
+ QPoint m_toolRectangleStartPoint, m_toolRectangleEndPoint;
+ QRect m_toolRectangleRectWithoutLineWidth, m_toolRectangleRect;
+};
+
+class kpToolRectangleCommand : public kpCommand
+{
+public:
+ kpToolRectangleCommand (kpToolRectangle::Mode mode,
+ const QPen &pen, const QPen &maskPen,
+ const QBrush &brush, const QBrush &maskBrush,
+ const QRect &rect,
+ const QPoint &startPoint, const QPoint &endPoint,
+ kpMainWindow *mainWindow);
+ virtual ~kpToolRectangleCommand ();
+
+ virtual QString name () const;
+
+ virtual int size () const;
+
+ virtual void execute ();
+ virtual void unexecute ();
+
+private:
+ kpToolRectangle::Mode m_mode;
+ QPen m_pen, m_maskPen;
+ QBrush m_brush, m_maskBrush;
+ QRect m_rect;
+ QPoint m_startPoint, m_endPoint;
+ QPixmap *m_oldPixmapPtr;
+};
+
+#endif // __kptoolrectangle_h__
diff --git a/kolourpaint/tools/kptoolrectselection.cpp b/kolourpaint/tools/kptoolrectselection.cpp
new file mode 100644
index 00000000..3726cbfe
--- /dev/null
+++ b/kolourpaint/tools/kptoolrectselection.cpp
@@ -0,0 +1,46 @@
+
+/*
+ Copyright (c) 2003,2004,2005 Clarence Dang <dang@kde.org>
+ 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 <kptoolrectselection.h>
+
+#include <klocale.h>
+
+
+kpToolRectSelection::kpToolRectSelection (kpMainWindow *mainWindow)
+ : kpToolSelection (Rectangle,
+ i18n ("Selection (Rectangular)"),
+ i18n ("Makes a rectangular selection"),
+ Qt::Key_S,
+ mainWindow, "tool_rect_selection")
+{
+}
+
+kpToolRectSelection::~kpToolRectSelection ()
+{
+}
+
diff --git a/kolourpaint/tools/kptoolrectselection.h b/kolourpaint/tools/kptoolrectselection.h
new file mode 100644
index 00000000..0d66b7a5
--- /dev/null
+++ b/kolourpaint/tools/kptoolrectselection.h
@@ -0,0 +1,43 @@
+
+/*
+ Copyright (c) 2003,2004,2005 Clarence Dang <dang@kde.org>
+ 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 __kptoolrectselection_h__
+#define __kptoolrectselection_h__
+
+#include <kptoolselection.h>
+
+class kpMainWindow;
+
+class kpToolRectSelection : public kpToolSelection
+{
+public:
+ kpToolRectSelection (kpMainWindow *);
+ virtual ~kpToolRectSelection ();
+};
+
+#endif // __kptoolrectselection_h__
diff --git a/kolourpaint/tools/kptoolresizescale.cpp b/kolourpaint/tools/kptoolresizescale.cpp
new file mode 100644
index 00000000..ce9c9059
--- /dev/null
+++ b/kolourpaint/tools/kptoolresizescale.cpp
@@ -0,0 +1,1222 @@
+
+/*
+ Copyright (c) 2003,2004,2005 Clarence Dang <dang@kde.org>
+ 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 <kptoolresizescale.h>
+
+#include <math.h>
+
+#include <qaccel.h>
+#include <qapplication.h>
+#include <qbuttongroup.h>
+#include <qcheckbox.h>
+#include <qgroupbox.h>
+#include <qhbox.h>
+#include <qlabel.h>
+#include <qlayout.h>
+#include <qpoint.h>
+#include <qpointarray.h>
+#include <qpushbutton.h>
+#include <qrect.h>
+#include <qsize.h>
+#include <qtoolbutton.h>
+#include <qwhatsthis.h>
+#include <qwmatrix.h>
+
+#include <kapplication.h>
+#include <kcombobox.h>
+#include <kconfig.h>
+#include <kdebug.h>
+#include <kglobal.h>
+#include <kiconeffect.h>
+#include <kiconloader.h>
+#include <klocale.h>
+#include <knuminput.h>
+
+#include <kpdefs.h>
+#include <kpdocument.h>
+#include <kpmainwindow.h>
+#include <kppixmapfx.h>
+#include <kpselection.h>
+#include <kptool.h>
+
+
+/*
+ * kpToolResizeScaleCommand
+ */
+
+kpToolResizeScaleCommand::kpToolResizeScaleCommand (bool actOnSelection,
+ int newWidth, int newHeight,
+ Type type,
+ kpMainWindow *mainWindow)
+ : kpCommand (mainWindow),
+ m_actOnSelection (actOnSelection),
+ m_type (type),
+ m_backgroundColor (mainWindow ? mainWindow->backgroundColor () : kpColor::invalid),
+ m_oldSelection (0)
+{
+ kpDocument *doc = document ();
+
+ m_oldWidth = doc->width (m_actOnSelection);
+ m_oldHeight = doc->height (m_actOnSelection);
+
+ m_actOnTextSelection = (m_actOnSelection &&
+ doc && doc->selection () &&
+ doc->selection ()->isText ());
+
+ 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 ()->pixmap ());
+}
+
+kpToolResizeScaleCommand::~kpToolResizeScaleCommand ()
+{
+ delete m_oldSelection;
+}
+
+
+// public virtual [base kpCommand]
+QString kpToolResizeScaleCommand::name () const
+{
+ if (m_actOnSelection)
+ {
+ if (m_actOnTextSelection)
+ {
+ if (m_type == Resize)
+ return i18n ("Text: Resize Box");
+ }
+ else
+ {
+ if (m_type == Scale)
+ return i18n ("Selection: Scale");
+ else 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::null;
+}
+
+// public virtual [base kpCommand]
+int kpToolResizeScaleCommand::size () const
+{
+ return kpPixmapFX::pixmapSize (m_oldPixmap) +
+ kpPixmapFX::pixmapSize (m_oldRightPixmap) +
+ kpPixmapFX::pixmapSize (m_oldBottomPixmap) +
+ (m_oldSelection ? m_oldSelection->size () : 0);
+}
+
+
+// public
+int kpToolResizeScaleCommand::newWidth () const
+{
+ return m_newWidth;
+}
+
+// public
+void kpToolResizeScaleCommand::setNewWidth (int width)
+{
+ resize (width, newHeight ());
+}
+
+
+// public
+int kpToolResizeScaleCommand::newHeight () const
+{
+ return m_newHeight;
+}
+
+// public
+void kpToolResizeScaleCommand::setNewHeight (int height)
+{
+ resize (newWidth (), height);
+}
+
+
+// public
+QSize kpToolResizeScaleCommand::newSize () const
+{
+ return QSize (newWidth (), newHeight ());
+}
+
+// public virtual
+void kpToolResizeScaleCommand::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 kpToolResizeScaleCommand::scaleSelectionWithImage () const
+{
+ return m_scaleSelectionWithImage;
+}
+
+
+// private
+void kpToolResizeScaleCommand::scaleSelectionRegionWithDocument ()
+{
+#if DEBUG_KP_TOOL_RESIZE_SCALE_COMMAND
+ kdDebug () << "kpToolResizeScaleCommand::scaleSelectionRegionWithDocument"
+ << endl;
+#endif
+
+ if (!m_oldSelection)
+ {
+ kdError () << "kpToolResizeScaleCommand::scaleSelectionRegionWithDocument()"
+ << " without old sel" << endl;
+ return;
+ }
+
+ if (m_oldSelection->pixmap ())
+ {
+ kdError () << "kpToolResizeScaleCommand::scaleSelectionRegionWithDocument()"
+ << " old sel has pixmap" << endl;
+ return;
+ }
+
+
+ const double horizScale = double (m_newWidth) / double (m_oldWidth);
+ const double vertScale = double (m_newHeight) / double (m_oldHeight);
+
+ const int newX = (int) (m_oldSelection->x () * horizScale);
+ const int newY = (int) (m_oldSelection->y () * vertScale);
+
+
+ QPointArray currentPoints = m_oldSelection->points ();
+ currentPoints.detach ();
+
+ currentPoints.translate (-currentPoints.boundingRect ().x (),
+ -currentPoints.boundingRect ().y ());
+
+ // TODO: refactor into kpPixmapFX
+ QWMatrix scaleMatrix;
+ scaleMatrix.scale (horizScale, vertScale);
+ currentPoints = scaleMatrix.map (currentPoints);
+
+ currentPoints.translate (
+ -currentPoints.boundingRect ().x () + newX,
+ -currentPoints.boundingRect ().y () + newY);
+
+ document ()->setSelection (kpSelection (currentPoints, QPixmap (),
+ m_oldSelection->transparency ()));
+
+
+ if (m_mainWindow->tool ())
+ m_mainWindow->tool ()->somethingBelowTheCursorChanged ();
+}
+
+
+// public virtual [base kpCommand]
+void kpToolResizeScaleCommand::execute ()
+{
+#if DEBUG_KP_TOOL_RESIZE_SCALE_COMMAND
+ kdDebug () << "kpToolResizeScaleCommand::execute() type="
+ << (int) m_type
+ << " oldWidth=" << m_oldWidth
+ << " oldHeight=" << m_oldHeight
+ << " newWidth=" << m_newWidth
+ << " newHeight=" << m_newHeight
+ << endl;
+#endif
+
+ if (m_oldWidth == m_newWidth && m_oldHeight == m_newHeight)
+ return;
+
+ if (m_type == Resize)
+ {
+ if (m_actOnSelection)
+ {
+ if (!m_actOnTextSelection)
+ {
+ kdError () << "kpToolResizeScaleCommand::execute() resizing sel doesn't make sense" << endl;
+ return;
+ }
+ else
+ {
+ QApplication::setOverrideCursor (Qt::waitCursor);
+ document ()->selection ()->textResize (m_newWidth, m_newHeight);
+
+ if (m_mainWindow->tool ())
+ m_mainWindow->tool ()->somethingBelowTheCursorChanged ();
+
+ QApplication::restoreOverrideCursor ();
+ }
+ }
+ else
+ {
+ QApplication::setOverrideCursor (Qt::waitCursor);
+
+
+ if (m_newWidth < m_oldWidth)
+ {
+ m_oldRightPixmap = kpPixmapFX::getPixmapAt (
+ *document ()->pixmap (),
+ QRect (m_newWidth, 0,
+ m_oldWidth - m_newWidth, m_oldHeight));
+ }
+
+ if (m_newHeight < m_oldHeight)
+ {
+ m_oldBottomPixmap = kpPixmapFX::getPixmapAt (
+ *document ()->pixmap (),
+ QRect (0, m_newHeight,
+ m_newWidth, m_oldHeight - m_newHeight));
+ }
+
+ document ()->resize (m_newWidth, m_newHeight, m_backgroundColor);
+
+
+ QApplication::restoreOverrideCursor ();
+ }
+ }
+ else
+ {
+ QApplication::setOverrideCursor (Qt::waitCursor);
+
+
+ QPixmap oldPixmap = *document ()->pixmap (m_actOnSelection);
+
+ if (!m_isLosslessScale)
+ m_oldPixmap = oldPixmap;
+
+ QPixmap newPixmap = kpPixmapFX::scale (oldPixmap, m_newWidth, m_newHeight,
+ m_type == SmoothScale);
+
+
+ if (!m_oldSelection && document ()->selection ())
+ {
+ // Save sel border
+ m_oldSelection = new kpSelection (*document ()->selection ());
+ m_oldSelection->setPixmap (QPixmap ());
+ }
+
+ if (m_actOnSelection)
+ {
+ QRect newRect = QRect (m_oldSelection->x (), m_oldSelection->y (),
+ newPixmap.width (), newPixmap.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)
+ document ()->setSelection (
+ kpSelection (kpSelection::Rectangle, newRect, newPixmap,
+ m_oldSelection->transparency ()));
+
+ if (m_mainWindow->tool ())
+ m_mainWindow->tool ()->somethingBelowTheCursorChanged ();
+ }
+ else
+ {
+ document ()->setPixmap (newPixmap);
+
+ if (m_scaleSelectionWithImage)
+ {
+ scaleSelectionRegionWithDocument ();
+ }
+ }
+
+
+ QApplication::restoreOverrideCursor ();
+ }
+}
+
+// public virtual [base kpCommand]
+void kpToolResizeScaleCommand::unexecute ()
+{
+#if DEBUG_KP_TOOL_RESIZE_SCALE_COMMAND
+ kdDebug () << "kpToolResizeScaleCommand::unexecute() type="
+ << m_type << endl;
+#endif
+
+ if (m_oldWidth == m_newWidth && m_oldHeight == m_newHeight)
+ return;
+
+ kpDocument *doc = document ();
+ if (!doc)
+ return;
+
+ if (m_type == Resize)
+ {
+ if (m_actOnSelection)
+ {
+ if (!m_actOnTextSelection)
+ {
+ kdError () << "kpToolResizeScaleCommand::unexecute() resizing sel doesn't make sense" << endl;
+ return;
+ }
+ else
+ {
+ QApplication::setOverrideCursor (Qt::waitCursor);
+ document ()->selection ()->textResize (m_oldWidth, m_oldHeight);
+
+ if (m_mainWindow->tool ())
+ m_mainWindow->tool ()->somethingBelowTheCursorChanged ();
+
+ QApplication::restoreOverrideCursor ();
+ }
+ }
+ else
+ {
+ QApplication::setOverrideCursor (Qt::waitCursor);
+
+
+ QPixmap newPixmap (m_oldWidth, m_oldHeight);
+
+ kpPixmapFX::setPixmapAt (&newPixmap, QPoint (0, 0),
+ *doc->pixmap ());
+
+ if (m_newWidth < m_oldWidth)
+ {
+ kpPixmapFX::setPixmapAt (&newPixmap,
+ QPoint (m_newWidth, 0),
+ m_oldRightPixmap);
+ }
+
+ if (m_newHeight < m_oldHeight)
+ {
+ kpPixmapFX::setPixmapAt (&newPixmap,
+ QPoint (0, m_newHeight),
+ m_oldBottomPixmap);
+ }
+
+ doc->setPixmap (newPixmap);
+
+
+ QApplication::restoreOverrideCursor ();
+ }
+ }
+ else
+ {
+ QApplication::setOverrideCursor (Qt::waitCursor);
+
+
+ QPixmap oldPixmap;
+
+ if (!m_isLosslessScale)
+ oldPixmap = m_oldPixmap;
+ else
+ oldPixmap = kpPixmapFX::scale (*doc->pixmap (m_actOnSelection),
+ m_oldWidth, m_oldHeight);
+
+
+ if (m_actOnSelection)
+ {
+ kpSelection oldSelection = *m_oldSelection;
+ oldSelection.setPixmap (oldPixmap);
+ doc->setSelection (oldSelection);
+
+ if (m_mainWindow->tool ())
+ m_mainWindow->tool ()->somethingBelowTheCursorChanged ();
+ }
+ else
+ {
+ doc->setPixmap (oldPixmap);
+
+ if (m_scaleSelectionWithImage)
+ {
+ doc->setSelection (*m_oldSelection);
+
+ if (m_mainWindow->tool ())
+ m_mainWindow->tool ()->somethingBelowTheCursorChanged ();
+ }
+ }
+
+
+ QApplication::restoreOverrideCursor ();
+ }
+}
+
+
+/*
+ * kpToolResizeScaleDialog
+ */
+
+#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--; \
+}
+
+
+// private static
+kpToolResizeScaleCommand::Type kpToolResizeScaleDialog::s_lastType =
+ kpToolResizeScaleCommand::Resize;
+
+// private static
+double kpToolResizeScaleDialog::s_lastPercentWidth = 100,
+ kpToolResizeScaleDialog::s_lastPercentHeight = 100;
+
+
+kpToolResizeScaleDialog::kpToolResizeScaleDialog (kpMainWindow *mainWindow)
+ : KDialogBase ((QWidget *) mainWindow,
+ 0/*name*/,
+ true/*modal*/,
+ i18n ("Resize / Scale")/*caption*/,
+ KDialogBase::Ok | KDialogBase::Cancel),
+ m_mainWindow (mainWindow),
+ m_ignoreKeepAspectRatio (0)
+{
+ // Using the percentage from last time become too confusing so disable for now
+ s_lastPercentWidth = 100, s_lastPercentHeight = 100;
+
+
+ QWidget *baseWidget = new QWidget (this);
+ setMainWidget (baseWidget);
+
+
+ createActOnBox (baseWidget);
+ createOperationGroupBox (baseWidget);
+ createDimensionsGroupBox (baseWidget);
+
+
+ QVBoxLayout *baseLayout = new QVBoxLayout (baseWidget, 0/*margin*/, spacingHint ());
+ baseLayout->addWidget (m_actOnBox);
+ baseLayout->addWidget (m_operationGroupBox);
+ baseLayout->addWidget (m_dimensionsGroupBox);
+
+
+ slotActOnChanged ();
+
+ m_newWidthInput->setEditFocus ();
+
+ //enableButtonOK (!isNoOp ());
+}
+
+kpToolResizeScaleDialog::~kpToolResizeScaleDialog ()
+{
+}
+
+
+// private
+kpDocument *kpToolResizeScaleDialog::document () const
+{
+ return m_mainWindow ? m_mainWindow->document () : 0;
+}
+
+// private
+kpSelection *kpToolResizeScaleDialog::selection () const
+{
+ return document () ? document ()->selection () : 0;
+}
+
+
+// private
+void kpToolResizeScaleDialog::createActOnBox (QWidget *baseWidget)
+{
+ m_actOnBox = new QHBox (baseWidget);
+ m_actOnBox->setSpacing (spacingHint () * 2);
+
+
+ m_actOnLabel = new QLabel (i18n ("Ac&t on:"), m_actOnBox);
+ m_actOnCombo = new KComboBox (m_actOnBox);
+
+
+ m_actOnLabel->setBuddy (m_actOnCombo);
+
+ m_actOnCombo->insertItem (i18n ("Entire Image"), Image);
+ if (selection ())
+ {
+ QString selName = i18n ("Selection");
+
+ if (selection ()->isText ())
+ selName = i18n ("Text Box");
+
+ m_actOnCombo->insertItem (selName, Selection);
+ m_actOnCombo->setCurrentItem (Selection);
+ }
+ else
+ {
+ m_actOnLabel->setEnabled (false);
+ m_actOnCombo->setEnabled (false);
+ }
+
+
+ m_actOnBox->setStretchFactor (m_actOnCombo, 1);
+
+
+ connect (m_actOnCombo, SIGNAL (activated (int)),
+ this, SLOT (slotActOnChanged ()));
+}
+
+
+static QIconSet toolButtonIconSet (const QString &iconName)
+{
+ QIconSet iconSet = UserIconSet (iconName);
+
+
+ // No "disabled" pixmap is generated by UserIconSet() so generate it
+ // ourselves:
+
+ QPixmap disabledIcon = KGlobal::iconLoader ()->iconEffect ()->apply (
+ UserIcon (iconName),
+ KIcon::Toolbar, KIcon::DisabledState);
+
+ const QPixmap iconSetNormalIcon = iconSet.pixmap (QIconSet::Small,
+ QIconSet::Normal);
+
+ // I bet past or future versions of KIconEffect::apply() resize the
+ // disabled icon if we claim it's in group KIcon::Toolbar. So resize
+ // it to match the QIconSet::Normal icon, just in case.
+ disabledIcon = kpPixmapFX::scale (disabledIcon,
+ iconSetNormalIcon.width (),
+ iconSetNormalIcon.height (),
+ true/*smooth scale*/);
+
+
+ iconSet.setPixmap (disabledIcon,
+ QIconSet::Small, QIconSet::Disabled);
+
+ return iconSet;
+}
+
+static void toolButtonSetLook (QToolButton *button,
+ const QString &iconName,
+ const QString &name)
+{
+ button->setIconSet (toolButtonIconSet (iconName));
+ button->setUsesTextLabel (true);
+ button->setTextLabel (name, false/*no tooltip*/);
+ button->setAccel (QAccel::shortcutKey (name));
+ button->setFocusPolicy (QWidget::StrongFocus);
+ button->setToggleButton (true);
+}
+
+
+// private
+void kpToolResizeScaleDialog::createOperationGroupBox (QWidget *baseWidget)
+{
+ m_operationGroupBox = new QGroupBox (i18n ("Operation"), baseWidget);
+ QWhatsThis::add (m_operationGroupBox,
+ i18n ("<qt>"
+ "<ul>"
+ "<li><b>Resize</b>: 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.</li>"
+
+ "<li><b>Scale</b>: The picture will be expanded"
+ " by duplicating pixels or squashed by dropping pixels.</li>"
+
+ "<li><b>Smooth Scale</b>: This is the same as"
+ " <i>Scale</i> except that it blends neighboring"
+ " pixels to produce a smoother looking picture.</li>"
+ "</ul>"
+ "</qt>"));
+
+ // TODO: ALT+R doesn't select the button.
+ m_resizeButton = new QToolButton (m_operationGroupBox);
+ toolButtonSetLook (m_resizeButton,
+ QString::fromLatin1 ("resize"),
+ i18n ("&Resize"));
+
+ m_scaleButton = new QToolButton (m_operationGroupBox);
+ toolButtonSetLook (m_scaleButton,
+ QString::fromLatin1 ("scale"),
+ i18n ("&Scale"));
+
+ m_smoothScaleButton = new QToolButton (m_operationGroupBox);
+ toolButtonSetLook (m_smoothScaleButton,
+ QString::fromLatin1 ("smooth_scale"),
+ i18n ("S&mooth Scale"));
+
+
+ //m_resizeLabel = new QLabel (i18n ("&Resize"), m_operationGroupBox);
+ //m_scaleLabel = new QLabel (i18n ("&Scale"), m_operationGroupBox);
+ //m_smoothScaleLabel = new QLabel (i18n ("S&mooth scale"), m_operationGroupBox);
+
+
+ //m_resizeLabel->setAlignment (m_resizeLabel->alignment () | Qt::ShowPrefix);
+ //m_scaleLabel->setAlignment (m_scaleLabel->alignment () | Qt::ShowPrefix);
+ //m_smoothScaleLabel->setAlignment (m_smoothScaleLabel->alignment () | Qt::ShowPrefix);
+
+
+ QButtonGroup *resizeScaleButtonGroup = new QButtonGroup (baseWidget);
+ resizeScaleButtonGroup->setExclusive (true);
+ resizeScaleButtonGroup->hide ();
+
+ resizeScaleButtonGroup->insert (m_resizeButton);
+ resizeScaleButtonGroup->insert (m_scaleButton);
+ resizeScaleButtonGroup->insert (m_smoothScaleButton);
+
+
+ QGridLayout *operationLayout = new QGridLayout (m_operationGroupBox,
+ 1, 2,
+ marginHint () * 2/*don't overlap groupbox title*/,
+ spacingHint ());
+
+ operationLayout->addWidget (m_resizeButton, 0, 0, Qt::AlignCenter);
+ //operationLayout->addWidget (m_resizeLabel, 1, 0, Qt::AlignCenter);
+
+ operationLayout->addWidget (m_scaleButton, 0, 1, Qt::AlignCenter);
+ //operationLayout->addWidget (m_scaleLabel, 1, 1, Qt::AlignCenter);
+
+ operationLayout->addWidget (m_smoothScaleButton, 0, 2, Qt::AlignCenter);
+ //operationLayout->addWidget (m_smoothScaleLabel, 1, 2, Qt::AlignCenter);
+
+
+ connect (m_resizeButton, SIGNAL (toggled (bool)),
+ this, SLOT (slotTypeChanged ()));
+ connect (m_scaleButton, SIGNAL (toggled (bool)),
+ this, SLOT (slotTypeChanged ()));
+ connect (m_smoothScaleButton, SIGNAL (toggled (bool)),
+ this, SLOT (slotTypeChanged ()));
+}
+
+// private
+void kpToolResizeScaleDialog::createDimensionsGroupBox (QWidget *baseWidget)
+{
+ m_dimensionsGroupBox = new QGroupBox (i18n ("Dimensions"), baseWidget);
+
+ QLabel *widthLabel = new QLabel (i18n ("Width:"), m_dimensionsGroupBox);
+ widthLabel->setAlignment (widthLabel->alignment () | Qt::AlignHCenter);
+ QLabel *heightLabel = new QLabel (i18n ("Height:"), m_dimensionsGroupBox);
+ heightLabel->setAlignment (heightLabel->alignment () | Qt::AlignHCenter);
+
+ QLabel *originalLabel = new QLabel (i18n ("Original:"), m_dimensionsGroupBox);
+ m_originalWidthInput = new KIntNumInput (
+ document ()->width ((bool) selection ()),
+ m_dimensionsGroupBox);
+ QLabel *xLabel0 = new QLabel (i18n ("x"), m_dimensionsGroupBox);
+ m_originalHeightInput = new KIntNumInput (
+ document ()->height ((bool) selection ()),
+ m_dimensionsGroupBox);
+
+ QLabel *newLabel = new QLabel (i18n ("&New:"), m_dimensionsGroupBox);
+ m_newWidthInput = new KIntNumInput (m_dimensionsGroupBox);
+ QLabel *xLabel1 = new QLabel (i18n ("x"), m_dimensionsGroupBox);
+ m_newHeightInput = new KIntNumInput (m_dimensionsGroupBox);
+
+ QLabel *percentLabel = new QLabel (i18n ("&Percent:"), m_dimensionsGroupBox);
+ m_percentWidthInput = new KDoubleNumInput (0.01/*lower*/, 1000000/*upper*/,
+ 100/*value*/, 1/*step*/,
+ 2/*precision*/,
+ m_dimensionsGroupBox);
+ m_percentWidthInput->setSuffix (i18n ("%"));
+ QLabel *xLabel2 = new QLabel (i18n ("x"), m_dimensionsGroupBox);
+ m_percentHeightInput = new KDoubleNumInput (0.01/*lower*/, 1000000/*upper*/,
+ 100/*value*/, 1/*step*/,
+ 2/*precision*/,
+ m_dimensionsGroupBox);
+ m_percentHeightInput->setSuffix (i18n ("%"));
+
+ m_keepAspectRatioCheckBox = new QCheckBox (i18n ("Keep &aspect ratio"),
+ m_dimensionsGroupBox);
+
+
+ m_originalWidthInput->setEnabled (false);
+ m_originalHeightInput->setEnabled (false);
+ originalLabel->setBuddy (m_originalWidthInput);
+ newLabel->setBuddy (m_newWidthInput);
+ m_percentWidthInput->setValue (s_lastPercentWidth);
+ m_percentHeightInput->setValue (s_lastPercentHeight);
+ percentLabel->setBuddy (m_percentWidthInput);
+
+
+ QGridLayout *dimensionsLayout = new QGridLayout (m_dimensionsGroupBox,
+ 5, 4, marginHint () * 2, spacingHint ());
+ dimensionsLayout->setColStretch (1/*column*/, 1);
+ dimensionsLayout->setColStretch (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->addMultiCellWidget (m_keepAspectRatioCheckBox, 4, 4, 0, 3);
+ dimensionsLayout->setRowStretch (4/*row*/, 1);
+ dimensionsLayout->setRowSpacing (4/*row*/, dimensionsLayout->rowSpacing (4) * 2);
+
+
+ connect (m_newWidthInput, SIGNAL (valueChanged (int)),
+ this, SLOT (slotWidthChanged (int)));
+ connect (m_newHeightInput, SIGNAL (valueChanged (int)),
+ this, SLOT (slotHeightChanged (int)));
+
+ connect (m_percentWidthInput, SIGNAL (valueChanged (double)),
+ this, SLOT (slotPercentWidthChanged (double)));
+ connect (m_percentHeightInput, SIGNAL (valueChanged (double)),
+ this, SLOT (slotPercentHeightChanged (double)));
+
+ connect (m_keepAspectRatioCheckBox, SIGNAL (toggled (bool)),
+ this, SLOT (setKeepAspectRatio (bool)));
+}
+
+
+// private
+void kpToolResizeScaleDialog::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 kpToolResizeScaleDialog::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 kpToolResizeScaleDialog::resizeEnabled () const
+{
+ return (!actOnSelection () ||
+ (actOnSelection () && selection ()->isText ()));
+}
+
+// private
+bool kpToolResizeScaleDialog::scaleEnabled () const
+{
+ return (!(actOnSelection () && selection ()->isText ()));
+}
+
+// private
+bool kpToolResizeScaleDialog::smoothScaleEnabled () const
+{
+ return scaleEnabled ();
+}
+
+
+// public slot
+void kpToolResizeScaleDialog::slotActOnChanged ()
+{
+#if DEBUG_KP_TOOL_RESIZE_SCALE_DIALOG && 1
+ kdDebug () << "kpToolResizeScaleDialog::slotActOnChanged()" << endl;
+#endif
+
+ m_resizeButton->setEnabled (resizeEnabled ());
+ //m_resizeLabel->setEnabled (resizeEnabled ());
+
+ m_scaleButton->setEnabled (scaleEnabled ());
+ //m_scaleLabel->setEnabled (scaleEnabled ());
+
+ m_smoothScaleButton->setEnabled (smoothScaleEnabled ());
+ //m_smoothScaleLabel->setEnabled (smoothScaleEnabled ());
+
+
+ // TODO: somehow share logic with (resize|*scale)Enabled()
+ if (actOnSelection ())
+ {
+ if (selection ()->isText ())
+ {
+ m_resizeButton->setOn (true);
+ }
+ else
+ {
+ if (s_lastType == kpToolResizeScaleCommand::Scale)
+ m_scaleButton->setOn (true);
+ else
+ m_smoothScaleButton->setOn (true);
+ }
+ }
+ else
+ {
+ if (s_lastType == kpToolResizeScaleCommand::Resize)
+ m_resizeButton->setOn (true);
+ else if (s_lastType == kpToolResizeScaleCommand::Scale)
+ m_scaleButton->setOn (true);
+ else
+ m_smoothScaleButton->setOn (true);
+ }
+
+
+ m_originalWidthInput->setValue (originalWidth ());
+ m_originalHeightInput->setValue (originalHeight ());
+
+
+ m_newWidthInput->blockSignals (true);
+ m_newHeightInput->blockSignals (true);
+
+ m_newWidthInput->setMinValue (actOnSelection () ?
+ selection ()->minimumWidth () :
+ 1);
+ m_newHeightInput->setMinValue (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 kpToolResizeScaleDialog::slotTypeChanged ()
+{
+ s_lastType = type ();
+}
+
+// public slot
+void kpToolResizeScaleDialog::slotWidthChanged (int width)
+{
+#if DEBUG_KP_TOOL_RESIZE_SCALE_DIALOG && 1
+ kdDebug () << "kpToolResizeScaleDialog::slotWidthChanged("
+ << width << ")" << endl;
+#endif
+ const double newPercentWidth = double (width) * 100 / double (originalWidth ());
+
+ SET_VALUE_WITHOUT_SIGNAL_EMISSION (m_percentWidthInput, newPercentWidth);
+
+ widthFitHeightToAspectRatio ();
+
+ //enableButtonOK (!isNoOp ());
+ s_lastPercentWidth = newPercentWidth;
+}
+
+// public slot
+void kpToolResizeScaleDialog::slotHeightChanged (int height)
+{
+#if DEBUG_KP_TOOL_RESIZE_SCALE_DIALOG && 1
+ kdDebug () << "kpToolResizeScaleDialog::slotHeightChanged("
+ << height << ")" << endl;
+#endif
+ const double newPercentHeight = double (height) * 100 / double (originalHeight ());
+
+ SET_VALUE_WITHOUT_SIGNAL_EMISSION (m_percentHeightInput, newPercentHeight);
+
+ heightFitWidthToAspectRatio ();
+
+ //enableButtonOK (!isNoOp ());
+ s_lastPercentHeight = newPercentHeight;
+}
+
+// public slot
+void kpToolResizeScaleDialog::slotPercentWidthChanged (double percentWidth)
+{
+#if DEBUG_KP_TOOL_RESIZE_SCALE_DIALOG && 1
+ kdDebug () << "kpToolResizeScaleDialog::slotPercentWidthChanged("
+ << percentWidth << ")" << endl;
+#endif
+
+ SET_VALUE_WITHOUT_SIGNAL_EMISSION (m_newWidthInput,
+ qRound (percentWidth * originalWidth () / 100.0));
+
+ widthFitHeightToAspectRatio ();
+
+ //enableButtonOK (!isNoOp ());
+ s_lastPercentWidth = percentWidth;
+}
+
+// public slot
+void kpToolResizeScaleDialog::slotPercentHeightChanged (double percentHeight)
+{
+#if DEBUG_KP_TOOL_RESIZE_SCALE_DIALOG && 1
+ kdDebug () << "kpToolResizeScaleDialog::slotPercentHeightChanged("
+ << percentHeight << ")" << endl;
+#endif
+
+ SET_VALUE_WITHOUT_SIGNAL_EMISSION (m_newHeightInput,
+ qRound (percentHeight * originalHeight () / 100.0));
+
+ heightFitWidthToAspectRatio ();
+
+ //enableButtonOK (!isNoOp ());
+ s_lastPercentHeight = percentHeight;
+}
+
+// public
+bool kpToolResizeScaleDialog::keepAspectRatio () const
+{
+ return m_keepAspectRatioCheckBox->isChecked ();
+}
+
+// public slot
+void kpToolResizeScaleDialog::setKeepAspectRatio (bool on)
+{
+#if DEBUG_KP_TOOL_RESIZE_SCALE_DIALOG && 1
+ kdDebug () << "kpToolResizeScaleDialog::setKeepAspectRatio("
+ << on << ")" << endl;
+#endif
+ if (on != m_keepAspectRatioCheckBox->isChecked ())
+ m_keepAspectRatioCheckBox->setChecked (on);
+
+ if (on)
+ widthFitHeightToAspectRatio ();
+}
+
+#undef IGNORE_KEEP_ASPECT_RATIO
+#undef SET_VALUE_WITHOUT_SIGNAL_EMISSION
+
+
+// private
+int kpToolResizeScaleDialog::originalWidth () const
+{
+ return document ()->width (actOnSelection ());
+}
+
+// private
+int kpToolResizeScaleDialog::originalHeight () const
+{
+ return document ()->height (actOnSelection ());
+}
+
+
+// public
+int kpToolResizeScaleDialog::imageWidth () const
+{
+ return m_newWidthInput->value ();
+}
+
+// public
+int kpToolResizeScaleDialog::imageHeight () const
+{
+ return m_newHeightInput->value ();
+}
+
+// public
+bool kpToolResizeScaleDialog::actOnSelection () const
+{
+ return (m_actOnCombo->currentItem () == Selection);
+}
+
+// public
+kpToolResizeScaleCommand::Type kpToolResizeScaleDialog::type () const
+{
+ if (m_resizeButton->isOn ())
+ return kpToolResizeScaleCommand::Resize;
+ else if (m_scaleButton->isOn ())
+ return kpToolResizeScaleCommand::Scale;
+ else
+ return kpToolResizeScaleCommand::SmoothScale;
+}
+
+// public
+bool kpToolResizeScaleDialog::isNoOp () const
+{
+ return (imageWidth () == originalWidth () &&
+ imageHeight () == originalHeight ());
+}
+
+
+// private slot virtual [base KDialogBase]
+void kpToolResizeScaleDialog::slotOk ()
+{
+ enum { eText, eSelection, eImage } actionTarget = eText;
+
+ if (actOnSelection ())
+ {
+ if (selection ()->isText ())
+ {
+ actionTarget = eText;
+ }
+ else
+ {
+ actionTarget = eSelection;
+ }
+ }
+ else
+ {
+ actionTarget = eImage;
+ }
+
+
+ QString message, caption, continueButtonText;
+
+ // Note: If eText, can't Scale nor SmoothScale.
+ // If eSelection, can't Resize.
+
+ switch (type ())
+ {
+ default:
+ case kpToolResizeScaleCommand::Resize:
+ if (actionTarget == eText)
+ {
+ message =
+ i18n ("<qt><p>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.</p>"
+
+ "<p>Are you sure you want to resize the text box?</p></qt>");
+
+ caption = i18n ("Resize Text Box?");
+ continueButtonText = i18n ("R&esize Text Box");
+ }
+ else if (actionTarget == eImage)
+ {
+ message =
+ i18n ("<qt><p>Resizing the image to %1x%2"
+ " may take a substantial amount of memory."
+ " This can reduce system"
+ " responsiveness and cause other application resource"
+ " problems.</p>"
+
+ "<p>Are you sure you want to resize the image?</p></qt>");
+
+ caption = i18n ("Resize Image?");
+ continueButtonText = i18n ("R&esize Image");
+ }
+
+ break;
+
+ case kpToolResizeScaleCommand::Scale:
+ if (actionTarget == eImage)
+ {
+ message =
+ i18n ("<qt><p>Scaling the image to %1x%2"
+ " may take a substantial amount of memory."
+ " This can reduce system"
+ " responsiveness and cause other application resource"
+ " problems.</p>"
+
+ "<p>Are you sure you want to scale the image?</p></qt>");
+
+ caption = i18n ("Scale Image?");
+ continueButtonText = i18n ("Scal&e Image");
+ }
+ else if (actionTarget == eSelection)
+ {
+ message =
+ i18n ("<qt><p>Scaling the selection to %1x%2"
+ " may take a substantial amount of memory."
+ " This can reduce system"
+ " responsiveness and cause other application resource"
+ " problems.</p>"
+
+ "<p>Are you sure you want to scale the selection?</p></qt>");
+
+ caption = i18n ("Scale Selection?");
+ continueButtonText = i18n ("Scal&e Selection");
+ }
+
+ break;
+
+ case kpToolResizeScaleCommand::SmoothScale:
+ if (actionTarget == eImage)
+ {
+ message =
+ i18n ("<qt><p>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.</p>"
+
+ "<p>Are you sure you want to smooth scale the image?</p></qt>");
+
+ caption = i18n ("Smooth Scale Image?");
+ continueButtonText = i18n ("Smooth Scal&e Image");
+ }
+ else if (actionTarget == eSelection)
+ {
+ message =
+ i18n ("<qt><p>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.</p>"
+
+ "<p>Are you sure you want to smooth scale the selection?</p></qt>");
+
+ caption = i18n ("Smooth Scale Selection?");
+ continueButtonText = i18n ("Smooth Scal&e Selection");
+ }
+
+ break;
+ }
+
+
+ if (kpTool::warnIfBigImageSize (originalWidth (),
+ originalHeight (),
+ imageWidth (), imageHeight (),
+ message.arg (imageWidth ()).arg (imageHeight ()),
+ caption,
+ continueButtonText,
+ this))
+ {
+ KDialogBase::slotOk ();
+ }
+}
+
+
+#include <kptoolresizescale.moc>
diff --git a/kolourpaint/tools/kptoolresizescale.h b/kolourpaint/tools/kptoolresizescale.h
new file mode 100644
index 00000000..e23b040e
--- /dev/null
+++ b/kolourpaint/tools/kptoolresizescale.h
@@ -0,0 +1,196 @@
+
+/*
+ Copyright (c) 2003,2004,2005 Clarence Dang <dang@kde.org>
+ 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 __kptoolresizescale_h__
+#define __kptoolresizescale_h__
+
+#include <qpixmap.h>
+
+#include <kpcommandhistory.h>
+#include <kdialogbase.h>
+
+#include <kpcolor.h>
+#include <kpselection.h>
+
+class QCheckBox;
+class QGroupBox;
+class QHBox;
+class QRadioButton;
+class QSize;
+class QString;
+class QToolButton;
+
+class KComboBox;
+class KDoubleNumInput;
+class KIntNumInput;
+
+class kpDocument;
+class kpMainWindow;
+class kpViewManager;
+
+class kpToolResizeScaleCommand : public kpCommand
+{
+public:
+ enum Type
+ {
+ Resize, Scale, SmoothScale
+ };
+
+ kpToolResizeScaleCommand (bool actOnSelection,
+ int newWidth, int newHeight,
+ Type type,
+ kpMainWindow *mainWindow);
+ virtual ~kpToolResizeScaleCommand ();
+
+ virtual QString name () const;
+ virtual int size () const;
+
+public:
+ int newWidth () const;
+ void setNewWidth (int width);
+
+ int newHeight () const;
+ void setNewHeight (int height);
+
+ QSize newSize () const;
+ virtual void resize (int width, int height);
+
+public:
+ bool scaleSelectionWithImage () const;
+
+private:
+ void scaleSelectionRegionWithDocument ();
+
+public:
+ virtual void execute ();
+ virtual void unexecute ();
+
+protected:
+ bool m_actOnSelection;
+ int m_newWidth, m_newHeight;
+ Type m_type;
+ bool m_isLosslessScale;
+ bool m_scaleSelectionWithImage;
+ kpColor m_backgroundColor;
+
+ int m_oldWidth, m_oldHeight;
+ bool m_actOnTextSelection;
+ QPixmap m_oldPixmap, m_oldRightPixmap, m_oldBottomPixmap;
+ kpSelection *m_oldSelection;
+};
+
+class kpToolResizeScaleDialog : public KDialogBase
+{
+Q_OBJECT
+
+public:
+ kpToolResizeScaleDialog (kpMainWindow *mainWindow);
+ virtual ~kpToolResizeScaleDialog ();
+
+ enum ActOn
+ {
+ Image, Selection
+ };
+
+private:
+ static kpToolResizeScaleCommand::Type s_lastType;
+ static double s_lastPercentWidth, s_lastPercentHeight;
+
+private:
+ kpDocument *document () const;
+ kpSelection *selection () const;
+
+ void createActOnBox (QWidget *baseWidget);
+ void createOperationGroupBox (QWidget *baseWidget);
+ void createDimensionsGroupBox (QWidget *baseWidget);
+
+ void widthFitHeightToAspectRatio ();
+ void heightFitWidthToAspectRatio ();
+
+private:
+ bool resizeEnabled () const;
+ bool scaleEnabled () const;
+ bool smoothScaleEnabled () const;
+
+public slots:
+ void slotActOnChanged ();
+ void slotTypeChanged ();
+
+ void slotWidthChanged (int width);
+ void slotHeightChanged (int height);
+
+ void slotPercentWidthChanged (double percentWidth);
+ void slotPercentHeightChanged (double percentHeight);
+
+public:
+ // (refers only to the state of the checkbox - user of dialog does
+ // not have to do extra calculations)
+ bool keepAspectRatio () const;
+public slots:
+ void setKeepAspectRatio (bool on);
+
+private:
+ int originalWidth () const;
+ int originalHeight () const;
+
+public:
+ int imageWidth () const;
+ int imageHeight () const;
+ bool actOnSelection () const;
+ kpToolResizeScaleCommand::Type type () const;
+
+ bool isNoOp () const;
+
+private slots:
+ virtual void slotOk ();
+
+private:
+ kpMainWindow *m_mainWindow;
+
+ QHBox *m_actOnBox;
+ QLabel *m_actOnLabel;
+ KComboBox *m_actOnCombo;
+
+ QGroupBox *m_operationGroupBox;
+ QToolButton *m_resizeButton,
+ *m_scaleButton,
+ *m_smoothScaleButton;
+ QLabel *m_resizeLabel,
+ *m_scaleLabel,
+ *m_smoothScaleLabel;
+
+ QGroupBox *m_dimensionsGroupBox;
+ KIntNumInput *m_originalWidthInput, *m_originalHeightInput,
+ *m_newWidthInput, *m_newHeightInput;
+ KDoubleNumInput *m_percentWidthInput, *m_percentHeightInput;
+ QCheckBox *m_keepAspectRatioCheckBox;
+
+ int m_ignoreKeepAspectRatio;
+};
+
+#endif // __kptoolresizescale_h__
diff --git a/kolourpaint/tools/kptoolrotate.cpp b/kolourpaint/tools/kptoolrotate.cpp
new file mode 100644
index 00000000..8a37b673
--- /dev/null
+++ b/kolourpaint/tools/kptoolrotate.cpp
@@ -0,0 +1,500 @@
+
+/*
+ Copyright (c) 2003,2004,2005 Clarence Dang <dang@kde.org>
+ 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 <kptoolrotate.h>
+
+#include <qapplication.h>
+#include <qbuttongroup.h>
+#include <qgroupbox.h>
+#include <qlabel.h>
+#include <qlayout.h>
+#include <qpushbutton.h>
+#include <qradiobutton.h>
+#include <qwmatrix.h>
+
+#include <kdebug.h>
+#include <kiconloader.h>
+#include <knuminput.h>
+#include <klocale.h>
+
+#include <kpdefs.h>
+#include <kpdocument.h>
+#include <kpmainwindow.h>
+#include <kppixmapfx.h>
+#include <kpselection.h>
+#include <kptool.h>
+#include <kpviewmanager.h>
+
+
+kpToolRotateCommand::kpToolRotateCommand (bool actOnSelection,
+ double angle,
+ kpMainWindow *mainWindow)
+ : kpCommand (mainWindow),
+ m_actOnSelection (actOnSelection),
+ m_angle (angle),
+ m_backgroundColor (mainWindow ? mainWindow->backgroundColor (actOnSelection) : kpColor::invalid),
+ m_losslessRotation (kpPixmapFX::isLosslessRotation (angle))
+{
+}
+
+kpToolRotateCommand::~kpToolRotateCommand ()
+{
+}
+
+
+// public virtual [base kpCommand]
+QString kpToolRotateCommand::name () const
+{
+ QString opName = i18n ("Rotate");
+
+ if (m_actOnSelection)
+ return i18n ("Selection: %1").arg (opName);
+ else
+ return opName;
+}
+
+
+// public virtual [base kpCommand]
+int kpToolRotateCommand::size () const
+{
+ return kpPixmapFX::pixmapSize (m_oldPixmap) +
+ m_oldSelection.size ();
+}
+
+
+// public virtual [base kpCommand]
+void kpToolRotateCommand::execute ()
+{
+ kpDocument *doc = document ();
+ if (!doc)
+ return;
+
+
+ QApplication::setOverrideCursor (Qt::waitCursor);
+
+
+ if (!m_losslessRotation)
+ m_oldPixmap = *doc->pixmap (m_actOnSelection);
+
+
+ QPixmap newPixmap = kpPixmapFX::rotate (*doc->pixmap (m_actOnSelection),
+ m_angle,
+ m_backgroundColor);
+
+
+ if (m_actOnSelection)
+ {
+ kpSelection *sel = doc->selection ();
+
+ // Save old selection
+ m_oldSelection = *sel;
+ m_oldSelection.setPixmap (QPixmap ());
+
+
+ // Calculate new top left (so selection rotates about centre)
+ // (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 (newPixmap.width (), newPixmap.height ()));
+ QPoint newTopLeft (newTopLeftTimes2.x () / 2, newTopLeftTimes2.y () / 2);
+
+
+ // Calculate rotated points
+ QPointArray currentPoints = sel->points ();
+ currentPoints.translate (-currentPoints.boundingRect ().x (),
+ -currentPoints.boundingRect ().y ());
+ QWMatrix rotateMatrix = kpPixmapFX::rotateMatrix (*doc->pixmap (m_actOnSelection), m_angle);
+ currentPoints = rotateMatrix.map (currentPoints);
+ currentPoints.translate (-currentPoints.boundingRect ().x () + newTopLeft.x (),
+ -currentPoints.boundingRect ().y () + newTopLeft.y ());
+
+
+ if (currentPoints.boundingRect ().width () == newPixmap.width () &&
+ currentPoints.boundingRect ().height () == newPixmap.height ())
+ {
+ doc->setSelection (kpSelection (currentPoints, newPixmap,
+ m_oldSelection.transparency ()));
+ }
+ else
+ {
+ // TODO: fix the latter "victim of" problem in kpSelection by
+ // allowing the border width & height != pixmap width & height
+ // Or maybe autocrop?
+ #if DEBUG_KP_TOOL_ROTATE
+ kdDebug () << "kpToolRotateCommand::execute() currentPoints.boundingRect="
+ << currentPoints.boundingRect ()
+ << " newPixmap: w=" << newPixmap.width ()
+ << " h=" << newPixmap.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;
+ #endif
+ doc->setSelection (kpSelection (kpSelection::Rectangle,
+ QRect (newTopLeft.x (), newTopLeft.y (),
+ newPixmap.width (), newPixmap.height ()),
+ newPixmap,
+ m_oldSelection.transparency ()));
+ }
+
+ if (m_mainWindow->tool ())
+ m_mainWindow->tool ()->somethingBelowTheCursorChanged ();
+ }
+ else
+ doc->setPixmap (newPixmap);
+
+
+ QApplication::restoreOverrideCursor ();
+}
+
+// public virtual [base kpCommand]
+void kpToolRotateCommand::unexecute ()
+{
+ kpDocument *doc = document ();
+ if (!doc)
+ return;
+
+
+ QApplication::setOverrideCursor (Qt::waitCursor);
+
+
+ QPixmap oldPixmap;
+
+ if (!m_losslessRotation)
+ {
+ oldPixmap = m_oldPixmap;
+ m_oldPixmap.resize (0, 0);
+ }
+ else
+ {
+ oldPixmap = kpPixmapFX::rotate (*doc->pixmap (m_actOnSelection),
+ 360 - m_angle,
+ m_backgroundColor);
+ }
+
+
+ if (!m_actOnSelection)
+ doc->setPixmap (oldPixmap);
+ else
+ {
+ kpSelection oldSelection = m_oldSelection;
+ oldSelection.setPixmap (oldPixmap);
+ doc->setSelection (oldSelection);
+
+ if (m_mainWindow->tool ())
+ m_mainWindow->tool ()->somethingBelowTheCursorChanged ();
+ }
+
+
+ QApplication::restoreOverrideCursor ();
+}
+
+
+/*
+ * kpToolRotateDialog
+ */
+
+
+// private static
+int kpToolRotateDialog::s_lastWidth = -1,
+ kpToolRotateDialog::s_lastHeight = -1;
+
+// private static
+bool kpToolRotateDialog::s_lastIsClockwise = true;
+int kpToolRotateDialog::s_lastAngleRadioButtonID = 3;
+int kpToolRotateDialog::s_lastAngleCustom = 0;
+
+
+kpToolRotateDialog::kpToolRotateDialog (bool actOnSelection,
+ kpMainWindow *mainWindow,
+ const char *name)
+ : kpToolPreviewDialog (kpToolPreviewDialog::AllFeatures,
+ false/*don't reserve top row*/,
+ actOnSelection ? i18n ("Rotate Selection") : i18n ("Rotate Image"),
+ i18n ("After Rotate:"),
+ actOnSelection, mainWindow, name)
+{
+ // Too confusing - disable for now
+ s_lastAngleRadioButtonID = 3;
+ s_lastAngleCustom = 0;
+
+
+ createDirectionGroupBox ();
+ createAngleGroupBox ();
+
+
+ if (s_lastWidth > 0 && s_lastHeight > 0)
+ resize (s_lastWidth, s_lastHeight);
+
+
+ slotAngleCustomRadioButtonToggled (m_angleCustomRadioButton->isChecked ());
+ slotUpdate ();
+}
+
+kpToolRotateDialog::~kpToolRotateDialog ()
+{
+ s_lastWidth = width (), s_lastHeight = height ();
+}
+
+
+// private
+void kpToolRotateDialog::createDirectionGroupBox ()
+{
+ QGroupBox *directionGroupBox = new QGroupBox (i18n ("Direction"), mainWidget ());
+ addCustomWidget (directionGroupBox);
+
+
+ QLabel *antiClockwisePixmapLabel = new QLabel (directionGroupBox);
+ antiClockwisePixmapLabel->setPixmap (UserIcon ("image_rotate_anticlockwise"));
+
+ QLabel *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);
+
+
+ QButtonGroup *buttonGroup = new QButtonGroup (directionGroupBox);
+ buttonGroup->hide ();
+
+ buttonGroup->insert (m_antiClockwiseRadioButton);
+ buttonGroup->insert (m_clockwiseRadioButton);
+
+
+ QGridLayout *directionLayout = new QGridLayout (directionGroupBox,
+ 2, 2, marginHint () * 2, spacingHint ());
+ 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, SIGNAL (toggled (bool)),
+ this, SLOT (slotUpdate ()));
+ connect (m_clockwiseRadioButton, SIGNAL (toggled (bool)),
+ this, SLOT (slotUpdate ()));
+}
+
+// private
+void kpToolRotateDialog::createAngleGroupBox ()
+{
+ QGroupBox *angleGroupBox = new QGroupBox (i18n ("Angle"), mainWidget ());
+ addCustomWidget (angleGroupBox);
+
+
+ m_angle90RadioButton = new QRadioButton (i18n ("90 &degrees"), 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 KIntNumInput (s_lastAngleCustom, angleGroupBox);
+ m_angleCustomInput->setMinValue (-359);
+ m_angleCustomInput->setMaxValue (+359);
+ QLabel *degreesLabel = new QLabel (i18n ("degrees"), angleGroupBox);
+
+
+ m_angleButtonGroup = new QButtonGroup (angleGroupBox);
+ m_angleButtonGroup->hide ();
+
+ m_angleButtonGroup->insert (m_angle90RadioButton);
+ m_angleButtonGroup->insert (m_angle180RadioButton);
+ m_angleButtonGroup->insert (m_angle270RadioButton);
+
+ m_angleButtonGroup->insert (m_angleCustomRadioButton);
+
+ m_angleButtonGroup->setButton (s_lastAngleRadioButtonID);
+
+
+ QGridLayout *angleLayout = new QGridLayout (angleGroupBox,
+ 6, 3,
+ marginHint () * 2, spacingHint ());
+
+ angleLayout->addMultiCellWidget (m_angle90RadioButton, 0, 0, 0, 2);
+ angleLayout->addMultiCellWidget (m_angle180RadioButton, 1, 1, 0, 2);
+ angleLayout->addMultiCellWidget (m_angle270RadioButton, 2, 2, 0, 2);
+
+ angleLayout->addWidget (m_angleCustomRadioButton, 3, 0);
+ angleLayout->addWidget (m_angleCustomInput, 3, 1);
+ angleLayout->addWidget (degreesLabel, 3, 2);
+
+ angleLayout->setColStretch (1, 2); // Stretch Custom Angle Input
+
+
+ connect (m_angle90RadioButton, SIGNAL (toggled (bool)),
+ this, SLOT (slotUpdate ()));
+ connect (m_angle180RadioButton, SIGNAL (toggled (bool)),
+ this, SLOT (slotUpdate ()));
+ connect (m_angle270RadioButton, SIGNAL (toggled (bool)),
+ this, SLOT (slotUpdate ()));
+
+ connect (m_angleCustomRadioButton, SIGNAL (toggled (bool)),
+ this, SLOT (slotAngleCustomRadioButtonToggled (bool)));
+ connect (m_angleCustomRadioButton, SIGNAL (toggled (bool)),
+ this, SLOT (slotUpdate ()));
+
+ connect (m_angleCustomInput, SIGNAL (valueChanged (int)),
+ this, SLOT (slotUpdate ()));
+}
+
+
+// public virtual [base kpToolPreviewDialog]
+bool kpToolRotateDialog::isNoOp () const
+{
+ return (angle () == 0);
+}
+
+// public
+int kpToolRotateDialog::angle () const
+{
+ int retAngle;
+
+
+ if (m_angle90RadioButton->isChecked ())
+ retAngle = 90;
+ else if (m_angle180RadioButton->isChecked ())
+ retAngle = 180;
+ else if (m_angle270RadioButton->isChecked ())
+ retAngle = 270;
+ else // if (m_angleCustomRadioButton->isChecked ())
+ retAngle = m_angleCustomInput->value ();
+
+
+ if (m_antiClockwiseRadioButton->isChecked ())
+ retAngle *= -1;
+
+
+ if (retAngle < 0)
+ retAngle += ((0 - retAngle) / 360 + 1) * 360;
+
+ if (retAngle >= 360)
+ retAngle -= ((retAngle - 360) / 360 + 1) * 360;
+
+
+ return retAngle;
+}
+
+
+// private virtual [base kpToolPreviewDialog]
+QSize kpToolRotateDialog::newDimensions () const
+{
+ QWMatrix matrix = kpPixmapFX::rotateMatrix (m_oldWidth, m_oldHeight, angle ());
+ // TODO: Should we be using QWMatrix::Areas?
+ QRect rect = matrix.map (QRect (0, 0, m_oldWidth, m_oldHeight));
+ return rect.size ();
+}
+
+// private virtual [base kpToolPreviewDialog]
+QPixmap kpToolRotateDialog::transformPixmap (const QPixmap &pixmap,
+ int targetWidth, int targetHeight) const
+{
+ return kpPixmapFX::rotate (pixmap, angle (),
+ m_mainWindow ? m_mainWindow->backgroundColor (m_actOnSelection) : kpColor::invalid,
+ targetWidth, targetHeight);
+}
+
+
+// private slot
+void kpToolRotateDialog::slotAngleCustomRadioButtonToggled (bool isChecked)
+{
+ m_angleCustomInput->setEnabled (isChecked);
+
+ if (isChecked)
+ m_angleCustomInput->setEditFocus ();
+}
+
+// private slot virtual [base kpToolPreviewDialog]
+void kpToolRotateDialog::slotUpdate ()
+{
+ s_lastIsClockwise = m_clockwiseRadioButton->isChecked ();
+ s_lastAngleRadioButtonID = m_angleButtonGroup->selectedId ();
+ s_lastAngleCustom = m_angleCustomInput->value ();
+
+ kpToolPreviewDialog::slotUpdate ();
+}
+
+
+// private slot virtual [base KDialogBase]
+void kpToolRotateDialog::slotOk ()
+{
+ QString message, caption, continueButtonText;
+
+ if (document ()->selection ())
+ {
+ if (!document ()->selection ()->isText ())
+ {
+ message =
+ i18n ("<qt><p>Rotating the selection to %1x%2"
+ " may take a substantial amount of memory."
+ " This can reduce system"
+ " responsiveness and cause other application resource"
+ " problems.</p>"
+
+ "<p>Are you sure want to rotate the selection?</p></qt>");
+
+ caption = i18n ("Rotate Selection?");
+ continueButtonText = i18n ("Rotat&e Selection");
+ }
+ }
+ else
+ {
+ message =
+ i18n ("<qt><p>Rotating the image to %1x%2"
+ " may take a substantial amount of memory."
+ " This can reduce system"
+ " responsiveness and cause other application resource"
+ " problems.</p>"
+
+ "<p>Are you sure want to rotate the image?</p></qt>");
+
+ caption = i18n ("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.arg (newWidth).arg (newHeight),
+ caption,
+ continueButtonText,
+ this))
+ {
+ KDialogBase::slotOk ();
+ }
+}
+
+#include <kptoolrotate.moc>
diff --git a/kolourpaint/tools/kptoolrotate.h b/kolourpaint/tools/kptoolrotate.h
new file mode 100644
index 00000000..887473dc
--- /dev/null
+++ b/kolourpaint/tools/kptoolrotate.h
@@ -0,0 +1,129 @@
+
+/*
+ Copyright (c) 2003,2004,2005 Clarence Dang <dang@kde.org>
+ 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 __kptoolrotate_h__
+#define __kptoolrotate_h__
+
+#include <qpixmap.h>
+#include <qpoint.h>
+
+#include <kdialogbase.h>
+
+#include <kpcolor.h>
+#include <kpcommandhistory.h>
+#include <kpselection.h>
+#include <kptoolpreviewdialog.h>
+
+
+class QButtonGroup;
+class QRadioButton;
+class QString;
+
+class KIntNumInput;
+
+class kpDocument;
+class kpViewManager;
+class kpMainWindow;
+
+
+class kpToolRotateCommand : public kpCommand
+{
+public:
+ kpToolRotateCommand (bool actOnSelection,
+ double angle, // 0 <= angle < 360 (clockwise)
+ kpMainWindow *mainWindow);
+ virtual ~kpToolRotateCommand ();
+
+ virtual QString name () const;
+
+ virtual int size () const;
+
+ virtual void execute ();
+ virtual void unexecute ();
+
+private:
+ bool m_actOnSelection;
+ double m_angle;
+
+ kpColor m_backgroundColor;
+
+ bool m_losslessRotation;
+ QPixmap m_oldPixmap;
+ kpSelection m_oldSelection;
+};
+
+
+class kpToolRotateDialog : public kpToolPreviewDialog
+{
+Q_OBJECT
+
+public:
+ kpToolRotateDialog (bool actOnSelection,
+ kpMainWindow *parent,
+ const char *name = 0);
+ virtual ~kpToolRotateDialog ();
+
+private:
+ static int s_lastWidth, s_lastHeight;
+ static bool s_lastIsClockwise;
+ static int s_lastAngleRadioButtonID;
+ static int s_lastAngleCustom;
+
+ void createDirectionGroupBox ();
+ void createAngleGroupBox ();
+
+public:
+ virtual bool isNoOp () const;
+ int angle () const; // 0 <= angle < 360 (clockwise);
+
+private:
+ virtual QSize newDimensions () const;
+ virtual QPixmap transformPixmap (const QPixmap &pixmap,
+ int targetWidth, int targetHeight) const;
+
+private slots:
+ void slotAngleCustomRadioButtonToggled (bool isChecked);
+ virtual void slotUpdate ();
+
+private slots:
+ virtual void slotOk ();
+
+private:
+ QRadioButton *m_antiClockwiseRadioButton,
+ *m_clockwiseRadioButton;
+
+ QButtonGroup *m_angleButtonGroup;
+ QRadioButton *m_angle90RadioButton,
+ *m_angle180RadioButton,
+ *m_angle270RadioButton,
+ *m_angleCustomRadioButton;
+ KIntNumInput *m_angleCustomInput;
+};
+
+
+#endif // __kptoolrotate_h__
diff --git a/kolourpaint/tools/kptoolroundedrectangle.cpp b/kolourpaint/tools/kptoolroundedrectangle.cpp
new file mode 100644
index 00000000..b0f4ba05
--- /dev/null
+++ b/kolourpaint/tools/kptoolroundedrectangle.cpp
@@ -0,0 +1,45 @@
+
+/*
+ Copyright (c) 2003,2004,2005 Clarence Dang <dang@kde.org>
+ 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 <klocale.h>
+#include <kptoolroundedrectangle.h>
+
+kpToolRoundedRectangle::kpToolRoundedRectangle (kpMainWindow *mainWindow)
+ : kpToolRectangle (RoundedRectangle,
+ i18n ("Rounded Rectangle"),
+ i18n ("Draws rectangles and squares with rounded corners"),
+ Qt::Key_U,
+ mainWindow, "tool_rounded_rectangle")
+{
+}
+
+kpToolRoundedRectangle::~kpToolRoundedRectangle ()
+{
+}
+
+#include <kptoolroundedrectangle.moc>
diff --git a/kolourpaint/tools/kptoolroundedrectangle.h b/kolourpaint/tools/kptoolroundedrectangle.h
new file mode 100644
index 00000000..924c1b34
--- /dev/null
+++ b/kolourpaint/tools/kptoolroundedrectangle.h
@@ -0,0 +1,45 @@
+
+/*
+ Copyright (c) 2003,2004,2005 Clarence Dang <dang@kde.org>
+ 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 __kptoolroundedrectangle_h__
+#define __kptoolroundedrectangle_h__
+
+#include <kptoolrectangle.h>
+
+class kpMainWindow;
+
+class kpToolRoundedRectangle : public kpToolRectangle
+{
+Q_OBJECT
+
+public:
+ kpToolRoundedRectangle (kpMainWindow *);
+ virtual ~kpToolRoundedRectangle ();
+};
+
+#endif // __kptoolroundedrectangle_h__
diff --git a/kolourpaint/tools/kptoolselection.cpp b/kolourpaint/tools/kptoolselection.cpp
new file mode 100644
index 00000000..f664f01b
--- /dev/null
+++ b/kolourpaint/tools/kptoolselection.cpp
@@ -0,0 +1,2371 @@
+
+/*
+ Copyright (c) 2003,2004,2005 Clarence Dang <dang@kde.org>
+ 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 <kptoolselection.h>
+
+#include <qapplication.h>
+#include <qbitmap.h>
+#include <qcursor.h>
+#include <qpainter.h>
+#include <qpopupmenu.h>
+#include <qtimer.h>
+
+#include <kdebug.h>
+#include <klocale.h>
+
+#include <kpcommandhistory.h>
+#include <kpdefs.h>
+#include <kpdocument.h>
+#include <kpmainwindow.h>
+#include <kpselection.h>
+#include <kptooltoolbar.h>
+#include <kptoolwidgetopaqueortransparent.h>
+#include <kpview.h>
+#include <kpviewmanager.h>
+
+
+kpToolSelection::kpToolSelection (Mode mode,
+ const QString &text,
+ const QString &description,
+ int key,
+ kpMainWindow *mainWindow,
+ const char *name)
+ : kpTool (text, description, key, mainWindow, name),
+ m_mode (mode),
+ m_currentPullFromDocumentCommand (0),
+ m_currentMoveCommand (0),
+ m_currentResizeScaleCommand (0),
+ m_toolWidgetOpaqueOrTransparent (0),
+ m_currentCreateTextCommand (0),
+ m_createNOPTimer (new QTimer (this)),
+ m_RMBMoveUpdateGUITimer (new QTimer (this))
+{
+ connect (m_createNOPTimer, SIGNAL (timeout ()),
+ this, SLOT (delayedDraw ()));
+ connect (m_RMBMoveUpdateGUITimer, SIGNAL (timeout ()),
+ this, SLOT (slotRMBMoveUpdateGUI ()));
+}
+
+kpToolSelection::~kpToolSelection ()
+{
+}
+
+
+// private
+void kpToolSelection::pushOntoDocument ()
+{
+#if DEBUG_KP_TOOL_SELECTION && 1
+ kdDebug () << "kpToolSelection::pushOntoDocument() CALLED" << endl;
+#endif
+ mainWindow ()->slotDeselect ();
+}
+
+
+// protected
+bool kpToolSelection::onSelectionToMove () const
+{
+ kpView *v = viewManager ()->viewUnderCursor ();
+ if (!v)
+ return 0;
+
+ return v->mouseOnSelectionToMove (m_currentViewPoint);
+}
+
+// protected
+int kpToolSelection::onSelectionResizeHandle () const
+{
+ kpView *v = viewManager ()->viewUnderCursor ();
+ if (!v)
+ return 0;
+
+ return v->mouseOnSelectionResizeHandle (m_currentViewPoint);
+}
+
+// protected
+bool kpToolSelection::onSelectionToSelectText () const
+{
+ kpView *v = viewManager ()->viewUnderCursor ();
+ if (!v)
+ return 0;
+
+ return v->mouseOnSelectionToSelectText (m_currentViewPoint);
+}
+
+
+// public
+QString kpToolSelection::haventBegunDrawUserMessage () const
+{
+#if DEBUG_KP_TOOL_SELECTION && 0
+ kdDebug () << "kpToolSelection::haventBegunDrawUserMessage()"
+ " cancelledShapeButStillHoldingButtons="
+ << m_cancelledShapeButStillHoldingButtons
+ << endl;
+#endif
+
+ if (m_cancelledShapeButStillHoldingButtons)
+ return i18n ("Let go of all the mouse buttons.");
+
+ kpSelection *sel = document ()->selection ();
+ if (sel && onSelectionResizeHandle () && !controlOrShiftPressed ())
+ {
+ if (m_mode == Text)
+ return i18n ("Left drag to resize text box.");
+ else
+ return i18n ("Left drag to scale selection.");
+ }
+ else if (sel && sel->contains (m_currentPoint))
+ {
+ if (m_mode == Text)
+ {
+ if (onSelectionToSelectText () && !controlOrShiftPressed ())
+ return i18n ("Left click to change cursor position.");
+ else
+ return i18n ("Left drag to move text box.");
+ }
+ else
+ {
+ return i18n ("Left drag to move selection.");
+ }
+ }
+ else
+ {
+ if (m_mode == Text)
+ return i18n ("Left drag to create text box.");
+ else
+ return i18n ("Left drag to create selection.");
+ }
+}
+
+
+// virtual
+void kpToolSelection::begin ()
+{
+#if DEBUG_KP_TOOL_SELECTION
+ kdDebug () << "kpToolSelection::begin()" << endl;
+#endif
+
+ kpToolToolBar *tb = toolToolBar ();
+
+ if (tb)
+ {
+ m_toolWidgetOpaqueOrTransparent = tb->toolWidgetOpaqueOrTransparent ();
+
+ if (m_toolWidgetOpaqueOrTransparent)
+ {
+ connect (m_toolWidgetOpaqueOrTransparent, SIGNAL (isOpaqueChanged (bool)),
+ this, SLOT (slotIsOpaqueChanged ()));
+ m_toolWidgetOpaqueOrTransparent->show ();
+ }
+ }
+ else
+ {
+ m_toolWidgetOpaqueOrTransparent = 0;
+ }
+
+ viewManager ()->setQueueUpdates ();
+ {
+ viewManager ()->setSelectionBorderVisible (true);
+ viewManager ()->setSelectionBorderFinished (true);
+ }
+ viewManager ()->restoreQueueUpdates ();
+
+ m_startDragFromSelectionTopLeft = QPoint ();
+ m_dragType = Unknown;
+ m_dragHasBegun = false;
+ m_hadSelectionBeforeDrag = false; // arbitrary
+ m_resizeScaleType = 0;
+
+ m_currentPullFromDocumentCommand = 0;
+ m_currentMoveCommand = 0;
+ m_currentResizeScaleCommand = 0;
+ m_currentCreateTextCommand = 0;
+
+ m_cancelledShapeButStillHoldingButtons = false;
+
+ setUserMessage (haventBegunDrawUserMessage ());
+}
+
+// virtual
+void kpToolSelection::end ()
+{
+#if DEBUG_KP_TOOL_SELECTION
+ kdDebug () << "kpToolSelection::end()" << endl;
+#endif
+
+ if (document ()->selection ())
+ pushOntoDocument ();
+
+ if (m_toolWidgetOpaqueOrTransparent)
+ {
+ disconnect (m_toolWidgetOpaqueOrTransparent, SIGNAL (isOpaqueChanged (bool)),
+ this, SLOT (slotIsOpaqueChanged ()));
+ m_toolWidgetOpaqueOrTransparent = 0;
+ }
+
+ viewManager ()->unsetCursor ();
+}
+
+// virtual
+void kpToolSelection::reselect ()
+{
+#if DEBUG_KP_TOOL_SELECTION
+ kdDebug () << "kpToolSelection::reselect()" << endl;
+#endif
+
+ if (document ()->selection ())
+ pushOntoDocument ();
+}
+
+
+// virtual
+void kpToolSelection::beginDraw ()
+{
+#if DEBUG_KP_TOOL_SELECTION
+ kdDebug () << "kpToolSelection::beginDraw() m_startPoint="
+ << m_startPoint
+ << " QCursor::pos() view startPoint="
+ << m_viewUnderStartPoint->mapFromGlobal (QCursor::pos ())
+ << endl;
+#endif
+
+ m_createNOPTimer->stop ();
+ m_RMBMoveUpdateGUITimer->stop ();
+
+
+ // In case the cursor was wrong to start with
+ // (forgot to call kpTool::somethingBelowTheCursorChanged()),
+ // make sure it is correct during this operation.
+ hover (m_currentPoint);
+
+ // Currently used only to end the current text
+ if (hasBegunShape ())
+ endShape (m_currentPoint, QRect (m_startPoint/* TODO: wrong */, m_currentPoint).normalize ());
+
+ m_dragType = Create;
+ m_dragHasBegun = false;
+
+ kpSelection *sel = document ()->selection ();
+ m_hadSelectionBeforeDrag = bool (sel);
+
+ if (sel)
+ {
+ #if DEBUG_KP_TOOL_SELECTION
+ kdDebug () << "\thas sel region rect=" << sel->boundingRect () << endl;
+ #endif
+ QRect selectionRect = sel->boundingRect ();
+
+ if (onSelectionResizeHandle () && !controlOrShiftPressed ())
+ {
+ #if DEBUG_KP_TOOL_SELECTION
+ kdDebug () << "\t\tis resize/scale" << endl;
+ #endif
+
+ m_startDragFromSelectionTopLeft = m_currentPoint - selectionRect.topLeft ();
+ m_dragType = ResizeScale;
+ m_resizeScaleType = onSelectionResizeHandle ();
+
+ viewManager ()->setQueueUpdates ();
+ {
+ viewManager ()->setSelectionBorderVisible (true);
+ viewManager ()->setSelectionBorderFinished (true);
+ viewManager ()->setTextCursorEnabled (false);
+ }
+ viewManager ()->restoreQueueUpdates ();
+ }
+ else if (sel->contains (m_currentPoint))
+ {
+ if (m_mode == Text && onSelectionToSelectText () && !controlOrShiftPressed ())
+ {
+ #if DEBUG_KP_TOOL_SELECTION
+ kdDebug () << "\t\tis select cursor pos" << endl;
+ #endif
+
+ m_dragType = SelectText;
+
+ viewManager ()->setTextCursorPosition (sel->textRowForPoint (m_currentPoint),
+ sel->textColForPoint (m_currentPoint));
+ }
+ else
+ {
+ #if DEBUG_KP_TOOL_SELECTION
+ kdDebug () << "\t\tis move" << endl;
+ #endif
+
+ m_startDragFromSelectionTopLeft = m_currentPoint - selectionRect.topLeft ();
+ m_dragType = Move;
+
+ if (m_mouseButton == 0)
+ {
+ setSelectionBorderForMove ();
+ }
+ else
+ {
+ // Don't hide sel border momentarily if user is just
+ // right _clicking_ selection
+ m_RMBMoveUpdateGUITimer->start (100, true/*single shot*/);
+ }
+ }
+ }
+ else
+ {
+ #if DEBUG_KP_TOOL_SELECTION
+ kdDebug () << "\t\tis new sel" << endl;
+ #endif
+
+ pushOntoDocument ();
+ }
+ }
+
+ // creating new selection?
+ if (m_dragType == Create)
+ {
+ viewManager ()->setQueueUpdates ();
+ {
+ viewManager ()->setSelectionBorderVisible (true);
+ viewManager ()->setSelectionBorderFinished (false);
+ viewManager ()->setTextCursorEnabled (false);
+ }
+ viewManager ()->restoreQueueUpdates ();
+
+ m_createNOPTimer->start (200, true/*single shot*/);
+ }
+
+ if (m_dragType != SelectText)
+ {
+ setUserMessage (cancelUserMessage ());
+ }
+}
+
+
+// protected
+const QCursor &kpToolSelection::cursor () const
+{
+#if DEBUG_KP_TOOL_SELECTION && 1
+ kdDebug () << "kpToolSelection::cursor()"
+ << " m_currentPoint=" << m_currentPoint
+ << " QCursor::pos() view under cursor="
+ << (viewUnderCursor () ?
+ viewUnderCursor ()->mapFromGlobal (QCursor::pos ()) :
+ KP_INVALID_POINT)
+ << " controlOrShiftPressed=" << controlOrShiftPressed ()
+ << endl;
+#endif
+
+ kpSelection *sel = document () ? document ()->selection () : 0;
+
+ if (sel && onSelectionResizeHandle () && !controlOrShiftPressed ())
+ {
+ #if DEBUG_KP_TOOL_SELECTION && 1
+ kdDebug () << "\tonSelectionResizeHandle="
+ << onSelectionResizeHandle () << endl;
+ #endif
+ switch (onSelectionResizeHandle ())
+ {
+ case (kpView::Top | kpView::Left):
+ case (kpView::Bottom | kpView::Right):
+ return Qt::sizeFDiagCursor;
+
+ case (kpView::Bottom | kpView::Left):
+ case (kpView::Top | kpView::Right):
+ return Qt::sizeBDiagCursor;
+
+ case kpView::Top:
+ case kpView::Bottom:
+ return Qt::sizeVerCursor;
+
+ case kpView::Left:
+ case kpView::Right:
+ return Qt::sizeHorCursor;
+ }
+
+ return Qt::arrowCursor;
+ }
+ else if (sel && sel->contains (m_currentPoint))
+ {
+ #if DEBUG_KP_TOOL_SELECTION && 1
+ kdDebug () << "\tsel contains currentPoint; selecting text? "
+ << onSelectionToSelectText () << endl;
+ #endif
+
+ if (m_mode == Text && onSelectionToSelectText () && !controlOrShiftPressed ())
+ return Qt::ibeamCursor;
+ else
+ return Qt::sizeAllCursor;
+ }
+ else
+ {
+ #if DEBUG_KP_TOOL_SELECTION && 1
+ kdDebug () << "\tnot on sel" << endl;
+ #endif
+ return Qt::crossCursor;
+ }
+}
+
+// virtual
+void kpToolSelection::hover (const QPoint &point)
+{
+#if DEBUG_KP_TOOL_SELECTION && 1
+ kdDebug () << "kpToolSelection::hover" << point << endl;
+#endif
+
+ viewManager ()->setCursor (cursor ());
+
+ 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 ())
+ setUserMessage (mess);
+}
+
+// protected
+void kpToolSelection::popupRMBMenu ()
+{
+ QPopupMenu *pop = mainWindow () ? mainWindow ()->selectionToolRMBMenu () : 0;
+ if (!pop)
+ return;
+
+ // WARNING: enters event loop - may re-enter view/tool event handlers
+ pop->exec (QCursor::pos ());
+
+ // Cursor may have moved while menu up, triggering mouseMoveEvents
+ // for the menu - not the view. Update cursor position now.
+ somethingBelowTheCursorChanged ();
+}
+
+// protected
+void kpToolSelection::setSelectionBorderForMove ()
+{
+ // don't show border while moving
+ viewManager ()->setQueueUpdates ();
+ {
+ viewManager ()->setSelectionBorderVisible (false);
+ viewManager ()->setSelectionBorderFinished (true);
+ viewManager ()->setTextCursorEnabled (false);
+ }
+ viewManager ()->restoreQueueUpdates ();
+}
+
+// protected slot
+void kpToolSelection::slotRMBMoveUpdateGUI ()
+{
+ // (just in case not called from single shot)
+ m_RMBMoveUpdateGUITimer->stop ();
+
+ setSelectionBorderForMove ();
+
+ kpSelection * const sel = document () ? document ()->selection () : 0;
+ if (sel)
+ setUserShapePoints (sel->topLeft ());
+}
+
+// protected slot
+void kpToolSelection::delayedDraw ()
+{
+#if DEBUG_KP_TOOL_SELECTION && 1
+ kdDebug () << "kpToolSelection::delayedDraw() hasBegunDraw="
+ << hasBegunDraw ()
+ << " currentPoint=" << m_currentPoint
+ << " lastPoint=" << m_lastPoint
+ << " startPoint=" << m_startPoint
+ << endl;
+#endif
+
+ // (just in case not called from single shot)
+ m_createNOPTimer->stop ();
+
+ if (hasBegunDraw ())
+ {
+ draw (m_currentPoint, m_lastPoint,
+ QRect (m_startPoint, m_currentPoint).normalize ());
+ }
+}
+
+// virtual
+void kpToolSelection::draw (const QPoint &inThisPoint, const QPoint & /*lastPoint*/,
+ const QRect &inNormalizedRect)
+{
+ QPoint thisPoint = inThisPoint;
+ QRect normalizedRect = inNormalizedRect;
+
+#if DEBUG_KP_TOOL_SELECTION && 1
+ kdDebug () << "kpToolSelection::draw" << thisPoint
+ << " startPoint=" << m_startPoint
+ << " normalizedRect=" << normalizedRect << endl;
+#endif
+
+
+ // OPT: return when thisPoint == m_lastPoint so that e.g. when creating
+ // Points sel, press modifiers doesn't add multiple points in same
+ // place
+
+
+ bool nextDragHasBegun = true;
+
+
+ if (m_dragType == Create)
+ {
+ #if DEBUG_KP_TOOL_SELECTION && 1
+ kdDebug () << "\tnot moving - resizing rect to" << normalizedRect
+ << endl;
+ kdDebug () << "\t\tcreateNOPTimer->isActive()="
+ << m_createNOPTimer->isActive ()
+ << " viewManhattanLength from startPoint="
+ << m_viewUnderStartPoint->transformDocToViewX ((thisPoint - m_startPoint).manhattanLength ())
+ << endl;
+ #endif
+
+ if (m_createNOPTimer->isActive ())
+ {
+ if (m_viewUnderStartPoint->transformDocToViewX ((thisPoint - m_startPoint).manhattanLength ()) <= 6)
+ {
+ #if DEBUG_KP_TOOL_SELECTION && 1
+ kdDebug () << "\t\tsuppress accidental movement" << endl;
+ #endif
+ thisPoint = m_startPoint;
+ }
+ else
+ {
+ #if DEBUG_KP_TOOL_SELECTION && 1
+ kdDebug () << "\t\tit's a \"big\" intended move - stop timer" << endl;
+ #endif
+ m_createNOPTimer->stop ();
+ }
+ }
+
+
+ // Prevent unintentional 1-pixel selections
+ if (!m_dragHasBegun && thisPoint == m_startPoint)
+ {
+ if (m_mode != kpToolSelection::Text)
+ {
+ #if DEBUG_KP_TOOL_SELECTION && 1
+ kdDebug () << "\tnon-text NOP - return" << endl;
+ #endif
+ setUserShapePoints (thisPoint);
+ return;
+ }
+ else // m_mode == kpToolSelection::Text
+ {
+ // Attempt to deselect text box by clicking?
+ if (m_hadSelectionBeforeDrag)
+ {
+ #if DEBUG_KP_TOOL_SELECTION && 1
+ kdDebug () << "\ttext box deselect - NOP - return" << endl;
+ #endif
+ setUserShapePoints (thisPoint);
+ return;
+ }
+
+ // Drag-wise, this is a NOP so we'd normally return (hence
+ // m_dragHasBegun would not change). However, as a special
+ // case, allow user to create a text box using a single
+ // click. But don't set m_dragHasBegun for next iteration
+ // since it would be untrue.
+ //
+ // This makes sure that a single click creation of text box
+ // works even if draw() is invoked more than once at the
+ // same position (esp. with accidental drag suppression
+ // (above)).
+ nextDragHasBegun = false;
+ }
+ }
+
+
+ switch (m_mode)
+ {
+ case kpToolSelection::Rectangle:
+ {
+ const QRect usefulRect = normalizedRect.intersect (document ()->rect ());
+ document ()->setSelection (kpSelection (kpSelection::Rectangle, usefulRect,
+ mainWindow ()->selectionTransparency ()));
+
+ setUserShapePoints (m_startPoint,
+ QPoint (QMAX (0, QMIN (m_currentPoint.x (), document ()->width () - 1)),
+ QMAX (0, QMIN (m_currentPoint.y (), document ()->height () - 1))));
+ break;
+ }
+ case kpToolSelection::Text:
+ {
+ const kpTextStyle textStyle = mainWindow ()->textStyle ();
+
+ int minimumWidth, minimumHeight;
+
+ // Just a click?
+ if (!m_dragHasBegun && thisPoint == m_startPoint)
+ {
+ #if DEBUG_KP_TOOL_SELECTION && 1
+ kdDebug () << "\tclick creating text box" << endl;
+ #endif
+
+ // (Click creating text box with RMB would not be obvious
+ // since RMB menu most likely hides text box immediately
+ // afterwards)
+ if (m_mouseButton == 1)
+ break;
+
+
+ minimumWidth = kpSelection::preferredMinimumWidthForTextStyle (textStyle);
+ if (thisPoint.x () >= m_startPoint.x ())
+ {
+ if (m_startPoint.x () + minimumWidth - 1 >= document ()->width ())
+ {
+ minimumWidth = QMAX (kpSelection::minimumWidthForTextStyle (textStyle),
+ document ()->width () - m_startPoint.x ());
+ }
+ }
+ else
+ {
+ if (m_startPoint.x () - minimumWidth + 1 < 0)
+ {
+ minimumWidth = QMAX (kpSelection::minimumWidthForTextStyle (textStyle),
+ m_startPoint.x () + 1);
+ }
+ }
+
+ minimumHeight = kpSelection::preferredMinimumHeightForTextStyle (textStyle);
+ if (thisPoint.y () >= m_startPoint.y ())
+ {
+ if (m_startPoint.y () + minimumHeight - 1 >= document ()->height ())
+ {
+ minimumHeight = QMAX (kpSelection::minimumHeightForTextStyle (textStyle),
+ document ()->height () - m_startPoint.y ());
+ }
+ }
+ else
+ {
+ if (m_startPoint.y () - minimumHeight + 1 < 0)
+ {
+ minimumHeight = QMAX (kpSelection::minimumHeightForTextStyle (textStyle),
+ m_startPoint.y () + 1);
+ }
+ }
+ }
+ else
+ {
+ #if DEBUG_KP_TOOL_SELECTION && 1
+ kdDebug () << "\tdrag creating text box" << endl;
+ #endif
+ minimumWidth = kpSelection::minimumWidthForTextStyle (textStyle);
+ minimumHeight = kpSelection::minimumHeightForTextStyle (textStyle);
+ }
+
+
+ if (normalizedRect.width () < minimumWidth)
+ {
+ if (thisPoint.x () >= m_startPoint.x ())
+ normalizedRect.setWidth (minimumWidth);
+ else
+ normalizedRect.setX (normalizedRect.right () - minimumWidth + 1);
+ }
+
+ if (normalizedRect.height () < minimumHeight)
+ {
+ if (thisPoint.y () >= m_startPoint.y ())
+ normalizedRect.setHeight (minimumHeight);
+ else
+ normalizedRect.setY (normalizedRect.bottom () - minimumHeight + 1);
+ }
+ #if DEBUG_KP_TOOL_SELECTION && 1
+ kdDebug () << "\t\tnormalizedRect=" << normalizedRect
+ << " kpSelection::preferredMinimumSize="
+ << QSize (minimumWidth, minimumHeight)
+ << endl;
+ #endif
+
+ QValueVector <QString> textLines (1, QString ());
+ kpSelection sel (normalizedRect, textLines, textStyle);
+
+ if (!m_currentCreateTextCommand)
+ {
+ m_currentCreateTextCommand = new kpToolSelectionCreateCommand (
+ i18n ("Text: Create Box"),
+ sel,
+ mainWindow ());
+ }
+ else
+ m_currentCreateTextCommand->setFromSelection (sel);
+
+ viewManager ()->setTextCursorPosition (0, 0);
+ document ()->setSelection (sel);
+
+ QPoint actualEndPoint = KP_INVALID_POINT;
+ if (m_startPoint == normalizedRect.topLeft ())
+ actualEndPoint = normalizedRect.bottomRight ();
+ else if (m_startPoint == normalizedRect.bottomRight ())
+ actualEndPoint = normalizedRect.topLeft ();
+ else if (m_startPoint == normalizedRect.topRight ())
+ actualEndPoint = normalizedRect.bottomLeft ();
+ else if (m_startPoint == normalizedRect.bottomLeft ())
+ actualEndPoint = normalizedRect.topRight ();
+
+ setUserShapePoints (m_startPoint, actualEndPoint);
+ break;
+ }
+ case kpToolSelection::Ellipse:
+ document ()->setSelection (kpSelection (kpSelection::Ellipse, normalizedRect,
+ mainWindow ()->selectionTransparency ()));
+ setUserShapePoints (m_startPoint, m_currentPoint);
+ break;
+ case kpToolSelection::FreeForm:
+ QPointArray points;
+
+ if (document ()->selection ())
+ points = document ()->selection ()->points ();
+
+
+ // (not detached so will modify "points" directly but
+ // still need to call kpDocument::setSelection() to
+ // update screen)
+
+ if (!m_dragHasBegun)
+ {
+ // We thought the drag at startPoint was a NOP
+ // but it turns out that it wasn't...
+ points.putPoints (points.count (), 1, m_startPoint.x (), m_startPoint.y ());
+ }
+
+ // TODO: there should be an upper limit on this before drawing the
+ // polygon becomes too slow
+ points.putPoints (points.count (), 1, thisPoint.x (), thisPoint.y ());
+
+
+ document ()->setSelection (kpSelection (points, mainWindow ()->selectionTransparency ()));
+ #if DEBUG_KP_TOOL_SELECTION && 1
+ kdDebug () << "\t\tfreeform; #points=" << document ()->selection ()->points ().count () << endl;
+ #endif
+
+ setUserShapePoints (m_currentPoint);
+ break;
+ }
+
+ viewManager ()->setSelectionBorderVisible (true);
+ }
+ else if (m_dragType == Move)
+ {
+ #if DEBUG_KP_TOOL_SELECTION && 1
+ kdDebug () << "\tmoving selection" << endl;
+ #endif
+
+ kpSelection *sel = document ()->selection ();
+
+ QRect targetSelRect = QRect (thisPoint.x () - m_startDragFromSelectionTopLeft.x (),
+ thisPoint.y () - m_startDragFromSelectionTopLeft.y (),
+ sel->width (),
+ sel->height ());
+
+ #if DEBUG_KP_TOOL_SELECTION && 1
+ kdDebug () << "\t\tstartPoint=" << m_startPoint
+ << " thisPoint=" << thisPoint
+ << " startDragFromSel=" << m_startDragFromSelectionTopLeft
+ << " targetSelRect=" << targetSelRect
+ << endl;
+ #endif
+
+ // Try to make sure selection still intersects document so that it's
+ // reachable.
+
+ if (targetSelRect.right () < 0)
+ targetSelRect.moveBy (-targetSelRect.right (), 0);
+ else if (targetSelRect.left () >= document ()->width ())
+ targetSelRect.moveBy (document ()->width () - targetSelRect.left () - 1, 0);
+
+ if (targetSelRect.bottom () < 0)
+ targetSelRect.moveBy (0, -targetSelRect.bottom ());
+ else if (targetSelRect.top () >= document ()->height ())
+ targetSelRect.moveBy (0, document ()->height () - targetSelRect.top () - 1);
+
+ #if DEBUG_KP_TOOL_SELECTION && 1
+ kdDebug () << "\t\t\tafter ensure sel rect clickable=" << targetSelRect << endl;
+ #endif
+
+
+ if (!m_dragHasBegun &&
+ targetSelRect.topLeft () + m_startDragFromSelectionTopLeft == m_startPoint)
+ {
+ #if DEBUG_KP_TOOL_SELECTION && 1
+ kdDebug () << "\t\t\t\tnop" << endl;
+ #endif
+
+
+ if (!m_RMBMoveUpdateGUITimer->isActive ())
+ {
+ // (slotRMBMoveUpdateGUI() calls similar line)
+ setUserShapePoints (sel->topLeft ());
+ }
+
+ // Prevent both NOP drag-moves
+ return;
+ }
+
+
+ if (m_RMBMoveUpdateGUITimer->isActive ())
+ {
+ m_RMBMoveUpdateGUITimer->stop ();
+ slotRMBMoveUpdateGUI ();
+ }
+
+
+ if (!sel->pixmap () && !m_currentPullFromDocumentCommand)
+ {
+ m_currentPullFromDocumentCommand = new kpToolSelectionPullFromDocumentCommand (
+ QString::null/*uninteresting child of macro cmd*/,
+ mainWindow ());
+ m_currentPullFromDocumentCommand->execute ();
+ }
+
+ if (!m_currentMoveCommand)
+ {
+ m_currentMoveCommand = new kpToolSelectionMoveCommand (
+ QString::null/*uninteresting child of macro cmd*/,
+ mainWindow ());
+ m_currentMoveCommandIsSmear = false;
+ }
+
+
+ //viewManager ()->setQueueUpdates ();
+ //viewManager ()->setFastUpdates ();
+
+ if (m_shiftPressed)
+ m_currentMoveCommandIsSmear = true;
+
+ if (!m_dragHasBegun && (m_controlPressed || m_shiftPressed))
+ m_currentMoveCommand->copyOntoDocument ();
+
+ m_currentMoveCommand->moveTo (targetSelRect.topLeft ());
+
+ if (m_shiftPressed)
+ m_currentMoveCommand->copyOntoDocument ();
+
+ //viewManager ()->restoreFastUpdates ();
+ //viewManager ()->restoreQueueUpdates ();
+
+ QPoint start = m_currentMoveCommand->originalSelection ().topLeft ();
+ QPoint end = targetSelRect.topLeft ();
+ setUserShapePoints (start, end, false/*don't set size*/);
+ setUserShapeSize (end.x () - start.x (), end.y () - start.y ());
+ }
+ else if (m_dragType == ResizeScale)
+ {
+ #if DEBUG_KP_TOOL_SELECTION && 1
+ kdDebug () << "\tresize/scale" << endl;
+ #endif
+
+ kpSelection *sel = document ()->selection ();
+
+ if (!m_dragHasBegun && thisPoint == m_startPoint)
+ {
+ #if DEBUG_KP_TOOL_SELECTION && 1
+ kdDebug () << "\t\tnop" << endl;
+ #endif
+
+ setUserShapePoints (QPoint (sel->width (), sel->height ()));
+ return;
+ }
+
+
+ if (!sel->pixmap () && !m_currentPullFromDocumentCommand)
+ {
+ m_currentPullFromDocumentCommand = new kpToolSelectionPullFromDocumentCommand (
+ QString::null/*uninteresting child of macro cmd*/,
+ mainWindow ());
+ m_currentPullFromDocumentCommand->execute ();
+ }
+
+ if (!m_currentResizeScaleCommand)
+ {
+ m_currentResizeScaleCommand = new kpToolSelectionResizeScaleCommand (mainWindow ());
+ }
+
+
+ kpSelection originalSelection = m_currentResizeScaleCommand->originalSelection ();
+ const int oldWidth = originalSelection.width ();
+ const int oldHeight = originalSelection.height ();
+
+
+ // Determine new width.
+
+ int userXSign = 0;
+ if (m_resizeScaleType & kpView::Left)
+ userXSign = -1;
+ else if (m_resizeScaleType & kpView::Right)
+ userXSign = +1;
+
+ int newWidth = oldWidth + userXSign * (thisPoint.x () - m_startPoint.x ());
+
+ newWidth = QMAX (originalSelection.minimumWidth (), newWidth);
+
+
+ // Determine new height.
+
+ int userYSign = 0;
+ if (m_resizeScaleType & kpView::Top)
+ userYSign = -1;
+ else if (m_resizeScaleType & kpView::Bottom)
+ userYSign = +1;
+
+ int newHeight = oldHeight + userYSign * (thisPoint.y () - m_startPoint.y ());
+
+ newHeight = QMAX (originalSelection.minimumHeight (), newHeight);
+
+
+ // Keep aspect ratio?
+ if (m_shiftPressed && !sel->isText ())
+ {
+ // Width changed more than height? At equality, favour width.
+ // Fix width, change height.
+ if ((userXSign ? double (newWidth) / oldWidth : 0) >=
+ (userYSign ? double (newHeight) / oldHeight : 0))
+ {
+ newHeight = newWidth * oldHeight / oldWidth;
+ newHeight = QMAX (originalSelection.minimumHeight (),
+ newHeight);
+ }
+ // Height changed more than width?
+ // Fix height, change width.
+ else
+ {
+ newWidth = newHeight * oldWidth / oldHeight;
+ newWidth = QMAX (originalSelection.minimumWidth (), newWidth);
+ }
+ }
+
+
+ // Adjust x/y to new width/height for left/top resizes.
+
+ int newX = originalSelection.x ();
+ int newY = originalSelection.y ();
+
+ if (m_resizeScaleType & kpView::Left)
+ {
+ newX -= (newWidth - originalSelection.width ());
+ }
+
+ if (m_resizeScaleType & kpView::Top)
+ {
+ newY -= (newHeight - originalSelection.height ());
+ }
+
+ #if DEBUG_KP_TOOL_SELECTION && 1
+ kdDebug () << "\t\tnewX=" << newX
+ << " newY=" << newY
+ << " newWidth=" << newWidth
+ << " newHeight=" << newHeight
+ << endl;
+ #endif
+
+
+ viewManager ()->setFastUpdates ();
+ m_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 ());
+ }
+
+
+ m_dragHasBegun = nextDragHasBegun;
+}
+
+// virtual
+void kpToolSelection::cancelShape ()
+{
+#if DEBUG_KP_TOOL_SELECTION
+ kdDebug () << "kpToolSelection::cancelShape() mouseButton=" << m_mouseButton << endl;
+#endif
+
+ m_createNOPTimer->stop ();
+ m_RMBMoveUpdateGUITimer->stop ();
+
+
+ viewManager ()->setQueueUpdates ();
+ {
+ if (m_dragType == Move)
+ {
+ #if DEBUG_KP_TOOL_SELECTION
+ kdDebug () << "\twas drag moving - undo drag and undo acquire" << endl;
+ #endif
+
+ if (m_currentMoveCommand)
+ {
+ #if DEBUG_KP_TOOL_SELECTION
+ kdDebug () << "\t\tundo currentMoveCommand" << endl;
+ #endif
+ m_currentMoveCommand->finalize ();
+ m_currentMoveCommand->unexecute ();
+ delete m_currentMoveCommand;
+ m_currentMoveCommand = 0;
+
+ if (document ()->selection ()->isText ())
+ viewManager ()->setTextCursorBlinkState (true);
+ }
+ }
+ else if (m_dragType == Create)
+ {
+ #if DEBUG_KP_TOOL_SELECTION
+ kdDebug () << "\twas creating sel - kill" << endl;
+ #endif
+
+ // TODO: should we give the user back the selection s/he had before (if any)?
+ document ()->selectionDelete ();
+
+ if (m_currentCreateTextCommand)
+ {
+ delete m_currentCreateTextCommand;
+ m_currentCreateTextCommand = 0;
+ }
+ }
+ else if (m_dragType == ResizeScale)
+ {
+ #if DEBUG_KP_TOOL_SELECTION
+ kdDebug () << "\twas resize/scale sel - kill" << endl;
+ #endif
+
+ if (m_currentResizeScaleCommand)
+ {
+ #if DEBUG_KP_TOOL_SELECTION
+ kdDebug () << "\t\tundo currentResizeScaleCommand" << endl;
+ #endif
+ m_currentResizeScaleCommand->finalize (); // (unneeded but let's be safe)
+ m_currentResizeScaleCommand->unexecute ();
+ delete m_currentResizeScaleCommand;
+ m_currentResizeScaleCommand = 0;
+
+ if (document ()->selection ()->isText ())
+ viewManager ()->setTextCursorBlinkState (true);
+ }
+ }
+
+
+ if (m_currentPullFromDocumentCommand)
+ {
+ #if DEBUG_KP_TOOL_SELECTION
+ kdDebug () << "\t\tundo pullFromDocumentCommand" << endl;
+ #endif
+ m_currentPullFromDocumentCommand->unexecute ();
+ delete m_currentPullFromDocumentCommand;
+ m_currentPullFromDocumentCommand = 0;
+ }
+
+
+ viewManager ()->setSelectionBorderVisible (true);
+ viewManager ()->setSelectionBorderFinished (true);
+ viewManager ()->setTextCursorEnabled (m_mode == Text && true);
+ }
+ viewManager ()->restoreQueueUpdates ();
+
+
+ m_dragType = Unknown;
+ m_cancelledShapeButStillHoldingButtons = true;
+ setUserMessage (i18n ("Let go of all the mouse buttons."));
+}
+
+// virtual
+void kpToolSelection::releasedAllButtons ()
+{
+ m_cancelledShapeButStillHoldingButtons = false;
+ setUserMessage (haventBegunDrawUserMessage ());
+}
+
+// virtual
+void kpToolSelection::endDraw (const QPoint & /*thisPoint*/, const QRect & /*normalizedRect*/)
+{
+ m_createNOPTimer->stop ();
+ m_RMBMoveUpdateGUITimer->stop ();
+
+
+ viewManager ()->setQueueUpdates ();
+ {
+ if (m_currentCreateTextCommand)
+ {
+ commandHistory ()->addCommand (m_currentCreateTextCommand, false/*no exec*/);
+ m_currentCreateTextCommand = 0;
+ }
+
+ kpMacroCommand *cmd = 0;
+ if (m_currentMoveCommand)
+ {
+ if (m_currentMoveCommandIsSmear)
+ {
+ cmd = new kpMacroCommand (i18n ("%1: Smear")
+ .arg (document ()->selection ()->name ()),
+ mainWindow ());
+ }
+ else
+ {
+ cmd = new kpMacroCommand ((document ()->selection ()->isText () ?
+ i18n ("Text: Move Box") :
+ i18n ("Selection: Move")),
+ mainWindow ());
+ }
+
+ if (document ()->selection ()->isText ())
+ viewManager ()->setTextCursorBlinkState (true);
+ }
+ else if (m_currentResizeScaleCommand)
+ {
+ cmd = new kpMacroCommand (m_currentResizeScaleCommand->kpNamedCommand::name (),
+ mainWindow ());
+
+ if (document ()->selection ()->isText ())
+ viewManager ()->setTextCursorBlinkState (true);
+ }
+
+ if (m_currentPullFromDocumentCommand)
+ {
+ if (!m_currentMoveCommand && !m_currentResizeScaleCommand)
+ {
+ kdError () << "kpToolSelection::endDraw() pull without move nor resize/scale" << endl;
+ delete m_currentPullFromDocumentCommand;
+ m_currentPullFromDocumentCommand = 0;
+ }
+ else
+ {
+ kpSelection selection;
+
+ if (m_currentMoveCommand)
+ selection = m_currentMoveCommand->originalSelection ();
+ else if (m_currentResizeScaleCommand)
+ selection = m_currentResizeScaleCommand->originalSelection ();
+
+ // just the border
+ selection.setPixmap (QPixmap ());
+
+ kpCommand *createCommand = new kpToolSelectionCreateCommand (
+ i18n ("Selection: Create"),
+ selection,
+ mainWindow ());
+
+ if (kpToolSelectionCreateCommand::nextUndoCommandIsCreateBorder (commandHistory ()))
+ commandHistory ()->setNextUndoCommand (createCommand);
+ else
+ commandHistory ()->addCommand (createCommand,
+ false/*no exec - user already dragged out sel*/);
+
+
+ cmd->addCommand (m_currentPullFromDocumentCommand);
+ m_currentPullFromDocumentCommand = 0;
+ }
+ }
+
+ if (m_currentMoveCommand)
+ {
+ m_currentMoveCommand->finalize ();
+ cmd->addCommand (m_currentMoveCommand);
+ m_currentMoveCommand = 0;
+
+ if (document ()->selection ()->isText ())
+ viewManager ()->setTextCursorBlinkState (true);
+ }
+
+ if (m_currentResizeScaleCommand)
+ {
+ m_currentResizeScaleCommand->finalize ();
+ cmd->addCommand (m_currentResizeScaleCommand);
+ m_currentResizeScaleCommand = 0;
+
+ if (document ()->selection ()->isText ())
+ viewManager ()->setTextCursorBlinkState (true);
+ }
+
+ if (cmd)
+ commandHistory ()->addCommand (cmd, false/*no exec*/);
+
+ viewManager ()->setSelectionBorderVisible (true);
+ viewManager ()->setSelectionBorderFinished (true);
+ viewManager ()->setTextCursorEnabled (m_mode == Text && true);
+ }
+ viewManager ()->restoreQueueUpdates ();
+
+
+ m_dragType = Unknown;
+ setUserMessage (haventBegunDrawUserMessage ());
+
+
+ if (m_mouseButton == 1/*right*/)
+ popupRMBMenu ();
+}
+
+
+// protected virtual [base kpTool]
+void kpToolSelection::keyPressEvent (QKeyEvent *e)
+{
+#if DEBUG_KP_TOOL_SELECTION && 0
+ kdDebug () << "kpToolSelection::keyPressEvent(e->text='" << e->text () << "')" << endl;
+#endif
+
+
+ e->ignore ();
+
+
+ if (document ()->selection () &&
+ !hasBegunDraw () &&
+ e->key () == Qt::Key_Escape)
+ {
+ #if DEBUG_KP_TOOL_SELECTION && 0
+ kdDebug () << "\tescape pressed with sel when not begun draw - deselecting" << endl;
+ #endif
+
+ pushOntoDocument ();
+ e->accept ();
+ }
+
+
+ if (!e->isAccepted ())
+ {
+ #if DEBUG_KP_TOOL_SELECTION && 0
+ kdDebug () << "\tkey processing did not accept (text was '"
+ << e->text ()
+ << "') - passing on event to kpTool"
+ << endl;
+ #endif
+
+ kpTool::keyPressEvent (e);
+ return;
+ }
+}
+
+
+// private slot
+void kpToolSelection::selectionTransparencyChanged (const QString & /*name*/)
+{
+#if 0
+#if DEBUG_KP_TOOL_SELECTION
+ kdDebug () << "kpToolSelection::selectionTransparencyChanged(" << name << ")" << endl;
+#endif
+
+ if (mainWindow ()->settingSelectionTransparency ())
+ {
+ #if DEBUG_KP_TOOL_SELECTION
+ kdDebug () << "\trecursion - abort setting selection transparency: "
+ << mainWindow ()->settingSelectionTransparency () << endl;
+ #endif
+ return;
+ }
+
+ if (document ()->selection ())
+ {
+ #if DEBUG_KP_TOOL_SELECTION
+ kdDebug () << "\thave sel - set transparency" << endl;
+ #endif
+
+ kpSelectionTransparency oldST = document ()->selection ()->transparency ();
+ kpSelectionTransparency st = mainWindow ()->selectionTransparency ();
+
+ // TODO: This "NOP" check causes us a great deal of trouble e.g.:
+ //
+ // Select a solid red rectangle.
+ // Switch to transparent and set red as the background colour.
+ // (the selection is now invisible)
+ // Invert Colours.
+ // (the selection is now cyan)
+ // Change the background colour to green.
+ // (no command is added to undo this as the selection does not change)
+ // Undo.
+ // The rectangle is no longer invisible.
+ //
+ //if (document ()->selection ()->setTransparency (st, true/*check harder for no change in mask*/))
+
+ document ()->selection ()->setTransparency (st);
+ if (true)
+ {
+ #if DEBUG_KP_TOOL_SELECTION
+ kdDebug () << "\t\twhich changed the pixmap" << endl;
+ #endif
+
+ commandHistory ()->addCommand (new kpToolSelectionTransparencyCommand (
+ i18n ("Selection: Transparency"), // name,
+ st, oldST,
+ mainWindow ()),
+ false/* no exec*/);
+ }
+ }
+#endif
+
+ // TODO: I've duplicated the code (see below 3x) to make sure
+ // kpSelectionTransparency(oldST)::transparentColor() is defined
+ // and not taken from kpDocument (where it may not be defined because
+ // the transparency may be opaque).
+ //
+ // That way kpToolSelectionTransparencyCommand can force set colours.
+}
+
+
+// protected slot virtual
+void kpToolSelection::slotIsOpaqueChanged ()
+{
+#if DEBUG_KP_TOOL_SELECTION
+ kdDebug () << "kpToolSelection::slotIsOpaqueChanged()" << endl;
+#endif
+
+ if (mainWindow ()->settingSelectionTransparency ())
+ {
+ #if DEBUG_KP_TOOL_SELECTION
+ kdDebug () << "\trecursion - abort setting selection transparency: "
+ << mainWindow ()->settingSelectionTransparency () << endl;
+ #endif
+ return;
+ }
+
+ if (document ()->selection ())
+ {
+ #if DEBUG_KP_TOOL_SELECTION
+ kdDebug () << "\thave sel - set transparency" << endl;
+ #endif
+
+ QApplication::setOverrideCursor (Qt::waitCursor);
+
+ if (hasBegunShape ())
+ endShapeInternal ();
+
+ kpSelectionTransparency st = mainWindow ()->selectionTransparency ();
+ kpSelectionTransparency oldST = st;
+ oldST.setOpaque (!oldST.isOpaque ());
+
+ document ()->selection ()->setTransparency (st);
+ commandHistory ()->addCommand (new kpToolSelectionTransparencyCommand (
+ st.isOpaque () ?
+ i18n ("Selection: Opaque") :
+ i18n ("Selection: Transparent"),
+ st, oldST,
+ mainWindow ()),
+ false/* no exec*/);
+
+ QApplication::restoreOverrideCursor ();
+ }
+}
+
+// protected slot virtual [base kpTool]
+void kpToolSelection::slotBackgroundColorChanged (const kpColor &)
+{
+#if DEBUG_KP_TOOL_SELECTION
+ kdDebug () << "kpToolSelection::slotBackgroundColorChanged()" << endl;
+#endif
+
+ if (mainWindow ()->settingSelectionTransparency ())
+ {
+ #if DEBUG_KP_TOOL_SELECTION
+ kdDebug () << "\trecursion - abort setting selection transparency: "
+ << mainWindow ()->settingSelectionTransparency () << endl;
+ #endif
+ return;
+ }
+
+ if (document ()->selection ())
+ {
+ #if DEBUG_KP_TOOL_SELECTION
+ kdDebug () << "\thave sel - set transparency" << endl;
+ #endif
+
+ QApplication::setOverrideCursor (Qt::waitCursor);
+
+ kpSelectionTransparency st = mainWindow ()->selectionTransparency ();
+ kpSelectionTransparency oldST = st;
+ oldST.setTransparentColor (oldBackgroundColor ());
+
+ document ()->selection ()->setTransparency (st);
+ commandHistory ()->addCommand (new kpToolSelectionTransparencyCommand (
+ i18n ("Selection: Transparency Color"),
+ st, oldST,
+ mainWindow ()),
+ false/* no exec*/);
+
+ QApplication::restoreOverrideCursor ();
+ }
+}
+
+// protected slot virtual [base kpTool]
+void kpToolSelection::slotColorSimilarityChanged (double, int)
+{
+#if DEBUG_KP_TOOL_SELECTION
+ kdDebug () << "kpToolSelection::slotColorSimilarityChanged()" << endl;
+#endif
+
+ if (mainWindow ()->settingSelectionTransparency ())
+ {
+ #if DEBUG_KP_TOOL_SELECTION
+ kdDebug () << "\trecursion - abort setting selection transparency: "
+ << mainWindow ()->settingSelectionTransparency () << endl;
+ #endif
+ return;
+ }
+
+ if (document ()->selection ())
+ {
+ #if DEBUG_KP_TOOL_SELECTION
+ kdDebug () << "\thave sel - set transparency" << endl;
+ #endif
+
+ QApplication::setOverrideCursor (Qt::waitCursor);
+
+ kpSelectionTransparency st = mainWindow ()->selectionTransparency ();
+ kpSelectionTransparency oldST = st;
+ oldST.setColorSimilarity (oldColorSimilarity ());
+
+ document ()->selection ()->setTransparency (st);
+ commandHistory ()->addCommand (new kpToolSelectionTransparencyCommand (
+ i18n ("Selection: Transparency Color Similarity"),
+ st, oldST,
+ mainWindow ()),
+ false/* no exec*/);
+
+ QApplication::restoreOverrideCursor ();
+ }
+}
+
+
+/*
+ * kpToolSelectionCreateCommand
+ */
+
+kpToolSelectionCreateCommand::kpToolSelectionCreateCommand (const QString &name,
+ const kpSelection &fromSelection,
+ kpMainWindow *mainWindow)
+ : kpNamedCommand (name, mainWindow),
+ m_fromSelection (0),
+ m_textRow (0), m_textCol (0)
+{
+ setFromSelection (fromSelection);
+}
+
+kpToolSelectionCreateCommand::~kpToolSelectionCreateCommand ()
+{
+ delete m_fromSelection;
+}
+
+
+// public virtual [base kpCommand]
+int kpToolSelectionCreateCommand::size () const
+{
+ return kpPixmapFX::selectionSize (m_fromSelection);
+}
+
+
+// public static
+bool kpToolSelectionCreateCommand::nextUndoCommandIsCreateBorder (
+ kpCommandHistory *commandHistory)
+{
+ if (!commandHistory)
+ return false;
+
+ kpCommand *cmd = commandHistory->nextUndoCommand ();
+ if (!cmd)
+ return false;
+
+ kpToolSelectionCreateCommand *c = dynamic_cast <kpToolSelectionCreateCommand *> (cmd);
+ if (!c)
+ return false;
+
+ const kpSelection *sel = c->fromSelection ();
+ if (!sel)
+ return false;
+
+ return (!sel->pixmap ());
+}
+
+
+// public
+const kpSelection *kpToolSelectionCreateCommand::fromSelection () const
+{
+ return m_fromSelection;
+}
+
+// public
+void kpToolSelectionCreateCommand::setFromSelection (const kpSelection &fromSelection)
+{
+ delete m_fromSelection;
+ m_fromSelection = new kpSelection (fromSelection);
+}
+
+// public virtual [base kpCommand]
+void kpToolSelectionCreateCommand::execute ()
+{
+#if DEBUG_KP_TOOL_SELECTION
+ kdDebug () << "kpToolSelectionCreateCommand::execute()" << endl;
+#endif
+
+ kpDocument *doc = document ();
+ if (!doc)
+ {
+ kdError () << "kpToolSelectionCreateCommand::execute() without doc" << endl;
+ return;
+ }
+
+ if (m_fromSelection)
+ {
+ #if DEBUG_KP_TOOL_SELECTION
+ kdDebug () << "\tusing fromSelection" << endl;
+ kdDebug () << "\t\thave sel=" << doc->selection ()
+ << " pixmap=" << (doc->selection () ? doc->selection ()->pixmap () : 0)
+ << endl;
+ #endif
+ if (!m_fromSelection->isText ())
+ {
+ if (m_fromSelection->transparency () != m_mainWindow->selectionTransparency ())
+ m_mainWindow->setSelectionTransparency (m_fromSelection->transparency ());
+ }
+ else
+ {
+ if (m_fromSelection->textStyle () != m_mainWindow->textStyle ())
+ m_mainWindow->setTextStyle (m_fromSelection->textStyle ());
+ }
+
+ m_mainWindow->viewManager ()->setTextCursorPosition (m_textRow, m_textCol);
+ doc->setSelection (*m_fromSelection);
+
+ if (m_mainWindow->tool ())
+ m_mainWindow->tool ()->somethingBelowTheCursorChanged ();
+ }
+}
+
+// public virtual [base kpCommand]
+void kpToolSelectionCreateCommand::unexecute ()
+{
+ kpDocument *doc = document ();
+ if (!doc)
+ {
+ kdError () << "kpToolSelectionCreateCommand::unexecute() without doc" << endl;
+ return;
+ }
+
+ if (!doc->selection ())
+ {
+ // Was just a border that got deselected?
+ if (m_fromSelection && !m_fromSelection->pixmap ())
+ return;
+
+ kdError () << "kpToolSelectionCreateCommand::unexecute() without sel region" << endl;
+ return;
+ }
+
+ m_textRow = m_mainWindow->viewManager ()->textCursorRow ();
+ m_textCol = m_mainWindow->viewManager ()->textCursorCol ();
+
+ doc->selectionDelete ();
+
+ if (m_mainWindow->tool ())
+ m_mainWindow->tool ()->somethingBelowTheCursorChanged ();
+}
+
+
+/*
+ * kpToolSelectionPullFromDocumentCommand
+ */
+
+kpToolSelectionPullFromDocumentCommand::kpToolSelectionPullFromDocumentCommand (const QString &name,
+ kpMainWindow *mainWindow)
+ : kpNamedCommand (name, mainWindow),
+ m_backgroundColor (mainWindow ? mainWindow->backgroundColor () : kpColor::invalid),
+ m_originalSelectionRegion (0)
+{
+#if DEBUG_KP_TOOL_SELECTION && 1
+ kdDebug () << "kpToolSelectionPullFromDocumentCommand::<ctor>() mainWindow="
+ << m_mainWindow
+ << endl;
+#endif
+}
+
+kpToolSelectionPullFromDocumentCommand::~kpToolSelectionPullFromDocumentCommand ()
+{
+ delete m_originalSelectionRegion;
+}
+
+
+// public virtual [base kpCommand]
+int kpToolSelectionPullFromDocumentCommand::size () const
+{
+ return kpPixmapFX::selectionSize (m_originalSelectionRegion);
+}
+
+
+// public virtual [base kpCommand]
+void kpToolSelectionPullFromDocumentCommand::execute ()
+{
+#if DEBUG_KP_TOOL_SELECTION && 1
+ kdDebug () << "kpToolSelectionPullFromDocumentCommand::execute()" << endl;
+#endif
+
+ kpDocument *doc = document ();
+
+ if (!doc)
+ {
+ kdError () << "kpToolSelectionPullFromDocumentCommand::execute() without doc" << endl;
+ return;
+ }
+
+ kpViewManager *vm = m_mainWindow ? m_mainWindow->viewManager () : 0;
+ if (vm)
+ vm->setQueueUpdates ();
+
+ // In case the user CTRL+Z'ed, selected a random region to throw us off
+ // and then CTRL+Shift+Z'ed putting us here. Make sure we pull from the
+ // originally requested region - not the random one.
+ if (m_originalSelectionRegion)
+ {
+ if (m_originalSelectionRegion->transparency () != m_mainWindow->selectionTransparency ())
+ m_mainWindow->setSelectionTransparency (m_originalSelectionRegion->transparency ());
+
+ doc->setSelection (*m_originalSelectionRegion);
+ }
+ else
+ {
+ // must have selection region but not pixmap
+ if (!doc->selection () || doc->selection ()->pixmap ())
+ {
+ kdError () << "kpToolSelectionPullFromDocumentCommand::execute() sel="
+ << doc->selection ()
+ << " pixmap="
+ << (doc->selection () ? doc->selection ()->pixmap () : 0)
+ << endl;
+ if (vm)
+ vm->restoreQueueUpdates ();
+ return;
+ }
+ }
+
+ doc->selectionPullFromDocument (m_backgroundColor);
+
+ if (vm)
+ vm->restoreQueueUpdates ();
+}
+
+// public virtual [base kpCommand]
+void kpToolSelectionPullFromDocumentCommand::unexecute ()
+{
+#if DEBUG_KP_TOOL_SELECTION && 1
+ kdDebug () << "kpToolSelectionPullFromDocumentCommand::unexecute()" << endl;
+#endif
+
+ kpDocument *doc = document ();
+
+ if (!doc)
+ {
+ kdError () << "kpToolSelectionPullFromDocumentCommand::unexecute() without doc" << endl;
+ return;
+ }
+
+ // must have selection pixmap
+ if (!doc->selection () || !doc->selection ()->pixmap ())
+ {
+ kdError () << "kpToolSelectionPullFromDocumentCommand::unexecute() sel="
+ << doc->selection ()
+ << " pixmap="
+ << (doc->selection () ? doc->selection ()->pixmap () : 0)
+ << endl;
+ return;
+ }
+
+
+ // 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->selection ()->setPixmap (QPixmap ());
+
+ delete m_originalSelectionRegion;
+ m_originalSelectionRegion = new kpSelection (*doc->selection ());
+}
+
+
+/*
+ * kpToolSelectionTransparencyCommand
+ */
+
+kpToolSelectionTransparencyCommand::kpToolSelectionTransparencyCommand (const QString &name,
+ const kpSelectionTransparency &st,
+ const kpSelectionTransparency &oldST,
+ kpMainWindow *mainWindow)
+ : kpNamedCommand (name, mainWindow),
+ m_st (st),
+ m_oldST (oldST)
+{
+}
+
+kpToolSelectionTransparencyCommand::~kpToolSelectionTransparencyCommand ()
+{
+}
+
+
+// public virtual [base kpCommand]
+int kpToolSelectionTransparencyCommand::size () const
+{
+ return 0;
+}
+
+
+// public virtual [base kpCommand]
+void kpToolSelectionTransparencyCommand::execute ()
+{
+#if DEBUG_KP_TOOL_SELECTION && 1
+ kdDebug () << "kpToolSelectionTransparencyCommand::execute()" << endl;
+#endif
+ kpDocument *doc = document ();
+ if (!doc)
+ return;
+
+ QApplication::setOverrideCursor (Qt::waitCursor);
+
+ m_mainWindow->setSelectionTransparency (m_st, true/*force colour change*/);
+
+ if (doc->selection ())
+ doc->selection ()->setTransparency (m_st);
+
+ QApplication::restoreOverrideCursor ();
+}
+
+// public virtual [base kpCommand]
+void kpToolSelectionTransparencyCommand::unexecute ()
+{
+#if DEBUG_KP_TOOL_SELECTION && 1
+ kdDebug () << "kpToolSelectionTransparencyCommand::unexecute()" << endl;
+#endif
+
+ kpDocument *doc = document ();
+ if (!doc)
+ return;
+
+ QApplication::setOverrideCursor (Qt::waitCursor);
+
+ m_mainWindow->setSelectionTransparency (m_oldST, true/*force colour change*/);
+
+ if (doc->selection ())
+ doc->selection ()->setTransparency (m_oldST);
+
+ QApplication::restoreOverrideCursor ();
+}
+
+
+/*
+ * kpToolSelectionMoveCommand
+ */
+
+kpToolSelectionMoveCommand::kpToolSelectionMoveCommand (const QString &name,
+ kpMainWindow *mainWindow)
+ : kpNamedCommand (name, mainWindow)
+{
+ kpDocument *doc = document ();
+ if (doc && doc->selection ())
+ {
+ m_startPoint = m_endPoint = doc->selection ()->topLeft ();
+ }
+}
+
+kpToolSelectionMoveCommand::~kpToolSelectionMoveCommand ()
+{
+}
+
+
+// public
+kpSelection kpToolSelectionMoveCommand::originalSelection () const
+{
+ kpDocument *doc = document ();
+ if (!doc || !doc->selection ())
+ {
+ kdError () << "kpToolSelectionMoveCommand::originalSelection() doc="
+ << doc
+ << " sel="
+ << (doc ? doc->selection () : 0)
+ << endl;
+ return kpSelection (kpSelection::Rectangle, QRect ());
+ }
+
+ kpSelection selection = *doc->selection();
+ selection.moveTo (m_startPoint);
+
+ return selection;
+}
+
+
+// public virtual [base kpComand]
+int kpToolSelectionMoveCommand::size () const
+{
+ return kpPixmapFX::pixmapSize (m_oldDocumentPixmap) +
+ kpPixmapFX::pointArraySize (m_copyOntoDocumentPoints);
+}
+
+
+// public virtual [base kpCommand]
+void kpToolSelectionMoveCommand::execute ()
+{
+#if DEBUG_KP_TOOL_SELECTION && 1
+ kdDebug () << "kpToolSelectionMoveCommand::execute()" << endl;
+#endif
+
+ kpDocument *doc = document ();
+ if (!doc)
+ {
+ kdError () << "kpToolSelectionMoveCommand::execute() no doc" << endl;
+ return;
+ }
+
+ kpSelection *sel = doc->selection ();
+
+ // have to have pulled pixmap by now
+ if (!sel || !sel->pixmap ())
+ {
+ kdError () << "kpToolSelectionMoveCommand::execute() but haven't pulled pixmap yet: "
+ << "sel=" << sel << " sel->pixmap=" << (sel ? sel->pixmap () : 0)
+ << endl;
+ return;
+ }
+
+ kpViewManager *vm = m_mainWindow ? m_mainWindow->viewManager () : 0;
+
+ if (vm)
+ vm->setQueueUpdates ();
+
+ QPointArray::ConstIterator copyOntoDocumentPointsEnd = m_copyOntoDocumentPoints.end ();
+ for (QPointArray::ConstIterator it = m_copyOntoDocumentPoints.begin ();
+ it != copyOntoDocumentPointsEnd;
+ it++)
+ {
+ sel->moveTo (*it);
+ doc->selectionCopyOntoDocument ();
+ }
+
+ sel->moveTo (m_endPoint);
+
+ if (m_mainWindow->tool ())
+ m_mainWindow->tool ()->somethingBelowTheCursorChanged ();
+
+ if (vm)
+ vm->restoreQueueUpdates ();
+}
+
+// public virtual [base kpCommand]
+void kpToolSelectionMoveCommand::unexecute ()
+{
+#if DEBUG_KP_TOOL_SELECTION && 1
+ kdDebug () << "kpToolSelectionMoveCommand::unexecute()" << endl;
+#endif
+
+ kpDocument *doc = document ();
+ if (!doc)
+ {
+ kdError () << "kpToolSelectionMoveCommand::unexecute() no doc" << endl;
+ return;
+ }
+
+ kpSelection *sel = doc->selection ();
+
+ // have to have pulled pixmap by now
+ if (!sel || !sel->pixmap ())
+ {
+ kdError () << "kpToolSelectionMoveCommand::unexecute() but haven't pulled pixmap yet: "
+ << "sel=" << sel << " sel->pixmap=" << (sel ? sel->pixmap () : 0)
+ << endl;
+ return;
+ }
+
+ kpViewManager *vm = m_mainWindow ? m_mainWindow->viewManager () : 0;
+
+ if (vm)
+ vm->setQueueUpdates ();
+
+ if (!m_oldDocumentPixmap.isNull ())
+ doc->setPixmapAt (m_oldDocumentPixmap, m_documentBoundingRect.topLeft ());
+#if DEBUG_KP_TOOL_SELECTION && 1
+ kdDebug () << "\tmove to startPoint=" << m_startPoint << endl;
+#endif
+ sel->moveTo (m_startPoint);
+
+ if (m_mainWindow->tool ())
+ m_mainWindow->tool ()->somethingBelowTheCursorChanged ();
+
+ if (vm)
+ vm->restoreQueueUpdates ();
+}
+
+// public
+void kpToolSelectionMoveCommand::moveTo (const QPoint &point, bool moveLater)
+{
+#if DEBUG_KP_TOOL_SELECTION && 0
+ kdDebug () << "kpToolSelectionMoveCommand::moveTo" << point
+ << " moveLater=" << moveLater
+ <<endl;
+#endif
+
+ if (!moveLater)
+ {
+ kpDocument *doc = document ();
+ if (!doc)
+ {
+ kdError () << "kpToolSelectionMoveCommand::moveTo() without doc" << endl;
+ return;
+ }
+
+ kpSelection *sel = doc->selection ();
+
+ // have to have pulled pixmap by now
+ if (!sel)
+ {
+ kdError () << "kpToolSelectionMoveCommand::moveTo() no sel region" << endl;
+ return;
+ }
+
+ if (!sel->pixmap ())
+ {
+ kdError () << "kpToolSelectionMoveCommand::moveTo() no sel pixmap" << endl;
+ return;
+ }
+
+ if (point == sel->topLeft ())
+ return;
+
+ sel->moveTo (point);
+ }
+
+ m_endPoint = point;
+}
+
+// public
+void kpToolSelectionMoveCommand::moveTo (int x, int y, bool moveLater)
+{
+ moveTo (QPoint (x, y), moveLater);
+}
+
+// public
+void kpToolSelectionMoveCommand::copyOntoDocument ()
+{
+#if DEBUG_KP_TOOL_SELECTION
+ kdDebug () << "kpToolSelectionMoveCommand::copyOntoDocument()" << endl;
+#endif
+
+ kpDocument *doc = document ();
+ if (!doc)
+ return;
+
+ kpSelection *sel = doc->selection ();
+
+ // have to have pulled pixmap by now
+ if (!sel)
+ {
+ kdError () << "\tkpToolSelectionMoveCommand::copyOntoDocument() without sel region" << endl;
+ return;
+ }
+
+ if (!sel->pixmap ())
+ {
+ kdError () << "kpToolSelectionMoveCommand::moveTo() no sel pixmap" << endl;
+ return;
+ }
+
+ if (m_oldDocumentPixmap.isNull ())
+ m_oldDocumentPixmap = *doc->pixmap ();
+
+ QRect selBoundingRect = sel->boundingRect ();
+ m_documentBoundingRect.unite (selBoundingRect);
+
+ doc->selectionCopyOntoDocument ();
+
+ m_copyOntoDocumentPoints.putPoints (m_copyOntoDocumentPoints.count (),
+ 1,
+ selBoundingRect.x (),
+ selBoundingRect.y ());
+}
+
+// public
+void kpToolSelectionMoveCommand::finalize ()
+{
+ if (!m_oldDocumentPixmap.isNull () && !m_documentBoundingRect.isNull ())
+ {
+ m_oldDocumentPixmap = kpTool::neededPixmap (m_oldDocumentPixmap,
+ m_documentBoundingRect);
+ }
+}
+
+
+/*
+ * kpToolSelectionResizeScaleCommand
+ */
+
+kpToolSelectionResizeScaleCommand::kpToolSelectionResizeScaleCommand (
+ kpMainWindow *mainWindow)
+ : kpNamedCommand (mainWindow->document ()->selection ()->isText () ?
+ i18n ("Text: Resize Box") :
+ i18n ("Selection: Smooth Scale"),
+ mainWindow),
+ m_smoothScaleTimer (new QTimer (this))
+{
+ m_originalSelection = *selection ();
+
+ m_newTopLeft = selection ()->topLeft ();
+ m_newWidth = selection ()->width ();
+ m_newHeight = selection ()->height ();
+
+ connect (m_smoothScaleTimer, SIGNAL (timeout ()),
+ this, SLOT (resizeScaleAndMove ()));
+}
+
+kpToolSelectionResizeScaleCommand::~kpToolSelectionResizeScaleCommand ()
+{
+}
+
+
+// public virtual
+int kpToolSelectionResizeScaleCommand::size () const
+{
+ return m_originalSelection.size ();
+}
+
+
+// public
+kpSelection kpToolSelectionResizeScaleCommand::originalSelection () const
+{
+ return m_originalSelection;
+}
+
+
+// public
+QPoint kpToolSelectionResizeScaleCommand::topLeft () const
+{
+ return m_newTopLeft;
+}
+
+// public
+void kpToolSelectionResizeScaleCommand::moveTo (const QPoint &point)
+{
+ 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)
+ 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)
+{
+#if DEBUG_KP_TOOL_SELECTION
+ kdDebug () << "kpToolSelectionResizeScaleCommand::resizeScaleAndMove(delayed="
+ << delayed << ")" << endl;
+#endif
+
+ killSmoothScaleTimer ();
+
+ kpSelection newSel;
+
+ if (selection ()->isText ())
+ {
+ newSel = m_originalSelection;
+ newSel.textResize (m_newWidth, m_newHeight);
+ }
+ else
+ {
+ newSel = kpSelection (kpSelection::Rectangle,
+ QRect (m_originalSelection.x (),
+ m_originalSelection.y (),
+ m_newWidth,
+ m_newHeight),
+ kpPixmapFX::scale (*m_originalSelection.pixmap (),
+ m_newWidth, m_newHeight,
+ !delayed/*if not delayed, smooth*/),
+ m_originalSelection.transparency ());
+
+ if (delayed)
+ {
+ // Call self with delayed==false in 200ms
+ m_smoothScaleTimer->start (200/*ms*/, true/*single shot*/);
+ }
+ }
+
+ newSel.moveTo (m_newTopLeft);
+
+ m_mainWindow->document ()->setSelection (newSel);
+}
+
+// protected slots
+void kpToolSelectionResizeScaleCommand::resizeScaleAndMove ()
+{
+#if DEBUG_KP_TOOL_SELECTION
+ kdDebug () << "kpToolSelectionResizeScaleCommand::resizeScaleAndMove()" << endl;
+#endif
+ resizeScaleAndMove (false/*no delay*/);
+}
+
+
+// public
+void kpToolSelectionResizeScaleCommand::finalize ()
+{
+#if DEBUG_KP_TOOL_SELECTION
+ kdDebug () << "kpToolSelectionResizeScaleCommand::finalize()"
+ << " smoothScaleTimer->isActive="
+ << m_smoothScaleTimer->isActive ()
+ << endl;
+#endif
+
+ // 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 ();
+
+ if (m_mainWindow->tool ())
+ m_mainWindow->tool ()->somethingBelowTheCursorChanged ();
+
+ QApplication::restoreOverrideCursor ();
+}
+
+// public virtual [base kpToolResizeScaleCommand]
+void kpToolSelectionResizeScaleCommand::unexecute ()
+{
+ QApplication::setOverrideCursor (Qt::waitCursor);
+
+ killSmoothScaleTimer ();
+
+ m_mainWindow->document ()->setSelection (m_originalSelection);
+
+ if (m_mainWindow->tool ())
+ m_mainWindow->tool ()->somethingBelowTheCursorChanged ();
+
+ QApplication::restoreOverrideCursor ();
+}
+
+
+/*
+ * kpToolSelectionDestroyCommand
+ */
+
+kpToolSelectionDestroyCommand::kpToolSelectionDestroyCommand (const QString &name,
+ bool pushOntoDocument,
+ kpMainWindow *mainWindow)
+ : kpNamedCommand (name, mainWindow),
+ m_pushOntoDocument (pushOntoDocument),
+ m_oldSelection (0)
+{
+}
+
+kpToolSelectionDestroyCommand::~kpToolSelectionDestroyCommand ()
+{
+ delete m_oldSelection;
+}
+
+
+// public virtual [base kpCommand]
+int kpToolSelectionDestroyCommand::size () const
+{
+ return kpPixmapFX::pixmapSize (m_oldDocPixmap) +
+ kpPixmapFX::selectionSize (m_oldSelection);
+}
+
+
+// public virtual [base kpCommand]
+void kpToolSelectionDestroyCommand::execute ()
+{
+#if DEBUG_KP_TOOL_SELECTION
+ kdDebug () << "kpToolSelectionDestroyCommand::execute () CALLED" << endl;
+#endif
+
+ kpDocument *doc = document ();
+ if (!doc)
+ {
+ kdError () << "kpToolSelectionDestroyCommand::execute() without doc" << endl;
+ return;
+ }
+
+ if (!doc->selection ())
+ {
+ kdError () << "kpToolSelectionDestroyCommand::execute() without sel region" << endl;
+ return;
+ }
+
+ m_textRow = m_mainWindow->viewManager ()->textCursorRow ();
+ m_textCol = m_mainWindow->viewManager ()->textCursorCol ();
+
+ m_oldSelection = new kpSelection (*doc->selection ());
+ if (m_pushOntoDocument)
+ {
+ m_oldDocPixmap = doc->getPixmapAt (doc->selection ()->boundingRect ());
+ doc->selectionPushOntoDocument ();
+ }
+ else
+ doc->selectionDelete ();
+
+ if (m_mainWindow->tool ())
+ m_mainWindow->tool ()->somethingBelowTheCursorChanged ();
+}
+
+// public virtual [base kpCommand]
+void kpToolSelectionDestroyCommand::unexecute ()
+{
+#if DEBUG_KP_TOOL_SELECTION
+ kdDebug () << "kpToolSelectionDestroyCommand::unexecute () CALLED" << endl;
+#endif
+
+ kpDocument *doc = document ();
+ if (!doc)
+ {
+ kdError () << "kpToolSelectionDestroyCommand::unexecute() without doc" << endl;
+ return;
+ }
+
+ if (doc->selection ())
+ {
+ // not error because it's possible that the user dragged out a new
+ // region (without pulling pixmap), and then CTRL+Z
+ #if DEBUG_KP_TOOL_SELECTION
+ kdDebug () << "kpToolSelectionDestroyCommand::unexecute() already has sel region" << endl;
+ #endif
+
+ if (doc->selection ()->pixmap ())
+ {
+ kdError () << "kpToolSelectionDestroyCommand::unexecute() already has sel pixmap" << endl;
+ return;
+ }
+ }
+
+ if (!m_oldSelection)
+ {
+ kdError () << "kpToolSelectionDestroyCommand::unexecute() without old sel" << endl;
+ return;
+ }
+
+ if (m_pushOntoDocument)
+ {
+ #if DEBUG_KP_TOOL_SELECTION
+ kdDebug () << "\tunpush oldDocPixmap onto doc first" << endl;
+ #endif
+ doc->setPixmapAt (m_oldDocPixmap, m_oldSelection->topLeft ());
+ }
+
+#if DEBUG_KP_TOOL_SELECTION
+ kdDebug () << "\tsetting selection to: rect=" << m_oldSelection->boundingRect ()
+ << " pixmap=" << m_oldSelection->pixmap ()
+ << " pixmap.isNull()=" << (m_oldSelection->pixmap ()
+ ?
+ m_oldSelection->pixmap ()->isNull ()
+ :
+ true)
+ << endl;
+#endif
+ if (!m_oldSelection->isText ())
+ {
+ if (m_oldSelection->transparency () != m_mainWindow->selectionTransparency ())
+ m_mainWindow->setSelectionTransparency (m_oldSelection->transparency ());
+ }
+ else
+ {
+ if (m_oldSelection->textStyle () != m_mainWindow->textStyle ())
+ m_mainWindow->setTextStyle (m_oldSelection->textStyle ());
+ }
+
+ m_mainWindow->viewManager ()->setTextCursorPosition (m_textRow, m_textCol);
+ doc->setSelection (*m_oldSelection);
+
+ if (m_mainWindow->tool ())
+ m_mainWindow->tool ()->somethingBelowTheCursorChanged ();
+
+ delete m_oldSelection;
+ m_oldSelection = 0;
+}
+
+#include <kptoolselection.moc>
diff --git a/kolourpaint/tools/kptoolselection.h b/kolourpaint/tools/kptoolselection.h
new file mode 100644
index 00000000..ee978a15
--- /dev/null
+++ b/kolourpaint/tools/kptoolselection.h
@@ -0,0 +1,313 @@
+
+/*
+ Copyright (c) 2003,2004,2005 Clarence Dang <dang@kde.org>
+ 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_selection_h__
+#define __kp_tool_selection_h__
+
+
+#include <qpixmap.h>
+#include <qpoint.h>
+#include <qpointarray.h>
+#include <qrect.h>
+
+#include <kpcolor.h>
+#include <kpcommandhistory.h>
+#include <kpselection.h>
+#include <kpselectiontransparency.h>
+#include <kptool.h>
+
+
+class QPoint;
+class QRect;
+class QTimer;
+
+class kpMainWindow;
+class kpSelection;
+
+class kpToolSelectionCreateCommand;
+class kpToolSelectionMoveCommand;
+class kpToolSelectionPullFromDocumentCommand;
+class kpToolSelectionResizeScaleCommand;
+class kpToolWidgetOpaqueOrTransparent;
+
+
+class kpToolSelection : public kpTool
+{
+Q_OBJECT
+
+public:
+ enum Mode {Rectangle, Ellipse, FreeForm, Text};
+
+ kpToolSelection (Mode mode,
+ const QString &text, const QString &description,
+ int key,
+ kpMainWindow *mainWindow, const char *name);
+ virtual ~kpToolSelection ();
+
+ void setMode (Mode mode) { m_mode = mode; }
+
+private:
+ void pushOntoDocument ();
+
+protected:
+ bool onSelectionToMove () const;
+ int onSelectionResizeHandle () const;
+ bool onSelectionToSelectText () const;
+
+public:
+ QString haventBegunDrawUserMessage () const;
+
+ virtual void begin ();
+ virtual void end ();
+ virtual void reselect ();
+
+ virtual bool careAboutModifierState () const { return true; }
+ bool controlOrShiftPressed () const { return (m_controlPressed || m_shiftPressed); }
+
+ virtual void beginDraw ();
+protected:
+ const QCursor &cursor () const;
+public:
+ virtual void hover (const QPoint &point);
+protected:
+ void popupRMBMenu ();
+ void setSelectionBorderForMove ();
+protected slots:
+ void slotRMBMoveUpdateGUI ();
+ void delayedDraw ();
+public:
+ virtual void draw (const QPoint &thisPoint, const QPoint &lastPoint,
+ const QRect &normalizedRect);
+ virtual void cancelShape ();
+ virtual void releasedAllButtons ();
+ virtual void endDraw (const QPoint &thisPoint, const QRect &normalizedRect);
+
+protected:
+ virtual void keyPressEvent (QKeyEvent *e);
+
+protected:
+ void selectionTransparencyChanged (const QString &name);
+
+protected slots:
+ virtual void slotIsOpaqueChanged ();
+ virtual void slotBackgroundColorChanged (const kpColor &color);
+ virtual void slotColorSimilarityChanged (double similarity, int);
+
+protected:
+ Mode m_mode;
+
+ QPoint m_startDragFromSelectionTopLeft;
+ enum DragType
+ {
+ Unknown, Create, Move, SelectText, ResizeScale
+ };
+ DragType m_dragType;
+ bool m_dragHasBegun;
+ bool m_hadSelectionBeforeDrag;
+ int m_resizeScaleType;
+
+ kpToolSelectionPullFromDocumentCommand *m_currentPullFromDocumentCommand;
+ kpToolSelectionMoveCommand *m_currentMoveCommand;
+ bool m_currentMoveCommandIsSmear;
+ kpToolSelectionResizeScaleCommand *m_currentResizeScaleCommand;
+ kpToolWidgetOpaqueOrTransparent *m_toolWidgetOpaqueOrTransparent;
+
+ kpToolSelectionCreateCommand *m_currentCreateTextCommand;
+ bool m_cancelledShapeButStillHoldingButtons;
+
+ QTimer *m_createNOPTimer, *m_RMBMoveUpdateGUITimer;
+};
+
+class kpToolSelectionCreateCommand : public kpNamedCommand
+{
+public:
+ // (if fromSelection doesn't have a pixmap, it will only recreate the region)
+ kpToolSelectionCreateCommand (const QString &name, const kpSelection &fromSelection,
+ kpMainWindow *mainWindow);
+ virtual ~kpToolSelectionCreateCommand ();
+
+ virtual int size () const;
+
+ static bool nextUndoCommandIsCreateBorder (kpCommandHistory *commandHistory);
+
+ const kpSelection *fromSelection () const;
+ void setFromSelection (const kpSelection &fromSelection);
+
+ virtual void execute ();
+ virtual void unexecute ();
+
+private:
+ kpSelection *m_fromSelection;
+
+ int m_textRow, m_textCol;
+};
+
+class kpToolSelectionPullFromDocumentCommand : public kpNamedCommand
+{
+public:
+ kpToolSelectionPullFromDocumentCommand (const QString &name, kpMainWindow *mainWindow);
+ virtual ~kpToolSelectionPullFromDocumentCommand ();
+
+ virtual int size () const;
+
+ virtual void execute ();
+ virtual void unexecute ();
+
+private:
+ kpColor m_backgroundColor;
+ kpSelection *m_originalSelectionRegion;
+};
+
+class kpToolSelectionTransparencyCommand : public kpNamedCommand
+{
+public:
+ kpToolSelectionTransparencyCommand (const QString &name,
+ const kpSelectionTransparency &st,
+ const kpSelectionTransparency &oldST,
+ kpMainWindow *mainWindow);
+ virtual ~kpToolSelectionTransparencyCommand ();
+
+ virtual int size () const;
+
+ virtual void execute ();
+ virtual void unexecute ();
+
+private:
+ kpSelectionTransparency m_st, m_oldST;
+};
+
+class kpToolSelectionMoveCommand : public kpNamedCommand
+{
+public:
+ kpToolSelectionMoveCommand (const QString &name, kpMainWindow *mainWindow);
+ virtual ~kpToolSelectionMoveCommand ();
+
+ kpSelection originalSelection () const;
+
+ virtual int size () const;
+
+ virtual void execute ();
+ virtual void unexecute ();
+
+ void moveTo (const QPoint &point, bool moveLater = false);
+ void moveTo (int x, int y, bool moveLater = false);
+ void copyOntoDocument ();
+ void finalize ();
+
+private:
+ QPoint m_startPoint, m_endPoint;
+
+ QPixmap m_oldDocumentPixmap;
+
+ // area of document affected (not the bounding rect of the sel)
+ QRect m_documentBoundingRect;
+
+ QPointArray m_copyOntoDocumentPoints;
+};
+
+// You could subclass kpToolResizeScaleCommand and/or
+// kpToolSelectionMoveCommand instead if want a disaster.
+// This is different to kpToolResizeScaleCommand in that:
+//
+// 1. This only works for selections.
+// 2. This is designed for the size and position to change several times
+// before execute().
+//
+class kpToolSelectionResizeScaleCommand : public QObject,
+ public kpNamedCommand
+{
+Q_OBJECT
+
+public:
+ kpToolSelectionResizeScaleCommand (kpMainWindow *mainWindow);
+ virtual ~kpToolSelectionResizeScaleCommand ();
+
+ virtual int size () const;
+
+public:
+ kpSelection originalSelection () const;
+
+ QPoint topLeft () const;
+ void moveTo (const QPoint &point);
+
+ int width () const;
+ int height () const;
+ void resize (int width, int height, bool delayed = false);
+
+ // (equivalent to resize() followed by moveTo() but faster)
+ void resizeAndMoveTo (int width, int height, const QPoint &point,
+ bool delayed = false);
+
+protected:
+ void killSmoothScaleTimer ();
+
+ // If <delayed>, does a fast, low-quality scale and then calls itself
+ // with <delayed> unset for a smooth scale, a short time later.
+ // If acting on a text box, <delayed> is ignored.
+ void resizeScaleAndMove (bool delayed);
+
+protected slots:
+ void resizeScaleAndMove (/*delayed = false*/);
+
+public:
+ void finalize ();
+
+public:
+ virtual void execute ();
+ virtual void unexecute ();
+
+protected:
+ kpSelection m_originalSelection;
+
+ QPoint m_newTopLeft;
+ int m_newWidth, m_newHeight;
+
+ QTimer *m_smoothScaleTimer;
+};
+
+class kpToolSelectionDestroyCommand : public kpNamedCommand
+{
+public:
+ kpToolSelectionDestroyCommand (const QString &name, bool pushOntoDocument,
+ kpMainWindow *mainWindow);
+ virtual ~kpToolSelectionDestroyCommand ();
+
+ virtual int size () const;
+
+ virtual void execute ();
+ virtual void unexecute ();
+
+private:
+ bool m_pushOntoDocument;
+ QPixmap m_oldDocPixmap;
+ kpSelection *m_oldSelection;
+
+ int m_textRow, m_textCol;
+};
+
+#endif // __kp_tool_selection_h__
diff --git a/kolourpaint/tools/kptoolskew.cpp b/kolourpaint/tools/kptoolskew.cpp
new file mode 100644
index 00000000..f1e446be
--- /dev/null
+++ b/kolourpaint/tools/kptoolskew.cpp
@@ -0,0 +1,449 @@
+
+/*
+ Copyright (c) 2003,2004,2005 Clarence Dang <dang@kde.org>
+ 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 <kptoolskew.h>
+
+#include <qapplication.h>
+#include <qgroupbox.h>
+#include <qlabel.h>
+#include <qlayout.h>
+#include <qpushbutton.h>
+#include <qwmatrix.h>
+
+#include <kdebug.h>
+#include <kiconloader.h>
+#include <klocale.h>
+#include <knuminput.h>
+
+#include <kpdefs.h>
+#include <kpdocument.h>
+#include <kpmainwindow.h>
+#include <kppixmapfx.h>
+#include <kpselection.h>
+#include <kptool.h>
+
+
+/*
+ * kpToolSkewCommand
+ */
+
+kpToolSkewCommand::kpToolSkewCommand (bool actOnSelection,
+ int hangle, int vangle,
+ kpMainWindow *mainWindow)
+ : kpCommand (mainWindow),
+ m_actOnSelection (actOnSelection),
+ m_hangle (hangle), m_vangle (vangle),
+ m_backgroundColor (mainWindow ? mainWindow->backgroundColor (actOnSelection) : kpColor::invalid),
+ m_oldPixmapPtr (0)
+{
+}
+
+kpToolSkewCommand::~kpToolSkewCommand ()
+{
+ delete m_oldPixmapPtr;
+}
+
+
+// public virtual [base kpCommand]
+QString kpToolSkewCommand::name () const
+{
+ QString opName = i18n ("Skew");
+
+ if (m_actOnSelection)
+ return i18n ("Selection: %1").arg (opName);
+ else
+ return opName;
+}
+
+
+// public virtual [base kpCommand]
+int kpToolSkewCommand::size () const
+{
+ return kpPixmapFX::pixmapSize (m_oldPixmapPtr) +
+ m_oldSelection.size ();
+}
+
+
+// public virtual [base kpCommand]
+void kpToolSkewCommand::execute ()
+{
+ kpDocument *doc = document ();
+ if (!doc)
+ return;
+
+
+ QApplication::setOverrideCursor (Qt::waitCursor);
+
+
+ m_oldPixmapPtr = new QPixmap ();
+ *m_oldPixmapPtr = *doc->pixmap (m_actOnSelection);
+
+
+ QPixmap newPixmap = kpPixmapFX::skew (*doc->pixmap (m_actOnSelection),
+ kpToolSkewDialog::horizontalAngleForPixmapFX (m_hangle),
+ kpToolSkewDialog::verticalAngleForPixmapFX (m_vangle),
+ m_backgroundColor);
+
+ if (m_actOnSelection)
+ {
+ kpSelection *sel = doc->selection ();
+
+ // Save old selection
+ m_oldSelection = *sel;
+
+
+ // Calculate skewed points
+ QPointArray currentPoints = sel->points ();
+ currentPoints.translate (-currentPoints.boundingRect ().x (),
+ -currentPoints.boundingRect ().y ());
+ QWMatrix skewMatrix = kpPixmapFX::skewMatrix (
+ *doc->pixmap (m_actOnSelection),
+ kpToolSkewDialog::horizontalAngleForPixmapFX (m_hangle),
+ kpToolSkewDialog::verticalAngleForPixmapFX (m_vangle));
+ currentPoints = skewMatrix.map (currentPoints);
+ currentPoints.translate (-currentPoints.boundingRect ().x () + m_oldSelection.x (),
+ -currentPoints.boundingRect ().y () + m_oldSelection.y ());
+
+
+ if (currentPoints.boundingRect ().width () == newPixmap.width () &&
+ currentPoints.boundingRect ().height () == newPixmap.height ())
+ {
+ doc->setSelection (kpSelection (currentPoints, newPixmap,
+ m_oldSelection.transparency ()));
+ }
+ else
+ {
+ // TODO: fix the latter "victim of" problem in kpSelection by
+ // allowing the border width & height != pixmap width & height
+ // Or maybe autocrop?
+ #if DEBUG_KP_TOOL_SKEW
+ kdDebug () << "kpToolSkewCommand::execute() currentPoints.boundingRect="
+ << currentPoints.boundingRect ()
+ << " newPixmap: w=" << newPixmap.width ()
+ << " h=" << newPixmap.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;
+ #endif
+ doc->setSelection (kpSelection (kpSelection::Rectangle,
+ QRect (currentPoints.boundingRect ().x (),
+ currentPoints.boundingRect ().y (),
+ newPixmap.width (),
+ newPixmap.height ()),
+ newPixmap,
+ m_oldSelection.transparency ()));
+ }
+
+ if (m_mainWindow->tool ())
+ m_mainWindow->tool ()->somethingBelowTheCursorChanged ();
+ }
+ else
+ {
+ doc->setPixmap (newPixmap);
+ }
+
+
+ QApplication::restoreOverrideCursor ();
+}
+
+// public virtual [base kpCommand]
+void kpToolSkewCommand::unexecute ()
+{
+ kpDocument *doc = document ();
+ if (!doc)
+ return;
+
+
+ QApplication::setOverrideCursor (Qt::waitCursor);
+
+
+ QPixmap oldPixmap = *m_oldPixmapPtr;
+ delete m_oldPixmapPtr; m_oldPixmapPtr = 0;
+
+
+ if (!m_actOnSelection)
+ doc->setPixmap (oldPixmap);
+ else
+ {
+ kpSelection oldSelection = m_oldSelection;
+ doc->setSelection (oldSelection);
+
+ if (m_mainWindow->tool ())
+ m_mainWindow->tool ()->somethingBelowTheCursorChanged ();
+ }
+
+
+ QApplication::restoreOverrideCursor ();
+}
+
+
+/*
+ * kpToolSkewDialog
+ */
+
+
+// private static
+int kpToolSkewDialog::s_lastWidth = -1,
+ kpToolSkewDialog::s_lastHeight = -1;
+
+// private static
+int kpToolSkewDialog::s_lastHorizontalAngle = 0,
+ kpToolSkewDialog::s_lastVerticalAngle = 0;
+
+
+kpToolSkewDialog::kpToolSkewDialog (bool actOnSelection, kpMainWindow *parent,
+ const char *name)
+ : kpToolPreviewDialog (kpToolPreviewDialog::AllFeatures,
+ false/*don't reserve top row*/,
+ actOnSelection ? i18n ("Skew Selection") : i18n ("Skew Image"),
+ i18n ("After Skew:"),
+ actOnSelection, parent, name)
+{
+ // Too confusing - disable for now
+ s_lastHorizontalAngle = s_lastVerticalAngle = 0;
+
+
+ createAngleGroupBox ();
+
+
+ if (s_lastWidth > 0 && s_lastHeight > 0)
+ resize (s_lastWidth, s_lastHeight);
+
+
+ slotUpdate ();
+
+
+ m_horizontalSkewInput->setEditFocus ();
+}
+
+kpToolSkewDialog::~kpToolSkewDialog ()
+{
+ s_lastWidth = width (), s_lastHeight = height ();
+}
+
+
+// private
+void kpToolSkewDialog::createAngleGroupBox ()
+{
+ QGroupBox *angleGroupBox = new QGroupBox (i18n ("Angle"), mainWidget ());
+ addCustomWidget (angleGroupBox);
+
+
+ QLabel *horizontalSkewPixmapLabel = new QLabel (angleGroupBox);
+ horizontalSkewPixmapLabel->setPixmap (UserIcon ("image_skew_horizontal"));
+
+ QLabel *horizontalSkewLabel = new QLabel (i18n ("&Horizontal:"), angleGroupBox);
+ m_horizontalSkewInput = new KIntNumInput (s_lastHorizontalAngle, angleGroupBox);
+ m_horizontalSkewInput->setMinValue (-89);
+ m_horizontalSkewInput->setMaxValue (+89);
+
+ QLabel *horizontalSkewDegreesLabel = new QLabel (i18n ("degrees"), angleGroupBox);
+
+
+ QLabel *verticalSkewPixmapLabel = new QLabel (angleGroupBox);
+ verticalSkewPixmapLabel->setPixmap (UserIcon ("image_skew_vertical"));
+
+ QLabel *verticalSkewLabel = new QLabel (i18n ("&Vertical:"), angleGroupBox);
+ m_verticalSkewInput = new KIntNumInput (s_lastVerticalAngle, angleGroupBox);
+ m_verticalSkewInput->setMinValue (-89);
+ m_verticalSkewInput->setMaxValue (+89);
+
+ QLabel *verticalSkewDegreesLabel = new QLabel (i18n ("degrees"), angleGroupBox);
+
+
+ horizontalSkewLabel->setBuddy (m_horizontalSkewInput);
+ verticalSkewLabel->setBuddy (m_verticalSkewInput);
+
+
+ QGridLayout *angleLayout = new QGridLayout (angleGroupBox, 4, 4,
+ marginHint () * 2, spacingHint ());
+
+ angleLayout->addWidget (horizontalSkewPixmapLabel, 0, 0);
+ angleLayout->addWidget (horizontalSkewLabel, 0, 1);
+ angleLayout->addWidget (m_horizontalSkewInput, 0, 2);
+ angleLayout->addWidget (horizontalSkewDegreesLabel, 0, 3);
+
+ angleLayout->addWidget (verticalSkewPixmapLabel, 1, 0);
+ angleLayout->addWidget (verticalSkewLabel, 1, 1);
+ angleLayout->addWidget (m_verticalSkewInput, 1, 2);
+ angleLayout->addWidget (verticalSkewDegreesLabel, 1, 3);
+
+
+ connect (m_horizontalSkewInput, SIGNAL (valueChanged (int)),
+ this, SLOT (slotUpdate ()));
+ connect (m_verticalSkewInput, SIGNAL (valueChanged (int)),
+ this, SLOT (slotUpdate ()));
+}
+
+
+// private virtual [base kpToolPreviewDialog]
+QSize kpToolSkewDialog::newDimensions () const
+{
+ kpDocument *doc = document ();
+ if (!doc)
+ return QSize ();
+
+ QWMatrix skewMatrix = kpPixmapFX::skewMatrix (*doc->pixmap (),
+ horizontalAngleForPixmapFX (),
+ verticalAngleForPixmapFX ());
+ // TODO: Should we be using QWMatrix::Areas?
+ QRect skewRect = skewMatrix.mapRect (doc->rect (m_actOnSelection));
+
+ return QSize (skewRect.width (), skewRect.height ());
+}
+
+// private virtual [base kpToolPreviewDialog]
+QPixmap kpToolSkewDialog::transformPixmap (const QPixmap &pixmap,
+ int targetWidth, int targetHeight) const
+{
+ return kpPixmapFX::skew (pixmap,
+ horizontalAngleForPixmapFX (),
+ verticalAngleForPixmapFX (),
+ m_mainWindow ? m_mainWindow->backgroundColor (m_actOnSelection) : kpColor::invalid,
+ targetWidth,
+ targetHeight);
+}
+
+
+// private
+void kpToolSkewDialog::updateLastAngles ()
+{
+ s_lastHorizontalAngle = horizontalAngle ();
+ s_lastVerticalAngle = verticalAngle ();
+}
+
+// private slot virtual [base kpToolPreviewDialog]
+void kpToolSkewDialog::slotUpdate ()
+{
+ updateLastAngles ();
+ kpToolPreviewDialog::slotUpdate ();
+}
+
+
+// public
+int kpToolSkewDialog::horizontalAngle () const
+{
+ return m_horizontalSkewInput->value ();
+}
+
+// public
+int kpToolSkewDialog::verticalAngle () const
+{
+ return m_verticalSkewInput->value ();
+}
+
+
+// public static
+int kpToolSkewDialog::horizontalAngleForPixmapFX (int hangle)
+{
+ return -hangle;
+}
+
+// public static
+int kpToolSkewDialog::verticalAngleForPixmapFX (int vangle)
+{
+ return -vangle;
+}
+
+
+// public
+int kpToolSkewDialog::horizontalAngleForPixmapFX () const
+{
+ return kpToolSkewDialog::horizontalAngleForPixmapFX (horizontalAngle ());
+}
+
+// public
+int kpToolSkewDialog::verticalAngleForPixmapFX () const
+{
+ return kpToolSkewDialog::verticalAngleForPixmapFX (verticalAngle ());
+}
+
+
+// public virtual [base kpToolPreviewDialog]
+bool kpToolSkewDialog::isNoOp () const
+{
+ return (horizontalAngle () == 0) && (verticalAngle () == 0);
+}
+
+
+// private slot virtual [base KDialogBase]
+void kpToolSkewDialog::slotOk ()
+{
+ QString message, caption, continueButtonText;
+
+ if (document ()->selection ())
+ {
+ if (!document ()->selection ()->isText ())
+ {
+ message =
+ i18n ("<qt><p>Skewing the selection to %1x%2"
+ " may take a substantial amount of memory."
+ " This can reduce system"
+ " responsiveness and cause other application resource"
+ " problems.</p>"
+
+ "<p>Are you sure want to skew the selection?</p></qt>");
+
+ caption = i18n ("Skew Selection?");
+ continueButtonText = i18n ("Sk&ew Selection");
+ }
+ }
+ else
+ {
+ message =
+ i18n ("<qt><p>Skewing the image to %1x%2"
+ " may take a substantial amount of memory."
+ " This can reduce system"
+ " responsiveness and cause other application resource"
+ " problems.</p>"
+
+ "<p>Are you sure want to skew the image?</p></qt>");
+
+ caption = i18n ("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.arg (newWidth).arg (newHeight),
+ caption,
+ continueButtonText,
+ this))
+ {
+ KDialogBase::slotOk ();
+ }
+}
+
+#include <kptoolskew.moc>
diff --git a/kolourpaint/tools/kptoolskew.h b/kolourpaint/tools/kptoolskew.h
new file mode 100644
index 00000000..570909c2
--- /dev/null
+++ b/kolourpaint/tools/kptoolskew.h
@@ -0,0 +1,121 @@
+
+/*
+ Copyright (c) 2003,2004,2005 Clarence Dang <dang@kde.org>
+ 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 __kptool_skew_h__
+#define __kptool_skew_h__
+
+#include <qpixmap.h>
+
+#include <kpcommandhistory.h>
+#include <kdialogbase.h>
+
+#include <kpcolor.h>
+#include <kpselection.h>
+#include <kptoolpreviewdialog.h>
+
+class QGroupBox;
+class QLabel;
+class QPixmap;
+
+class KIntNumInput;
+
+class kpDocument;
+class kpMainWindow;
+
+
+class kpToolSkewCommand : public kpCommand
+{
+public:
+ kpToolSkewCommand (bool actOnSelection,
+ int hangle, int vangle,
+ kpMainWindow *mainWindow);
+ virtual ~kpToolSkewCommand ();
+
+ virtual QString name () const;
+
+ virtual int size () const;
+
+ virtual void execute ();
+ virtual void unexecute ();
+
+private:
+ bool m_actOnSelection;
+ int m_hangle, m_vangle;
+
+ kpColor m_backgroundColor;
+ QPixmap *m_oldPixmapPtr;
+ kpSelection m_oldSelection;
+};
+
+
+class kpToolSkewDialog : public kpToolPreviewDialog
+{
+Q_OBJECT
+
+public:
+ kpToolSkewDialog (bool actOnSelection, kpMainWindow *parent,
+ const char *name = 0);
+ virtual ~kpToolSkewDialog ();
+
+private:
+ static int s_lastWidth, s_lastHeight;
+ static int s_lastHorizontalAngle, s_lastVerticalAngle;
+
+ void createAngleGroupBox ();
+
+ virtual QSize newDimensions () const;
+ virtual QPixmap transformPixmap (const QPixmap &pixmap,
+ int targetWidth, int targetHeight) const;
+
+ void updateLastAngles ();
+
+private slots:
+ virtual void slotUpdate ();
+
+public:
+ // These are the angles the users sees in the dialog and...
+ int horizontalAngle () const;
+ int verticalAngle () const;
+
+ // ...these functions translate them for use in kpPixmapFX::skew().
+ static int horizontalAngleForPixmapFX (int hangle);
+ static int verticalAngleForPixmapFX (int vangle);
+
+ int horizontalAngleForPixmapFX () const;
+ int verticalAngleForPixmapFX () const;
+
+ virtual bool isNoOp () const;
+
+private slots:
+ virtual void slotOk ();
+
+private:
+ KIntNumInput *m_horizontalSkewInput, *m_verticalSkewInput;
+};
+
+#endif // __kptool_skew_h__
diff --git a/kolourpaint/tools/kptooltext.cpp b/kolourpaint/tools/kptooltext.cpp
new file mode 100644
index 00000000..73a60e66
--- /dev/null
+++ b/kolourpaint/tools/kptooltext.cpp
@@ -0,0 +1,1394 @@
+
+/*
+ Copyright (c) 2003,2004,2005 Clarence Dang <dang@kde.org>
+ 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 <kptooltext.h>
+
+#include <qvaluevector.h>
+
+#include <kdebug.h>
+#include <klocale.h>
+
+#include <kpcommandhistory.h>
+#include <kpdocument.h>
+#include <kpmainwindow.h>
+#include <kpselection.h>
+#include <kptoolwidgetopaqueortransparent.h>
+#include <kpviewmanager.h>
+
+
+kpToolText::kpToolText (kpMainWindow *mainWindow)
+ : kpToolSelection (Text,
+ i18n ("Text"), i18n ("Writes text"),
+ Qt::Key_T,
+ mainWindow, "tool_text"),
+ m_isIMStarted (false),
+ m_IMStartCursorRow (0),
+ m_IMStartCursorCol (0),
+ m_IMPreeditStr (0)
+{
+}
+
+kpToolText::~kpToolText ()
+{
+}
+
+
+// public virtual [base kpToolSelection]
+void kpToolText::begin ()
+{
+#if DEBUG_KP_TOOL_TEXT && 1
+ kdDebug () << "kpToolText::begin()" << endl;
+#endif
+
+ mainWindow ()->enableTextToolBarActions (true);
+ viewManager ()->setTextCursorEnabled (true);
+
+ m_insertCommand = 0;
+ m_enterCommand = 0;
+ m_backspaceCommand = 0;
+ m_deleteCommand = 0;
+
+ kpToolSelection::begin ();
+}
+
+// public virtual [base kpToolSelection]
+void kpToolText::end ()
+{
+#if DEBUG_KP_TOOL_TEXT && 1
+ kdDebug () << "kpToolText::end()" << endl;
+#endif
+
+ kpToolSelection::end ();
+
+ viewManager ()->setTextCursorEnabled (false);
+ mainWindow ()->enableTextToolBarActions (false);
+}
+
+
+// public
+bool kpToolText::hasBegunText () const
+{
+ return (m_insertCommand ||
+ m_enterCommand ||
+ m_backspaceCommand ||
+ m_deleteCommand);
+}
+
+// public virtual [base kpTool]
+bool kpToolText::hasBegunShape () const
+{
+ return (hasBegunDraw () || hasBegunText ());
+}
+
+
+// public virtual [base kpToolSelection]
+void kpToolText::cancelShape ()
+{
+#if DEBUG_KP_TOOL_TEXT
+ kdDebug () << "kpToolText::cancelShape()" << endl;
+#endif
+
+ if (m_dragType != Unknown)
+ kpToolSelection::cancelShape ();
+ else if (hasBegunText ())
+ {
+ m_insertCommand = 0;
+ m_enterCommand = 0;
+ m_backspaceCommand = 0;
+ m_deleteCommand = 0;
+
+ commandHistory ()->undo ();
+ }
+ else
+ kpToolSelection::cancelShape ();
+}
+
+// public virtual [base kpTool]
+void kpToolText::endShape (const QPoint &thisPoint, const QRect &normalizedRect)
+{
+#if DEBUG_KP_TOOL_TEXT
+ kdDebug () << "kpToolText::endShape()" << endl;
+#endif
+
+ if (m_dragType != Unknown)
+ kpToolSelection::endDraw (thisPoint, normalizedRect);
+ else if (hasBegunText ())
+ {
+ m_insertCommand = 0;
+ m_enterCommand = 0;
+ m_backspaceCommand = 0;
+ m_deleteCommand = 0;
+ }
+ else
+ kpToolSelection::endDraw (thisPoint, normalizedRect);
+}
+
+
+// protected virtual [base kpTool]
+void kpToolText::keyPressEvent (QKeyEvent *e)
+{
+#if DEBUG_KP_TOOL_TEXT
+ kdDebug () << "kpToolText::keyPressEvent(e->text='" << e->text () << "')" << endl;
+#endif
+
+
+ e->ignore ();
+
+
+ if (hasBegunDraw ())
+ {
+ #if DEBUG_KP_TOOL_TEXT
+ kdDebug () << "\talready began draw with mouse - passing on event to kpTool" << endl;
+ #endif
+ kpToolSelection::keyPressEvent (e);
+ return;
+ }
+
+
+ kpSelection *sel = document ()->selection ();
+
+ if (!sel || !sel->isText ())
+ {
+ #if DEBUG_KP_TOOL_TEXT
+ kdDebug () << "\tno text sel - passing on event to kpTool" << endl;
+ #endif
+ //if (hasBegunShape ())
+ // endShape (m_currentPoint, QRect (m_startPoint, m_currentPoint).normalize ());
+
+ kpToolSelection::keyPressEvent (e);
+ return;
+ }
+
+
+ const QValueVector <QString> textLines = sel->textLines ();
+ int cursorRow = viewManager ()->textCursorRow ();
+ int cursorCol = viewManager ()->textCursorCol ();
+
+
+#define IS_SPACE(c) ((c).isSpace () || (c).isNull ())
+ if (e->key () == Qt::Key_Enter || e->key () == Qt::Key_Return)
+ {
+ #if DEBUG_KP_TOOL_TEXT
+ kdDebug () << "\tenter pressed" << endl;
+ #endif
+ if (!m_enterCommand)
+ {
+ // TODO: why not endShapeInternal(); ditto for everywhere else in this file?
+ if (hasBegunShape ())
+ endShape (m_currentPoint, QRect (m_startPoint, m_currentPoint).normalize ());
+
+ m_enterCommand = new kpToolTextEnterCommand (i18n ("Text: New Line"),
+ viewManager ()->textCursorRow (), viewManager ()->textCursorCol (),
+ mainWindow ());
+ commandHistory ()->addCommand (m_enterCommand, false/*no exec*/);
+ }
+ else
+ m_enterCommand->addEnter ();
+
+ e->accept ();
+ }
+ else if (e->key () == Qt::Key_Backspace)
+ {
+ #if DEBUG_KP_TOOL_TEXT
+ kdDebug () << "\tbackspace pressed" << endl;
+ #endif
+
+ if (!m_backspaceCommand)
+ {
+ if (hasBegunShape ())
+ endShape (m_currentPoint, QRect (m_startPoint, m_currentPoint).normalize ());
+
+ m_backspaceCommand = new kpToolTextBackspaceCommand (i18n ("Text: Backspace"),
+ viewManager ()->textCursorRow (), viewManager ()->textCursorCol (),
+ mainWindow ());
+ commandHistory ()->addCommand (m_backspaceCommand, false/*no exec*/);
+ }
+ else
+ m_backspaceCommand->addBackspace ();
+
+ e->accept ();
+ }
+ else if (e->key () == Qt::Key_Delete)
+ {
+ #if DEBUG_KP_TOOL_TEXT
+ kdDebug () << "\tdelete pressed" << endl;
+ #endif
+
+ if (!m_deleteCommand)
+ {
+ if (hasBegunShape ())
+ endShape (m_currentPoint, QRect (m_startPoint, m_currentPoint).normalize ());
+
+ m_deleteCommand = new kpToolTextDeleteCommand (i18n ("Text: Delete"),
+ viewManager ()->textCursorRow (), viewManager ()->textCursorCol (),
+ mainWindow ());
+ commandHistory ()->addCommand (m_deleteCommand, false/*no exec*/);
+ }
+ else
+ m_deleteCommand->addDelete ();
+
+ e->accept ();
+ }
+ else if (e->key () == Qt::Key_Up)
+ {
+ #if DEBUG_KP_TOOL_TEXT
+ kdDebug () << "\tup pressed" << endl;
+ #endif
+
+ if (hasBegunShape ())
+ endShape (m_currentPoint, QRect (m_startPoint, m_currentPoint).normalize ());
+
+ if (cursorRow > 0)
+ {
+ cursorRow--;
+ cursorCol = QMIN (cursorCol, (int) textLines [cursorRow].length ());
+ viewManager ()->setTextCursorPosition (cursorRow, cursorCol);
+ }
+
+ e->accept ();
+ }
+ else if (e->key () == Qt::Key_Down)
+ {
+ #if DEBUG_KP_TOOL_TEXT
+ kdDebug () << "\tdown pressed" << endl;
+ #endif
+
+ if (hasBegunShape ())
+ endShape (m_currentPoint, QRect (m_startPoint, m_currentPoint).normalize ());
+
+ if (cursorRow < (int) textLines.size () - 1)
+ {
+ cursorRow++;
+ cursorCol = QMIN (cursorCol, (int) textLines [cursorRow].length ());
+ viewManager ()->setTextCursorPosition (cursorRow, cursorCol);
+ }
+
+ e->accept ();
+ }
+ else if (e->key () == Qt::Key_Left)
+ {
+ #if DEBUG_KP_TOOL_TEXT
+ kdDebug () << "\tleft pressed" << endl;
+ #endif
+
+ #define MOVE_CURSOR_LEFT() \
+ { \
+ cursorCol--; \
+ \
+ if (cursorCol < 0) \
+ { \
+ cursorRow--; \
+ if (cursorRow < 0) \
+ { \
+ cursorRow = 0; \
+ cursorCol = 0; \
+ } \
+ else \
+ cursorCol = textLines [cursorRow].length (); \
+ } \
+ }
+
+ if (hasBegunShape ())
+ endShape (m_currentPoint, QRect (m_startPoint, m_currentPoint).normalize ());
+
+ if ((e->state () & Qt::ControlButton) == 0)
+ {
+ #if DEBUG_KP_TOOL_TEXT
+ kdDebug () << "\tmove single char" << endl;
+ #endif
+
+ MOVE_CURSOR_LEFT ();
+ viewManager ()->setTextCursorPosition (cursorRow, cursorCol);
+ }
+ else
+ {
+ #if DEBUG_KP_TOOL_TEXT
+ kdDebug () << "\tmove to start of word" << endl;
+ #endif
+
+ // (these comments will exclude the row=0,col=0 boundary case)
+
+ #define IS_ON_ANCHOR() (!IS_SPACE (textLines [cursorRow][cursorCol]) && \
+ (cursorCol == 0 || IS_SPACE (textLines [cursorRow][cursorCol - 1])))
+ 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_SPACE (textLines [cursorRow][cursorCol])))
+ {
+ 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
+
+ viewManager ()->setTextCursorPosition (cursorRow, cursorCol);
+ }
+
+ #undef MOVE_CURSOR_LEFT
+
+ e->accept ();
+
+ }
+ else if (e->key () == Qt::Key_Right)
+ {
+ #if DEBUG_KP_TOOL_TEXT
+ kdDebug () << "\tright pressed" << endl;
+ #endif
+
+ #define MOVE_CURSOR_RIGHT() \
+ { \
+ cursorCol++; \
+ \
+ if (cursorCol > (int) textLines [cursorRow].length ()) \
+ { \
+ cursorRow++; \
+ if (cursorRow > (int) textLines.size () - 1) \
+ { \
+ cursorRow = textLines.size () - 1; \
+ cursorCol = textLines [cursorRow].length (); \
+ } \
+ else \
+ cursorCol = 0; \
+ } \
+ }
+
+ if (hasBegunShape ())
+ endShape (m_currentPoint, QRect (m_startPoint, m_currentPoint).normalize ());
+
+ if ((e->state () & Qt::ControlButton) == 0)
+ {
+ #if DEBUG_KP_TOOL_TEXT
+ kdDebug () << "\tmove single char" << endl;
+ #endif
+
+ MOVE_CURSOR_RIGHT ();
+ viewManager ()->setTextCursorPosition (cursorRow, cursorCol);
+ }
+ else
+ {
+ #if DEBUG_KP_TOOL_TEXT
+ kdDebug () << "\tmove to start of word" << endl;
+ #endif
+
+ // (these comments will exclude the last row,end col boundary case)
+
+ #define IS_AT_END() (cursorRow == (int) textLines.size () - 1 && \
+ cursorCol == (int) textLines [cursorRow].length ())
+
+ // Find space
+ while (!IS_AT_END () && !IS_SPACE (textLines [cursorRow][cursorCol]))
+ {
+ MOVE_CURSOR_RIGHT ();
+ }
+
+ // --- now we're on a space ---
+
+ // Find letter
+ while (!IS_AT_END () && IS_SPACE (textLines [cursorRow][cursorCol]))
+ {
+ MOVE_CURSOR_RIGHT ();
+ }
+
+ // --- now we're on a letter ---
+
+ viewManager ()->setTextCursorPosition (cursorRow, cursorCol);
+
+ #undef IS_AT_END
+ }
+
+ #undef MOVE_CURSOR_RIGHT
+
+ e->accept ();
+ }
+ else if (e->key () == Qt::Key_Home)
+ {
+ #if DEBUG_KP_TOOL_TEXT
+ kdDebug () << "\thome pressed" << endl;
+ #endif
+
+ if (hasBegunShape ())
+ endShape (m_currentPoint, QRect (m_startPoint, m_currentPoint).normalize ());
+
+ if (e->state () & Qt::ControlButton)
+ cursorRow = 0;
+
+ cursorCol = 0;
+
+ viewManager ()->setTextCursorPosition (cursorRow, cursorCol);
+
+ e->accept ();
+ }
+ else if (e->key () == Qt::Key_End)
+ {
+ #if DEBUG_KP_TOOL_TEXT
+ kdDebug () << "\tend pressed" << endl;
+ #endif
+
+ if (hasBegunShape ())
+ endShape (m_currentPoint, QRect (m_startPoint, m_currentPoint).normalize ());
+
+ if (e->state () & Qt::ControlButton)
+ cursorRow = textLines.size () - 1;
+
+ cursorCol = textLines [cursorRow].length ();
+
+ viewManager ()->setTextCursorPosition (cursorRow, cursorCol);
+
+ e->accept ();
+ }
+ else
+ {
+ #if DEBUG_KP_TOOL_TEXT
+ kdDebug () << "\ttext='" << e->text () << "'" << endl;
+ #endif
+ QString usableText;
+ for (int i = 0; i < (int) e->text ().length (); i++)
+ {
+ if (e->text ().at (i).isPrint ())
+ usableText += e->text ().at (i);
+ }
+ #if DEBUG_KP_TOOL_TEXT
+ kdDebug () << "\tusableText='" << usableText << "'" << endl;
+ #endif
+
+ if (usableText.length () > 0)
+ {
+ if (!m_insertCommand)
+ {
+ if (hasBegunShape ())
+ endShape (m_currentPoint, QRect (m_startPoint, m_currentPoint).normalize ());
+
+ m_insertCommand = new kpToolTextInsertCommand (i18n ("Text: Write"),
+ viewManager ()->textCursorRow (), viewManager ()->textCursorCol (),
+ usableText,
+ mainWindow ());
+ commandHistory ()->addCommand (m_insertCommand, false/*no exec*/);
+ }
+ else
+ m_insertCommand->addText (usableText);
+
+ e->accept ();
+ }
+ }
+#undef IS_SPACE
+
+
+ if (!e->isAccepted ())
+ {
+ #if DEBUG_KP_TOOL_TEXT
+ kdDebug () << "\tkey processing did not accept (text was '"
+ << e->text ()
+ << "') - passing on event to kpToolSelection"
+ << endl;
+ #endif
+ //if (hasBegunShape ())
+ // endShape (m_currentPoint, QRect (m_startPoint, m_currentPoint).normalize ());
+
+ kpToolSelection::keyPressEvent (e);
+ return;
+ }
+}
+
+void kpToolText::imStartEvent (QIMEvent *e)
+{
+#if DEBUG_KP_TOOL_TEXT && 1
+ kdDebug () << "kpToolText::imStartEvent() text='" << e->text ()
+ << " cursorPos=" << e->cursorPos ()
+ << " selectionLength=" << e->selectionLength ()
+ << endl;
+#endif
+
+ kpSelection *sel = document ()->selection ();
+ if (hasBegunDraw() || !sel || !sel->isText ())
+ {
+ e->ignore();
+ return;
+ }
+
+ m_IMStartCursorRow = viewManager ()->textCursorRow ();
+ m_IMStartCursorCol = viewManager ()->textCursorCol ();
+ m_IMPreeditStr = QString::null;
+}
+
+void kpToolText::imComposeEvent (QIMEvent *e)
+{
+#if DEBUG_KP_TOOL_TEXT && 1
+ kdDebug () << "kpToolText::imComposeEvent() text='" << e->text ()
+ << " cursorPos=" << e->cursorPos ()
+ << " selectionLength=" << e->selectionLength ()
+ << endl;
+#endif
+
+ kpSelection *sel = document ()->selection ();
+ if (hasBegunDraw() || !sel || !sel->isText ())
+ {
+ e->ignore();
+ return;
+ }
+
+ // remove old preedit
+ if (m_IMPreeditStr.length() > 0 )
+ {
+ // set cursor at the start input point
+ viewManager ()->setTextCursorPosition (m_IMStartCursorRow, m_IMStartCursorCol);
+ for (unsigned int i = 0; i < m_IMPreeditStr.length(); i++)
+ {
+ if (!m_deleteCommand)
+ {
+ if (hasBegunShape ())
+ endShape (m_currentPoint, QRect (m_startPoint, m_currentPoint).normalize ());
+
+ m_deleteCommand = new kpToolTextDeleteCommand (i18n ("Text: Delete"),
+ viewManager ()->textCursorRow (), viewManager ()->textCursorCol (),
+ mainWindow ());
+ commandHistory ()->addCommand (m_deleteCommand, false/*no exec*/);
+ }
+ else
+ m_deleteCommand->addDelete ();
+ }
+ }
+
+ // insert new preedit
+ m_IMPreeditStr = e->text();
+ if (m_IMPreeditStr.length() > 0)
+ {
+ if (!m_insertCommand)
+ {
+ if (hasBegunShape ())
+ endShape (m_currentPoint, QRect (m_startPoint, m_currentPoint).normalize ());
+
+ m_insertCommand = new kpToolTextInsertCommand (i18n ("Text: Write"),
+ viewManager ()->textCursorRow (), viewManager ()->textCursorCol (),
+ m_IMPreeditStr,
+ mainWindow ());
+ commandHistory ()->addCommand (m_insertCommand, false/*no exec*/);
+ }
+ else
+ m_insertCommand->addText (m_IMPreeditStr);
+ }
+
+ // set cursor pos
+ if (m_IMStartCursorRow >= 0)
+ {
+ int row = m_IMStartCursorRow;
+ int col = m_IMStartCursorCol + e->cursorPos () /* + e->selectionLength()*/;
+ viewManager ()->setTextCursorPosition (row, col, true /* update MicroFocusHint */);
+ }
+}
+
+void kpToolText::imEndEvent (QIMEvent *e)
+{
+#if DEBUG_KP_TOOL_TEXT && 1
+ kdDebug () << "kpToolText::imEndEvent() text='" << e->text ()
+ << " cursorPos=" << e->cursorPos ()
+ << " selectionLength=" << e->selectionLength ()
+ << endl;
+#endif
+
+ kpSelection *sel = document ()->selection ();
+ if (hasBegunDraw() || !sel || !sel->isText ())
+ {
+ e->ignore();
+ return;
+ }
+
+ // remove old preedit
+ if (m_IMPreeditStr.length() > 0 )
+ {
+ // set cursor at the start input point
+ viewManager ()->setTextCursorPosition (m_IMStartCursorRow, m_IMStartCursorCol);
+ for (unsigned int i = 0; i < m_IMPreeditStr.length(); i++)
+ {
+ if (!m_deleteCommand)
+ {
+ if (hasBegunShape ())
+ endShape (m_currentPoint, QRect (m_startPoint, m_currentPoint).normalize ());
+
+ m_deleteCommand = new kpToolTextDeleteCommand (i18n ("Text: Delete"),
+ viewManager ()->textCursorRow (), viewManager ()->textCursorCol (),
+ mainWindow ());
+ commandHistory ()->addCommand (m_deleteCommand, false/*no exec*/);
+ }
+ else
+ m_deleteCommand->addDelete ();
+ }
+ }
+ m_IMPreeditStr = QString::null;
+
+ // commit string
+ QString inputStr = e->text();
+ if (inputStr.length() > 0)
+ {
+ if (!m_insertCommand)
+ {
+ if (hasBegunShape ())
+ endShape (m_currentPoint, QRect (m_startPoint, m_currentPoint).normalize ());
+
+ m_insertCommand = new kpToolTextInsertCommand (i18n ("Text: Write"),
+ viewManager ()->textCursorRow (), viewManager ()->textCursorCol (),
+ inputStr,
+ mainWindow ());
+ commandHistory ()->addCommand (m_insertCommand, false/*no exec*/);
+ }
+ else
+ m_insertCommand->addText (inputStr);
+ }
+}
+
+
+// protected
+bool kpToolText::shouldChangeTextStyle () const
+{
+ if (mainWindow ()->settingTextStyle ())
+ {
+ #if DEBUG_KP_TOOL_TEXT
+ kdDebug () << "\trecursion - abort setting text style: "
+ << mainWindow ()->settingTextStyle ()
+ << endl;
+ #endif
+ return false;
+ }
+
+ if (!document ()->selection () ||
+ !document ()->selection ()->isText ())
+ {
+ #if DEBUG_KP_TOOL_TEXT
+ kdDebug () << "\tno text selection - abort setting text style" << endl;
+ #endif
+ return false;
+ }
+
+ return true;
+}
+
+// protected
+void kpToolText::changeTextStyle (const QString &name,
+ const kpTextStyle &newTextStyle,
+ const kpTextStyle &oldTextStyle)
+{
+#if DEBUG_KP_TOOL_TEXT
+ kdDebug () << "kpToolText::changeTextStyle(" << name << ")" << endl;
+#endif
+
+ if (hasBegunShape ())
+ endShape (m_currentPoint, QRect (m_startPoint, m_currentPoint).normalize ());
+
+ commandHistory ()->addCommand (
+ new kpToolTextChangeStyleCommand (
+ name,
+ newTextStyle,
+ oldTextStyle,
+ mainWindow ()));
+}
+
+
+// protected slot virtual [base kpToolSelection]
+void kpToolText::slotIsOpaqueChanged ()
+{
+#if DEBUG_KP_TOOL_TEXT
+ kdDebug () << "kpToolText::slotIsOpaqueChanged()" << endl;
+#endif
+
+ if (!shouldChangeTextStyle ())
+ return;
+
+ kpTextStyle newTextStyle = mainWindow ()->textStyle ();
+ kpTextStyle oldTextStyle = newTextStyle;
+ oldTextStyle.setBackgroundOpaque (!m_toolWidgetOpaqueOrTransparent->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
+ kdDebug () << "kpToolText::slotColorsSwapped()" << endl;
+#endif
+
+ if (!shouldChangeTextStyle ())
+ return;
+
+ kpTextStyle newTextStyle = mainWindow ()->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
+ kdDebug () << "kpToolText::slotForegroundColorChanged()" << endl;
+#endif
+
+ if (!shouldChangeTextStyle ())
+ return;
+
+ kpTextStyle newTextStyle = mainWindow ()->textStyle ();
+ kpTextStyle oldTextStyle = newTextStyle;
+ oldTextStyle.setForegroundColor (oldForegroundColor ());
+
+ changeTextStyle (i18n ("Text: Foreground Color"),
+ newTextStyle,
+ oldTextStyle);
+}
+
+// protected slot virtual [base kpToolSelection]
+void kpToolText::slotBackgroundColorChanged (const kpColor & /*color*/)
+{
+#if DEBUG_KP_TOOL_TEXT
+ kdDebug () << "kpToolText::slotBackgroundColorChanged()" << endl;
+#endif
+
+ if (!shouldChangeTextStyle ())
+ return;
+
+ kpTextStyle newTextStyle = mainWindow ()->textStyle ();
+ kpTextStyle oldTextStyle = newTextStyle;
+ oldTextStyle.setBackgroundColor (oldBackgroundColor ());
+
+ changeTextStyle (i18n ("Text: Background Color"),
+ newTextStyle,
+ oldTextStyle);
+}
+
+// protected slot virtual [base kpToolSelection]
+void kpToolText::slotColorSimilarityChanged (double, int)
+{
+ // --- don't pass on event to kpToolSelection 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
+ kdDebug () << "kpToolText::slotFontFamilyChanged() new="
+ << fontFamily
+ << " old="
+ << oldFontFamily
+ << endl;
+#else
+ (void) fontFamily;
+#endif
+
+ if (!shouldChangeTextStyle ())
+ return;
+
+ kpTextStyle newTextStyle = mainWindow ()->textStyle ();
+ 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
+ kdDebug () << "kpToolText::slotFontSizeChanged() new="
+ << fontSize
+ << " old="
+ << oldFontSize
+ << endl;
+#else
+ (void) fontSize;
+#endif
+
+ if (!shouldChangeTextStyle ())
+ return;
+
+ kpTextStyle newTextStyle = mainWindow ()->textStyle ();
+ 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
+ kdDebug () << "kpToolText::slotBoldChanged(" << isBold << ")" << endl;
+#endif
+
+ if (!shouldChangeTextStyle ())
+ return;
+
+ kpTextStyle newTextStyle = mainWindow ()->textStyle ();
+ kpTextStyle oldTextStyle = newTextStyle;
+ oldTextStyle.setBold (!isBold);
+
+ changeTextStyle (i18n ("Text: Bold"),
+ newTextStyle,
+ oldTextStyle);
+}
+
+// public slot
+void kpToolText::slotItalicChanged (bool isItalic)
+{
+#if DEBUG_KP_TOOL_TEXT
+ kdDebug () << "kpToolText::slotItalicChanged(" << isItalic << ")" << endl;
+#endif
+
+ if (!shouldChangeTextStyle ())
+ return;
+
+ kpTextStyle newTextStyle = mainWindow ()->textStyle ();
+ kpTextStyle oldTextStyle = newTextStyle;
+ oldTextStyle.setItalic (!isItalic);
+
+ changeTextStyle (i18n ("Text: Italic"),
+ newTextStyle,
+ oldTextStyle);
+}
+
+// public slot
+void kpToolText::slotUnderlineChanged (bool isUnderline)
+{
+#if DEBUG_KP_TOOL_TEXT
+ kdDebug () << "kpToolText::slotUnderlineChanged(" << isUnderline << ")" << endl;
+#endif
+
+ if (!shouldChangeTextStyle ())
+ return;
+
+ kpTextStyle newTextStyle = mainWindow ()->textStyle ();
+ kpTextStyle oldTextStyle = newTextStyle;
+ oldTextStyle.setUnderline (!isUnderline);
+
+ changeTextStyle (i18n ("Text: Underline"),
+ newTextStyle,
+ oldTextStyle);
+}
+
+// public slot
+void kpToolText::slotStrikeThruChanged (bool isStrikeThru)
+{
+#if DEBUG_KP_TOOL_TEXT
+ kdDebug () << "kpToolText::slotStrikeThruChanged(" << isStrikeThru << ")" << endl;
+#endif
+
+ if (!shouldChangeTextStyle ())
+ return;
+
+ kpTextStyle newTextStyle = mainWindow ()->textStyle ();
+ kpTextStyle oldTextStyle = newTextStyle;
+ oldTextStyle.setStrikeThru (!isStrikeThru);
+
+ changeTextStyle (i18n ("Text: Strike Through"),
+ newTextStyle,
+ oldTextStyle);
+}
+
+
+/*
+ * kpToolTextChangeStyleCommand
+ */
+
+kpToolTextChangeStyleCommand::kpToolTextChangeStyleCommand (const QString &name,
+ const kpTextStyle &newTextStyle, const kpTextStyle &oldTextStyle,
+ kpMainWindow *mainWindow)
+ : kpNamedCommand (name, mainWindow),
+ m_newTextStyle (newTextStyle),
+ m_oldTextStyle (oldTextStyle)
+{
+}
+
+kpToolTextChangeStyleCommand::~kpToolTextChangeStyleCommand ()
+{
+}
+
+
+// public virtual [base kpCommand]
+int kpToolTextChangeStyleCommand::size () const
+{
+ return 0;
+}
+
+
+// public virtual [base kpCommand]
+void kpToolTextChangeStyleCommand::execute ()
+{
+#if DEBUG_KP_TOOL_TEXT && 1
+ kdDebug () << "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;
+#endif
+
+ m_mainWindow->setTextStyle (m_newTextStyle);
+ if (selection ())
+ selection ()->setTextStyle (m_newTextStyle);
+ else
+ kdError () << "kpToolTextChangeStyleCommand::execute() without sel" << endl;
+}
+
+// public virtual [base kpCommand]
+void kpToolTextChangeStyleCommand::unexecute ()
+{
+#if DEBUG_KP_TOOL_TEXT && 1
+ kdDebug () << "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;
+#endif
+
+ m_mainWindow->setTextStyle (m_oldTextStyle);
+ if (selection ())
+ selection ()->setTextStyle (m_oldTextStyle);
+ else
+ kdError () << "kpToolTextChangeStyleCommand::unexecute() without sel" << endl;
+}
+
+
+/*
+ * kpToolTextInsertCommand
+ */
+
+kpToolTextInsertCommand::kpToolTextInsertCommand (const QString &name,
+ int row, int col, QString newText,
+ kpMainWindow *mainWindow)
+ : kpNamedCommand (name, mainWindow),
+ m_row (row), m_col (col)
+{
+ viewManager ()->setTextCursorPosition (m_row, m_col);
+ addText (newText);
+}
+
+kpToolTextInsertCommand::~kpToolTextInsertCommand ()
+{
+}
+
+
+// public
+void kpToolTextInsertCommand::addText (const QString &moreText)
+{
+ if (moreText.isEmpty ())
+ return;
+
+ QValueVector <QString> textLines = selection ()->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;
+ selection ()->setTextLines (textLines);
+
+ m_newText += moreText;
+ m_col += moreText.length ();
+
+ viewManager ()->setTextCursorPosition (m_row, m_col);
+}
+
+
+// public virtual [base kpCommand]
+int kpToolTextInsertCommand::size () const
+{
+ return m_newText.length () * sizeof (QChar);
+}
+
+
+// public virtual [base kpCommand]
+void kpToolTextInsertCommand::execute ()
+{
+ viewManager ()->setTextCursorPosition (m_row, m_col);
+
+ QString text = m_newText;
+ m_newText = QString::null;
+ addText (text);
+}
+
+// public virtual [base kpCommand]
+void kpToolTextInsertCommand::unexecute ()
+{
+ viewManager ()->setTextCursorPosition (m_row, m_col);
+
+ QValueVector <QString> textLines = selection ()->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;
+ selection ()->setTextLines (textLines);
+
+ m_col -= m_newText.length ();
+
+ viewManager ()->setTextCursorPosition (m_row, m_col);
+}
+
+
+/*
+ * kpToolTextEnterCommand
+ */
+
+kpToolTextEnterCommand::kpToolTextEnterCommand (const QString &name,
+ int row, int col,
+ kpMainWindow *mainWindow)
+ : kpNamedCommand (name, mainWindow),
+ m_row (row), m_col (col),
+ m_numEnters (0)
+{
+ viewManager ()->setTextCursorPosition (m_row, m_col);
+ addEnter ();
+}
+
+kpToolTextEnterCommand::~kpToolTextEnterCommand ()
+{
+}
+
+
+// public
+void kpToolTextEnterCommand::addEnter ()
+{
+ QValueVector <QString> textLines = selection ()->textLines ();
+
+ const QString rightHalf = textLines [m_row].mid (m_col);
+
+ textLines [m_row].truncate (m_col);
+ textLines.insert (textLines.begin () + m_row + 1, rightHalf);
+
+ selection ()->setTextLines (textLines);
+
+ m_row++;
+ m_col = 0;
+
+ viewManager ()->setTextCursorPosition (m_row, m_col);
+
+ m_numEnters++;
+}
+
+
+// public virtual [base kpCommand]
+int 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++)
+ addEnter ();
+}
+
+// public virtual [base kpCommand]
+void kpToolTextEnterCommand::unexecute ()
+{
+ viewManager ()->setTextCursorPosition (m_row, m_col);
+
+ QValueVector <QString> textLines = selection ()->textLines ();
+
+ for (int i = 0; i < m_numEnters; i++)
+ {
+ if (m_col != 0)
+ {
+ kdError () << "kpToolTextEnterCommand::unexecute() col=" << m_col << endl;
+ break;
+ }
+
+ 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;
+ }
+
+ selection ()->setTextLines (textLines);
+
+ viewManager ()->setTextCursorPosition (m_row, m_col);
+}
+
+
+/*
+ * kpToolTextBackspaceCommand
+ */
+
+kpToolTextBackspaceCommand::kpToolTextBackspaceCommand (const QString &name,
+ int row, int col,
+ kpMainWindow *mainWindow)
+ : kpNamedCommand (name, mainWindow),
+ m_row (row), m_col (col),
+ m_numBackspaces (0)
+{
+ viewManager ()->setTextCursorPosition (m_row, m_col);
+ addBackspace ();
+}
+
+kpToolTextBackspaceCommand::~kpToolTextBackspaceCommand ()
+{
+}
+
+
+// public
+void kpToolTextBackspaceCommand::addBackspace ()
+{
+ QValueVector <QString> textLines = selection ()->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;
+ }
+ }
+
+ selection ()->setTextLines (textLines);
+
+ viewManager ()->setTextCursorPosition (m_row, m_col);
+
+ m_numBackspaces++;
+}
+
+
+// public virtual [base kpCommand]
+int kpToolTextBackspaceCommand::size () const
+{
+ return m_deletedText.length () * sizeof (QChar);
+}
+
+
+// public virtual [base kpCommand]
+void kpToolTextBackspaceCommand::execute ()
+{
+ viewManager ()->setTextCursorPosition (m_row, m_col);
+
+ m_deletedText = QString::null;
+ int oldNumBackspaces = m_numBackspaces;
+ m_numBackspaces = 0;
+
+ for (int i = 0; i < oldNumBackspaces; i++)
+ addBackspace ();
+}
+
+// public virtual [base kpCommand]
+void kpToolTextBackspaceCommand::unexecute ()
+{
+ viewManager ()->setTextCursorPosition (m_row, m_col);
+
+ QValueVector <QString> textLines = selection ()->textLines ();
+
+ for (int i = 0; i < (int) m_deletedText.length (); i++)
+ {
+ if (m_deletedText [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;
+ m_col++;
+ }
+ }
+
+ m_deletedText = QString::null;
+
+ selection ()->setTextLines (textLines);
+
+ viewManager ()->setTextCursorPosition (m_row, m_col);
+}
+
+
+/*
+ * kpToolTextDeleteCommand
+ */
+
+kpToolTextDeleteCommand::kpToolTextDeleteCommand (const QString &name,
+ int row, int col,
+ kpMainWindow *mainWindow)
+ : kpNamedCommand (name, mainWindow),
+ m_row (row), m_col (col),
+ m_numDeletes (0)
+{
+ viewManager ()->setTextCursorPosition (m_row, m_col);
+ addDelete ();
+}
+
+kpToolTextDeleteCommand::~kpToolTextDeleteCommand ()
+{
+}
+
+
+// public
+void kpToolTextDeleteCommand::addDelete ()
+{
+ QValueVector <QString> textLines = selection ()->textLines ();
+
+ if (m_col < (int) 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 < (int) textLines.size () - 1)
+ {
+ m_deletedText.prepend ('\n');
+
+ textLines [m_row] += textLines [m_row + 1];
+ textLines.erase (textLines.begin () + m_row + 1);
+ }
+ }
+
+ selection ()->setTextLines (textLines);
+
+ viewManager ()->setTextCursorPosition (m_row, m_col);
+
+ m_numDeletes++;
+}
+
+
+// public virtual [base kpCommand]
+int kpToolTextDeleteCommand::size () const
+{
+ return m_deletedText.length () * sizeof (QChar);
+}
+
+
+// public virtual [base kpCommand]
+void kpToolTextDeleteCommand::execute ()
+{
+ viewManager ()->setTextCursorPosition (m_row, m_col);
+
+ m_deletedText = QString::null;
+ int oldNumDeletes = m_numDeletes;
+ m_numDeletes = 0;
+
+ for (int i = 0; i < oldNumDeletes; i++)
+ addDelete ();
+}
+
+// public virtual [base kpCommand]
+void kpToolTextDeleteCommand::unexecute ()
+{
+ viewManager ()->setTextCursorPosition (m_row, m_col);
+
+ QValueVector <QString> textLines = selection ()->textLines ();
+
+ for (int i = 0; i < (int) m_deletedText.length (); i++)
+ {
+ if (m_deletedText [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;
+ }
+ }
+
+ m_deletedText = QString::null;
+
+ selection ()->setTextLines (textLines);
+
+ viewManager ()->setTextCursorPosition (m_row, m_col);
+}
+
+
+#include <kptooltext.moc>
diff --git a/kolourpaint/tools/kptooltext.h b/kolourpaint/tools/kptooltext.h
new file mode 100644
index 00000000..a99654b7
--- /dev/null
+++ b/kolourpaint/tools/kptooltext.h
@@ -0,0 +1,203 @@
+
+/*
+ Copyright (c) 2003,2004,2005 Clarence Dang <dang@kde.org>
+ 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_h__
+#define __kp_tool_text_h__
+
+#include <qstring.h>
+
+#include <kpcommandhistory.h>
+
+#include <kptextstyle.h>
+#include <kptoolselection.h>
+
+class kpColor;
+class kpMainWindow;
+class kpSelection;
+class kpViewManager;
+
+class kpToolText : public kpToolSelection
+{
+Q_OBJECT
+
+public:
+ kpToolText (kpMainWindow *mainWindow);
+ virtual ~kpToolText ();
+
+ virtual bool careAboutColorsSwapped () const { return true; }
+
+ virtual void begin ();
+ virtual void end ();
+
+ bool hasBegunText () const;
+ virtual bool hasBegunShape () const;
+ virtual void cancelShape ();
+ virtual void endShape (const QPoint &thisPoint, const QRect &normalizedRect);
+
+protected:
+ virtual void keyPressEvent (QKeyEvent *e);
+ virtual void imStartEvent (QIMEvent *e);
+ virtual void imComposeEvent (QIMEvent *e);
+ virtual void imEndEvent (QIMEvent *e);
+
+protected:
+ bool shouldChangeTextStyle () const;
+ void changeTextStyle (const QString &name,
+ const kpTextStyle &newTextStyle,
+ const kpTextStyle &oldTextStyle);
+
+protected slots:
+ virtual void slotIsOpaqueChanged ();
+ virtual void slotColorsSwapped (const kpColor &newForegroundColor,
+ const kpColor &newBackgroundColor);
+ virtual void slotForegroundColorChanged (const kpColor &color);
+ virtual void slotBackgroundColorChanged (const kpColor &color);
+ virtual void slotColorSimilarityChanged (double, int);
+
+public slots:
+ void slotFontFamilyChanged (const QString &fontFamily, const QString &oldFontFamily);
+ void slotFontSizeChanged (int fontSize, int oldFontSize);
+ void slotBoldChanged (bool isBold);
+ void slotItalicChanged (bool isItalic);
+ void slotUnderlineChanged (bool isUnderline);
+ void slotStrikeThruChanged (bool isStrikeThru);
+
+protected:
+ class kpToolTextInsertCommand *m_insertCommand;
+ class kpToolTextEnterCommand *m_enterCommand;
+ class kpToolTextBackspaceCommand *m_backspaceCommand;
+ class kpToolTextDeleteCommand *m_deleteCommand;
+
+ bool m_isIMStarted;
+ int m_IMStartCursorRow;
+ int m_IMStartCursorCol;
+ QString m_IMPreeditStr;
+};
+
+
+class kpToolTextChangeStyleCommand : public kpNamedCommand
+{
+public:
+ kpToolTextChangeStyleCommand (const QString &name,
+ const kpTextStyle &newTextStyle, const kpTextStyle &oldTextStyle,
+ kpMainWindow *mainWindow);
+ virtual ~kpToolTextChangeStyleCommand ();
+
+ virtual int size () const;
+
+ virtual void execute ();
+ virtual void unexecute ();
+
+protected:
+ kpTextStyle m_newTextStyle, m_oldTextStyle;
+};
+
+class kpToolTextInsertCommand : public kpNamedCommand
+{
+public:
+ kpToolTextInsertCommand (const QString &name,
+ int row, int col, QString newText,
+ kpMainWindow *mainWindow);
+ virtual ~kpToolTextInsertCommand ();
+
+ void addText (const QString &moreText);
+
+ virtual int size () const;
+
+ virtual void execute ();
+ virtual void unexecute ();
+
+protected:
+ int m_row, m_col;
+ QString m_newText;
+};
+
+class kpToolTextEnterCommand : public kpNamedCommand
+{
+public:
+ kpToolTextEnterCommand (const QString &name,
+ int row, int col,
+ kpMainWindow *mainWindow);
+ virtual ~kpToolTextEnterCommand ();
+
+ void addEnter ();
+
+ virtual int size () const;
+
+ virtual void execute ();
+ virtual void unexecute ();
+
+protected:
+ int m_row, m_col;
+ int m_numEnters;
+};
+
+class kpToolTextBackspaceCommand : public kpNamedCommand
+{
+public:
+ kpToolTextBackspaceCommand (const QString &name,
+ int row, int col,
+ kpMainWindow *mainWindow);
+ virtual ~kpToolTextBackspaceCommand ();
+
+ void addBackspace ();
+
+ virtual int size () const;
+
+ virtual void execute ();
+ virtual void unexecute ();
+
+protected:
+ int m_row, m_col;
+ int m_numBackspaces;
+ QString m_deletedText;
+};
+
+class kpToolTextDeleteCommand : public kpNamedCommand
+{
+public:
+ kpToolTextDeleteCommand (const QString &name,
+ int row, int col,
+ kpMainWindow *mainWindow);
+ virtual ~kpToolTextDeleteCommand ();
+
+ void addDelete ();
+
+ virtual int size () const;
+
+ virtual void execute ();
+ virtual void unexecute ();
+
+protected:
+ int m_row, m_col;
+ int m_numDeletes;
+ QString m_deletedText;
+};
+
+#endif // __kp_tool_text_h__
+