You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
tdegraphics/kolourpaint/tools/kptoolselection.cpp

2372 lines
70 KiB

/*
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>