diff options
Diffstat (limited to 'kolourpaint/tools/kptoolselection.cpp')
-rw-r--r-- | kolourpaint/tools/kptoolselection.cpp | 2371 |
1 files changed, 2371 insertions, 0 deletions
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> |