diff --git a/commands/imagelib/transforms/kpTransformResizeScaleCommand.cpp b/commands/imagelib/transforms/kpTransformResizeScaleCommand.cpp index 08bc38e2..752f8b62 100644 --- a/commands/imagelib/transforms/kpTransformResizeScaleCommand.cpp +++ b/commands/imagelib/transforms/kpTransformResizeScaleCommand.cpp @@ -1,478 +1,478 @@ /* Copyright (c) 2003-2007 Clarence Dang All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #define DEBUG_KP_TOOL_RESIZE_SCALE_COMMAND 0 #define DEBUG_KP_TOOL_RESIZE_SCALE_DIALOG 0 #include "kpTransformResizeScaleCommand.h" #include "layers/selections/image/kpAbstractImageSelection.h" #include "environments/commands/kpCommandEnvironment.h" #include "kpDefs.h" #include "document/kpDocument.h" #include "layers/selections/image/kpFreeFormImageSelection.h" #include "pixmapfx/kpPixmapFX.h" #include "layers/selections/image/kpRectangularImageSelection.h" #include "layers/selections/text/kpTextSelection.h" #include #include #include #include #include #include #include #include "kpLogCategories.h" #include //-------------------------------------------------------------------------------- kpTransformResizeScaleCommand::kpTransformResizeScaleCommand (bool actOnSelection, int newWidth, int newHeight, Type type, kpCommandEnvironment *environ) : kpCommand (environ), m_actOnSelection (actOnSelection), m_type (type), m_backgroundColor (environ->backgroundColor ()), m_oldSelectionPtr (nullptr) { kpDocument *doc = document (); Q_ASSERT (doc); m_oldWidth = doc->width (m_actOnSelection); m_oldHeight = doc->height (m_actOnSelection); m_actOnTextSelection = (m_actOnSelection && doc->textSelection ()); resize (newWidth, newHeight); // If we have a selection _border_ (but not a floating selection), // then scale the selection with the document m_scaleSelectionWithImage = (!m_actOnSelection && (m_type == Scale || m_type == SmoothScale) && document ()->selection () && !document ()->selection ()->hasContent ()); } kpTransformResizeScaleCommand::~kpTransformResizeScaleCommand () { delete m_oldSelectionPtr; } // public virtual [base kpCommand] QString kpTransformResizeScaleCommand::name () const { if (m_actOnSelection) { if (m_actOnTextSelection) { if (m_type == Resize) return i18n ("Text: Resize Box"); } else { if (m_type == Scale) return i18n ("Selection: Scale"); else if (m_type == SmoothScale) return i18n ("Selection: Smooth Scale"); } } else { switch (m_type) { case Resize: return i18n ("Resize"); case Scale: return i18n ("Scale"); case SmoothScale: return i18n ("Smooth Scale"); } } return QString (); } // public virtual [base kpCommand] kpCommandSize::SizeType kpTransformResizeScaleCommand::size () const { return ImageSize (m_oldImage) + ImageSize (m_oldRightImage) + ImageSize (m_oldBottomImage) + SelectionSize (m_oldSelectionPtr); } // public int kpTransformResizeScaleCommand::newWidth () const { return m_newWidth; } // public void kpTransformResizeScaleCommand::setNewWidth (int width) { resize (width, newHeight ()); } // public int kpTransformResizeScaleCommand::newHeight () const { return m_newHeight; } // public void kpTransformResizeScaleCommand::setNewHeight (int height) { resize (newWidth (), height); } // public QSize kpTransformResizeScaleCommand::newSize () const { return QSize (newWidth (), newHeight ()); } // public virtual void kpTransformResizeScaleCommand::resize (int width, int height) { m_newWidth = width; m_newHeight = height; m_isLosslessScale = ((m_type == Scale) && (m_newWidth / m_oldWidth * m_oldWidth == m_newWidth) && (m_newHeight / m_oldHeight * m_oldHeight == m_newHeight)); } // public bool kpTransformResizeScaleCommand::scaleSelectionWithImage () const { return m_scaleSelectionWithImage; } // private void kpTransformResizeScaleCommand::scaleSelectionRegionWithDocument () { #if DEBUG_KP_TOOL_RESIZE_SCALE_COMMAND qCDebug(kpLogCommands) << "kpTransformResizeScaleCommand::scaleSelectionRegionWithDocument" << endl; #endif Q_ASSERT (m_oldSelectionPtr); Q_ASSERT (!m_oldSelectionPtr->hasContent ()); const double horizScale = double (m_newWidth) / double (m_oldWidth); const double vertScale = double (m_newHeight) / double (m_oldHeight); - const int newX = (int) (m_oldSelectionPtr->x () * horizScale); - const int newY = (int) (m_oldSelectionPtr->y () * vertScale); + const int newX = static_cast (m_oldSelectionPtr->x () * horizScale); + const int newY = static_cast (m_oldSelectionPtr->y () * vertScale); QPolygon currentPoints = m_oldSelectionPtr->calculatePoints (); currentPoints.translate (-currentPoints.boundingRect ().x (), -currentPoints.boundingRect ().y ()); // TODO: refactor into kpPixmapFX // TODO: Can we get to size 0x0 accidently? QMatrix scaleMatrix; scaleMatrix.scale (horizScale, vertScale); currentPoints = scaleMatrix.map (currentPoints); currentPoints.translate ( -currentPoints.boundingRect ().x () + newX, -currentPoints.boundingRect ().y () + newY); kpAbstractImageSelection *imageSel = dynamic_cast (m_oldSelectionPtr); kpTextSelection *textSel = dynamic_cast (m_oldSelectionPtr); if (imageSel) { document ()->setSelection ( kpFreeFormImageSelection (currentPoints, kpImage (), imageSel->transparency ())); } else if (textSel) { document ()->setSelection ( kpTextSelection (currentPoints.boundingRect (), textSel->textLines (), textSel->textStyle ())); } else Q_ASSERT (!"Unknown selection type"); environ ()->somethingBelowTheCursorChanged (); } // public virtual [base kpCommand] void kpTransformResizeScaleCommand::execute () { #if DEBUG_KP_TOOL_RESIZE_SCALE_COMMAND qCDebug(kpLogCommands) << "kpTransformResizeScaleCommand::execute() type=" << (int) m_type << " oldWidth=" << m_oldWidth << " oldHeight=" << m_oldHeight << " newWidth=" << m_newWidth << " newHeight=" << m_newHeight << endl; #endif if (m_oldWidth == m_newWidth && m_oldHeight == m_newHeight) return; if (m_type == Resize) { if (m_actOnSelection) { if (!m_actOnTextSelection) Q_ASSERT (!"kpTransformResizeScaleCommand::execute() resizing sel doesn't make sense"); QApplication::setOverrideCursor (Qt::WaitCursor); kpTextSelection *textSel = textSelection (); Q_ASSERT (textSel); kpTextSelection *newSel = textSel->resized (m_newWidth, m_newHeight); document ()->setSelection (*newSel); delete newSel; environ ()->somethingBelowTheCursorChanged (); QApplication::restoreOverrideCursor (); } else { QApplication::setOverrideCursor (Qt::WaitCursor); if (m_newWidth < m_oldWidth) { m_oldRightImage = document ()->getImageAt ( QRect (m_newWidth, 0, m_oldWidth - m_newWidth, m_oldHeight)); } if (m_newHeight < m_oldHeight) { m_oldBottomImage = document ()->getImageAt ( QRect (0, m_newHeight, m_newWidth, m_oldHeight - m_newHeight)); } document ()->resize (m_newWidth, m_newHeight, m_backgroundColor); QApplication::restoreOverrideCursor (); } } // Scale else { QApplication::setOverrideCursor (Qt::WaitCursor); kpImage oldImage = document ()->image (m_actOnSelection); if (!m_isLosslessScale) m_oldImage = oldImage; kpImage newImage = kpPixmapFX::scale (oldImage, m_newWidth, m_newHeight, m_type == SmoothScale); if (!m_oldSelectionPtr && document ()->selection ()) { // Save sel border m_oldSelectionPtr = document ()->selection ()->clone (); m_oldSelectionPtr->deleteContent (); } if (m_actOnSelection) { if (m_actOnTextSelection) Q_ASSERT (!"kpTransformResizeScaleCommand::execute() scaling text sel doesn't make sense"); Q_ASSERT (m_oldSelectionPtr); if ( !m_oldSelectionPtr ) // make coverity happy return; QRect newRect = QRect (m_oldSelectionPtr->x (), m_oldSelectionPtr->y (), newImage.width (), newImage.height ()); // Not possible to retain non-rectangular selection borders on scale // (think about e.g. a 45 deg line as part of the border & 2x scale) Q_ASSERT (dynamic_cast (m_oldSelectionPtr)); document ()->setSelection ( kpRectangularImageSelection (newRect, newImage, static_cast (m_oldSelectionPtr) ->transparency ())); environ ()->somethingBelowTheCursorChanged (); } else { document ()->setImage (newImage); if (m_scaleSelectionWithImage) { scaleSelectionRegionWithDocument (); } } QApplication::restoreOverrideCursor (); } } // public virtual [base kpCommand] void kpTransformResizeScaleCommand::unexecute () { #if DEBUG_KP_TOOL_RESIZE_SCALE_COMMAND qCDebug(kpLogCommands) << "kpTransformResizeScaleCommand::unexecute() type=" << m_type << endl; #endif if (m_oldWidth == m_newWidth && m_oldHeight == m_newHeight) return; kpDocument *doc = document (); Q_ASSERT (doc); if (m_type == Resize) { if (m_actOnSelection) { if (!m_actOnTextSelection) Q_ASSERT (!"kpTransformResizeScaleCommand::unexecute() resizing sel doesn't make sense"); QApplication::setOverrideCursor (Qt::WaitCursor); kpTextSelection *textSel = textSelection (); Q_ASSERT (textSel); kpTextSelection *newSel = textSel->resized (m_oldWidth, m_oldHeight); document ()->setSelection (*newSel); delete newSel; environ ()->somethingBelowTheCursorChanged (); QApplication::restoreOverrideCursor (); } else { QApplication::setOverrideCursor (Qt::WaitCursor); kpImage newImage (m_oldWidth, m_oldHeight, QImage::Format_ARGB32_Premultiplied); kpPixmapFX::setPixmapAt (&newImage, QPoint (0, 0), doc->image ()); if (m_newWidth < m_oldWidth) { kpPixmapFX::setPixmapAt (&newImage, QPoint (m_newWidth, 0), m_oldRightImage); } if (m_newHeight < m_oldHeight) { kpPixmapFX::setPixmapAt (&newImage, QPoint (0, m_newHeight), m_oldBottomImage); } doc->setImage (newImage); QApplication::restoreOverrideCursor (); } } // Scale else { QApplication::setOverrideCursor (Qt::WaitCursor); kpImage oldImage; if (!m_isLosslessScale) oldImage = m_oldImage; else oldImage = kpPixmapFX::scale (doc->image (m_actOnSelection), m_oldWidth, m_oldHeight); if (m_actOnSelection) { if (m_actOnTextSelection) Q_ASSERT (!"kpTransformResizeScaleCommand::unexecute() scaling text sel doesn't make sense"); Q_ASSERT (dynamic_cast (m_oldSelectionPtr)); kpAbstractImageSelection *oldImageSel = static_cast (m_oldSelectionPtr); kpAbstractImageSelection *oldSelection = oldImageSel->clone (); oldSelection->setBaseImage (oldImage); doc->setSelection (*oldSelection); delete oldSelection; environ ()->somethingBelowTheCursorChanged (); } else { doc->setImage (oldImage); if (m_scaleSelectionWithImage) { doc->setSelection (*m_oldSelectionPtr); environ ()->somethingBelowTheCursorChanged (); } } QApplication::restoreOverrideCursor (); } } diff --git a/commands/kpCommandHistoryBase.cpp b/commands/kpCommandHistoryBase.cpp index c2d9f268..f7bdaa17 100644 --- a/commands/kpCommandHistoryBase.cpp +++ b/commands/kpCommandHistoryBase.cpp @@ -1,751 +1,751 @@ /* Copyright (c) 2003-2007 Clarence Dang 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_COMMAND_HISTORY 0 #include "kpCommandHistoryBase.h" #include #include #include #include #include #include #include #include #include #include #include #include "kpCommand.h" #include "kpLogCategories.h" #include "environments/commands/kpCommandEnvironment.h" #include "kpDefs.h" #include "document/kpDocument.h" #include "mainWindow/kpMainWindow.h" #include "tools/kpTool.h" //--------------------------------------------------------------------- //template static void ClearPointerList (QLinkedList *listPtr) { if (!listPtr) return; qDeleteAll (listPtr->begin (), listPtr->end ()); listPtr->clear (); } struct kpCommandHistoryBasePrivate { }; kpCommandHistoryBase::kpCommandHistoryBase (bool doReadConfig, KActionCollection *ac) : d (new kpCommandHistoryBasePrivate ()) { m_actionUndo = new KToolBarPopupAction(KDE::icon("edit-undo"), undoActionText (), this); ac->addAction (KStandardAction::name (KStandardAction::Undo), m_actionUndo); ac->setDefaultShortcuts (m_actionUndo, KStandardShortcut::shortcut (KStandardShortcut::Undo)); connect (m_actionUndo, SIGNAL(triggered(bool)), this, SLOT (undo())); m_actionRedo = new KToolBarPopupAction(KDE::icon("edit-redo"), redoActionText (), this); ac->addAction (KStandardAction::name (KStandardAction::Redo), m_actionRedo); ac->setDefaultShortcuts (m_actionRedo, KStandardShortcut::shortcut (KStandardShortcut::Redo)); connect (m_actionRedo, SIGNAL(triggered(bool)), this, SLOT (redo())); m_actionUndo->setEnabled (false); m_actionRedo->setEnabled (false); connect (m_actionUndo->menu (), SIGNAL (triggered(QAction*)), this, SLOT (undoUpToNumber(QAction*))); connect (m_actionRedo->menu (), SIGNAL (triggered(QAction*)), this, SLOT (redoUpToNumber(QAction*))); m_undoMinLimit = 10; m_undoMaxLimit = 500; m_undoMaxLimitSizeLimit = 16 * 1048576; m_documentRestoredPosition = 0; if (doReadConfig) readConfig (); } kpCommandHistoryBase::~kpCommandHistoryBase () { ::ClearPointerList (&m_undoCommandList); ::ClearPointerList (&m_redoCommandList); delete d; } // public int kpCommandHistoryBase::undoLimit () const { return undoMinLimit (); } // public void kpCommandHistoryBase::setUndoLimit (int limit) { setUndoMinLimit (limit); } // public int kpCommandHistoryBase::undoMinLimit () const { return m_undoMinLimit; } // public void kpCommandHistoryBase::setUndoMinLimit (int limit) { #if DEBUG_KP_COMMAND_HISTORY qCDebug(kpLogCommands) << "kpCommandHistoryBase::setUndoMinLimit(" << limit << ")" << endl; #endif if (limit < 1 || limit > 5000/*"ought to be enough for anybody"*/) { qCCritical(kpLogCommands) << "kpCommandHistoryBase::setUndoMinLimit(" << limit << ")" << endl; return; } if (limit == m_undoMinLimit) return; m_undoMinLimit = limit; trimCommandListsUpdateActions (); } // public int kpCommandHistoryBase::undoMaxLimit () const { return m_undoMaxLimit; } // public void kpCommandHistoryBase::setUndoMaxLimit (int limit) { #if DEBUG_KP_COMMAND_HISTORY qCDebug(kpLogCommands) << "kpCommandHistoryBase::setUndoMaxLimit(" << limit << ")" << endl; #endif if (limit < 1 || limit > 5000/*"ought to be enough for anybody"*/) { qCCritical(kpLogCommands) << "kpCommandHistoryBase::setUndoMaxLimit(" << limit << ")" << endl; return; } if (limit == m_undoMaxLimit) return; m_undoMaxLimit = limit; trimCommandListsUpdateActions (); } // public kpCommandSize::SizeType kpCommandHistoryBase::undoMaxLimitSizeLimit () const { return m_undoMaxLimitSizeLimit; } // public void kpCommandHistoryBase::setUndoMaxLimitSizeLimit (kpCommandSize::SizeType sizeLimit) { #if DEBUG_KP_COMMAND_HISTORY qCDebug(kpLogCommands) << "kpCommandHistoryBase::setUndoMaxLimitSizeLimit(" << sizeLimit << ")" << endl; #endif if (sizeLimit < 0 || sizeLimit > (500 * 1048576)/*"ought to be enough for anybody"*/) { qCCritical(kpLogCommands) << "kpCommandHistoryBase::setUndoMaxLimitSizeLimit(" << sizeLimit << ")" << endl; return; } if (sizeLimit == m_undoMaxLimitSizeLimit) return; m_undoMaxLimitSizeLimit = sizeLimit; trimCommandListsUpdateActions (); } // public void kpCommandHistoryBase::readConfig () { #if DEBUG_KP_COMMAND_HISTORY qCDebug(kpLogCommands) << "kpCommandHistoryBase::readConfig()"; #endif KConfigGroup cfg (KSharedConfig::openConfig (), kpSettingsGroupUndoRedo); setUndoMinLimit (cfg.readEntry (kpSettingUndoMinLimit, undoMinLimit ())); setUndoMaxLimit (cfg.readEntry (kpSettingUndoMaxLimit, undoMaxLimit ())); setUndoMaxLimitSizeLimit ( cfg.readEntry (kpSettingUndoMaxLimitSizeLimit, undoMaxLimitSizeLimit ())); trimCommandListsUpdateActions (); } // public void kpCommandHistoryBase::writeConfig () { #if DEBUG_KP_COMMAND_HISTORY qCDebug(kpLogCommands) << "kpCommandHistoryBase::writeConfig()"; #endif KConfigGroup cfg (KSharedConfig::openConfig (), kpSettingsGroupUndoRedo); cfg.writeEntry (kpSettingUndoMinLimit, undoMinLimit ()); cfg.writeEntry (kpSettingUndoMaxLimit, undoMaxLimit ()); cfg.writeEntry ( kpSettingUndoMaxLimitSizeLimit, undoMaxLimitSizeLimit ()); cfg.sync (); } // public void kpCommandHistoryBase::addCommand (kpCommand *command, bool execute) { #if DEBUG_KP_COMMAND_HISTORY qCDebug(kpLogCommands) << "kpCommandHistoryBase::addCommand(" << command << ",execute=" << execute << ")" << endl; #endif if (execute) command->execute (); m_undoCommandList.push_front (command); ::ClearPointerList (&m_redoCommandList); #if DEBUG_KP_COMMAND_HISTORY qCDebug(kpLogCommands) << "\tdocumentRestoredPosition=" << m_documentRestoredPosition << endl; #endif if (m_documentRestoredPosition != INT_MAX) { if (m_documentRestoredPosition > 0) m_documentRestoredPosition = INT_MAX; else m_documentRestoredPosition--; #if DEBUG_KP_COMMAND_HISTORY qCDebug(kpLogCommands) << "\t\tdocumentRestoredPosition=" << m_documentRestoredPosition << endl; #endif } trimCommandListsUpdateActions (); } // public void kpCommandHistoryBase::clear () { #if DEBUG_KP_COMMAND_HISTORY qCDebug(kpLogCommands) << "kpCommandHistoryBase::clear()"; #endif ::ClearPointerList (&m_undoCommandList); ::ClearPointerList (&m_redoCommandList); m_documentRestoredPosition = 0; updateActions (); } //--------------------------------------------------------------------- // protected slot void kpCommandHistoryBase::undoInternal () { #if DEBUG_KP_COMMAND_HISTORY qCDebug(kpLogCommands) << "kpCommandHistoryBase::undoInternal()"; #endif kpCommand *undoCommand = nextUndoCommand (); if (!undoCommand) return; undoCommand->unexecute (); m_undoCommandList.erase (m_undoCommandList.begin ()); m_redoCommandList.push_front (undoCommand); #if DEBUG_KP_COMMAND_HISTORY qCDebug(kpLogCommands) << "\tdocumentRestoredPosition=" << m_documentRestoredPosition << endl; #endif if (m_documentRestoredPosition != INT_MAX) { m_documentRestoredPosition++; if (m_documentRestoredPosition == 0) emit documentRestored (); #if DEBUG_KP_COMMAND_HISTORY qCDebug(kpLogCommands) << "\t\tdocumentRestoredPosition=" << m_documentRestoredPosition << endl; #endif } } //--------------------------------------------------------------------- // protected slot void kpCommandHistoryBase::redoInternal () { #if DEBUG_KP_COMMAND_HISTORY qCDebug(kpLogCommands) << "kpCommandHistoryBase::redoInternal()"; #endif kpCommand *redoCommand = nextRedoCommand (); if (!redoCommand) return; redoCommand->execute (); m_redoCommandList.erase (m_redoCommandList.begin ()); m_undoCommandList.push_front (redoCommand); #if DEBUG_KP_COMMAND_HISTORY qCDebug(kpLogCommands) << "\tdocumentRestoredPosition=" << m_documentRestoredPosition << endl; #endif if (m_documentRestoredPosition != INT_MAX) { m_documentRestoredPosition--; if (m_documentRestoredPosition == 0) emit documentRestored (); #if DEBUG_KP_COMMAND_HISTORY qCDebug(kpLogCommands) << "\t\tdocumentRestoredPosition=" << m_documentRestoredPosition << endl; #endif } } //--------------------------------------------------------------------- // public slot virtual void kpCommandHistoryBase::undo () { #if DEBUG_KP_COMMAND_HISTORY qCDebug(kpLogCommands) << "kpCommandHistoryBase::undo()"; #endif undoInternal (); trimCommandListsUpdateActions (); } //--------------------------------------------------------------------- // public slot virtual void kpCommandHistoryBase::redo () { #if DEBUG_KP_COMMAND_HISTORY qCDebug(kpLogCommands) << "kpCommandHistoryBase::redo()"; #endif redoInternal (); trimCommandListsUpdateActions (); } //--------------------------------------------------------------------- // public slot virtual void kpCommandHistoryBase::undoUpToNumber (QAction *which) { #if DEBUG_KP_COMMAND_HISTORY qCDebug(kpLogCommands) << "kpCommandHistoryBase::undoUpToNumber(" << which << ")"; #endif for (int i = 0; i <= which->data().toInt() && !m_undoCommandList.isEmpty (); i++) { undoInternal (); } trimCommandListsUpdateActions (); } // public slot virtual void kpCommandHistoryBase::redoUpToNumber (QAction *which) { #if DEBUG_KP_COMMAND_HISTORY qCDebug(kpLogCommands) << "kpCommandHistoryBase::redoUpToNumber(" << which << ")"; #endif for (int i = 0; i <= which->data().toInt() && !m_redoCommandList.isEmpty (); i++) { redoInternal (); } trimCommandListsUpdateActions (); } // protected QString kpCommandHistoryBase::undoActionText () const { kpCommand *undoCommand = nextUndoCommand (); if (undoCommand) return i18n ("&Undo: %1", undoCommand->name ()); else return i18n ("&Undo"); } // protected QString kpCommandHistoryBase::redoActionText () const { kpCommand *redoCommand = nextRedoCommand (); if (redoCommand) return i18n ("&Redo: %1", redoCommand->name ()); else return i18n ("&Redo"); } // protected QString kpCommandHistoryBase::undoActionToolTip () const { kpCommand *undoCommand = nextUndoCommand (); if (undoCommand) return i18n ("Undo: %1", undoCommand->name ()); else return i18n ("Undo"); } // protected QString kpCommandHistoryBase::redoActionToolTip () const { kpCommand *redoCommand = nextRedoCommand (); if (redoCommand) return i18n ("Redo: %1", redoCommand->name ()); else return i18n ("Redo"); } // protected void kpCommandHistoryBase::trimCommandListsUpdateActions () { #if DEBUG_KP_COMMAND_HISTORY qCDebug(kpLogCommands) << "kpCommandHistoryBase::trimCommandListsUpdateActions()"; #endif trimCommandLists (); updateActions (); } // protected void kpCommandHistoryBase::trimCommandList (QLinkedList *commandList) { #if DEBUG_KP_COMMAND_HISTORY qCDebug(kpLogCommands) << "kpCommandHistoryBase::trimCommandList()"; QTime timer; timer.start (); #endif if (!commandList) { qCCritical(kpLogCommands) << "kpCommandHistoryBase::trimCommandList() passed 0 commandList" << endl; return; } #if DEBUG_KP_COMMAND_HISTORY qCDebug(kpLogCommands) << "\tsize=" << commandList->size () << " undoMinLimit=" << m_undoMinLimit << " undoMaxLimit=" << m_undoMaxLimit << " undoMaxLimitSizeLimit=" << m_undoMaxLimitSizeLimit << endl; #endif - if ((int) commandList->size () <= m_undoMinLimit) + if (static_cast (commandList->size ()) <= m_undoMinLimit) { #if DEBUG_KP_COMMAND_HISTORY qCDebug(kpLogCommands) << "\t\tsize under undoMinLimit - done"; #endif return; } #if DEBUG_KP_COMMAND_HISTORY && 0 qCDebug(kpLogCommands) << "\tsize over undoMinLimit - iterating thru cmds:"; #endif QLinkedList ::iterator it = commandList->begin (); int upto = 0; kpCommandSize::SizeType sizeSoFar = 0; while (it != commandList->end ()) { bool advanceIt = true; if (sizeSoFar <= m_undoMaxLimitSizeLimit) { sizeSoFar += (*it)->size (); } #if DEBUG_KP_COMMAND_HISTORY && 0 qCDebug(kpLogCommands) << "\t\t" << upto << ":" << " name='" << (*it)->name () << "' size=" << (*it)->size () << " sizeSoFar=" << sizeSoFar << endl; #endif if (upto >= m_undoMinLimit) { if (upto >= m_undoMaxLimit || sizeSoFar > m_undoMaxLimitSizeLimit) { #if DEBUG_KP_COMMAND_HISTORY && 0 qCDebug(kpLogCommands) << "\t\t\tkill"; #endif delete (*it); it = m_undoCommandList.erase (it); advanceIt = false; } } if (advanceIt) it++; upto++; } #if DEBUG_KP_COMMAND_HISTORY qCDebug(kpLogCommands) << "\ttook " << timer.elapsed () << "ms"; #endif } // protected void kpCommandHistoryBase::trimCommandLists () { #if DEBUG_KP_COMMAND_HISTORY qCDebug(kpLogCommands) << "kpCommandHistoryBase::trimCommandLists()"; #endif trimCommandList (&m_undoCommandList); trimCommandList (&m_redoCommandList); #if DEBUG_KP_COMMAND_HISTORY qCDebug(kpLogCommands) << "\tdocumentRestoredPosition=" << m_documentRestoredPosition << endl; #endif if (m_documentRestoredPosition != INT_MAX) { #if DEBUG_KP_COMMAND_HISTORY qCDebug(kpLogCommands) << "\t\tundoCmdList.size=" << m_undoCommandList.size () << " redoCmdList.size=" << m_redoCommandList.size () << endl; #endif - if (m_documentRestoredPosition > (int) m_redoCommandList.size () || - -m_documentRestoredPosition > (int) m_undoCommandList.size ()) + if (m_documentRestoredPosition > static_cast (m_redoCommandList.size ()) || + -m_documentRestoredPosition > static_cast (m_undoCommandList.size ())) { #if DEBUG_KP_COMMAND_HISTORY qCDebug(kpLogCommands) << "\t\t\tinvalidate documentRestoredPosition"; #endif m_documentRestoredPosition = INT_MAX; } } } static void populatePopupMenu (QMenu *popupMenu, const QString &undoOrRedo, const QLinkedList &commandList) { if (!popupMenu) return; popupMenu->clear (); QLinkedList ::const_iterator it = commandList.begin (); int i = 0; while (i < 10 && it != commandList.end ()) { QAction *action = new QAction(i18n ("%1: %2", undoOrRedo, (*it)->name ()), popupMenu); action->setData(i); popupMenu->addAction (action); i++; it++; } if (it != commandList.end ()) { // TODO: maybe have a scrollview show all the items instead, like KOffice in KDE 3 // LOCOMPAT: should be centered text. popupMenu->addSection (i18np ("%1 more item", "%1 more items", commandList.size () - i)); } } // protected void kpCommandHistoryBase::updateActions () { #if DEBUG_KP_COMMAND_HISTORY qCDebug(kpLogCommands) << "kpCommandHistoryBase::updateActions()"; #endif - m_actionUndo->setEnabled ((bool) nextUndoCommand ()); + m_actionUndo->setEnabled (static_cast (nextUndoCommand ())); // Don't want to keep changing toolbar text. // TODO: As a bad side-effect, the menu doesn't have "Undo: " // anymore. In any case, the KDE4 KToolBarPopupAction // sucks in menus as it forces the clicking of a submenu. IMO, // there should be no submenu in the menu. //m_actionUndo->setText (undoActionText ()); // But in icon mode, a tooltip with context is useful. m_actionUndo->setToolTip (undoActionToolTip ()); #if DEBUG_KP_COMMAND_HISTORY QTime timer; timer.start (); #endif populatePopupMenu (m_actionUndo->menu (), i18n ("Undo"), m_undoCommandList); #if DEBUG_KP_COMMAND_HISTORY qCDebug(kpLogCommands) << "\tpopuplatePopupMenu undo=" << timer.elapsed () << "ms" << endl;; #endif - m_actionRedo->setEnabled ((bool) nextRedoCommand ()); + m_actionRedo->setEnabled (static_cast (nextRedoCommand ())); // Don't want to keep changing toolbar text. // TODO: As a bad side-effect, the menu doesn't have "Undo: " // anymore. In any case, the KDE4 KToolBarPopupAction // sucks in menus as it forces the clicking of a submenu. IMO, // there should be no submenu in the menu. //m_actionRedo->setText (redoActionText ()); // But in icon mode, a tooltip with context is useful. m_actionRedo->setToolTip (redoActionToolTip ()); #if DEBUG_KP_COMMAND_HISTORY timer.restart (); #endif populatePopupMenu (m_actionRedo->menu (), i18n ("Redo"), m_redoCommandList); #if DEBUG_KP_COMMAND_HISTORY qCDebug(kpLogCommands) << "\tpopuplatePopupMenu redo=" << timer.elapsed () << "ms" << endl; #endif } // public kpCommand *kpCommandHistoryBase::nextUndoCommand () const { if (m_undoCommandList.isEmpty ()) return nullptr; return m_undoCommandList.first (); } // public kpCommand *kpCommandHistoryBase::nextRedoCommand () const { if (m_redoCommandList.isEmpty ()) return nullptr; return m_redoCommandList.first (); } // public void kpCommandHistoryBase::setNextUndoCommand (kpCommand *command) { #if DEBUG_KP_COMMAND_HISTORY qCDebug(kpLogCommands) << "kpCommandHistoryBase::setNextUndoCommand(" << command << ")" << endl; #endif if (m_undoCommandList.isEmpty ()) return; delete *m_undoCommandList.begin (); *m_undoCommandList.begin () = command; trimCommandListsUpdateActions (); } // public slot virtual void kpCommandHistoryBase::documentSaved () { #if DEBUG_KP_COMMAND_HISTORY qCDebug(kpLogCommands) << "kpCommandHistoryBase::documentSaved()"; #endif m_documentRestoredPosition = 0; } diff --git a/commands/kpCommandSize.cpp b/commands/kpCommandSize.cpp index 82a073ec..5c39eac0 100644 --- a/commands/kpCommandSize.cpp +++ b/commands/kpCommandSize.cpp @@ -1,156 +1,156 @@ /* Copyright (c) 2003-2007 Clarence Dang 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_COMMAND_SIZE 0 #include "commands/kpCommandSize.h" #include "layers/selections/kpAbstractSelection.h" #include #include #include // public static kpCommandSize::SizeType kpCommandSize::PixmapSize (const QImage &image) { return kpCommandSize::PixmapSize (image.width (), image.height (), image.depth ()); } // public static kpCommandSize::SizeType kpCommandSize::PixmapSize (const QImage *image) { return (image ? kpCommandSize::PixmapSize (*image) : 0); } // public static kpCommandSize::SizeType kpCommandSize::PixmapSize (int width, int height, int depth) { // handle 15bpp int roundedDepth = (depth > 8 ? (depth + 7) / 8 * 8 : depth); kpCommandSize::SizeType ret = - (kpCommandSize::SizeType) width * height * roundedDepth / 8; + static_cast (width) * height * roundedDepth / 8; #if DEBUG_KP_COMMAND_SIZE && 0 qCDebug(kpLogCommands) << "kpCommandSize::PixmapSize() w=" << width << " h=" << height << " d=" << depth << " roundedDepth=" << roundedDepth << " ret=" << ret << endl; #endif return ret; } // public static kpCommandSize::SizeType kpCommandSize::QImageSize (const QImage &image) { return kpCommandSize::QImageSize (image.width (), image.height (), image.depth ()); } // public static kpCommandSize::SizeType kpCommandSize::QImageSize (const QImage *image) { return (image ? kpCommandSize::QImageSize (*image) : 0); } // public static kpCommandSize::SizeType kpCommandSize::QImageSize (int width, int height, int depth) { // handle 15bpp int roundedDepth = (depth > 8 ? (depth + 7) / 8 * 8 : depth); kpCommandSize::SizeType ret = - (kpCommandSize::SizeType) width * height * roundedDepth / 8; + static_cast (width) * height * roundedDepth / 8; #if DEBUG_KP_COMMAND_SIZE && 0 qCDebug(kpLogCommands) << "kpCommandSize::QImageSize() w=" << width << " h=" << height << " d=" << depth << " roundedDepth=" << roundedDepth << " ret=" << ret << endl; #endif return ret; } // public static kpCommandSize::SizeType kpCommandSize::ImageSize (const kpImage &image) { return kpCommandSize::PixmapSize (image); } // public static kpCommandSize::SizeType kpCommandSize::ImageSize (const kpImage *image) { return kpCommandSize::PixmapSize (image); } // public static kpCommandSize::SizeType kpCommandSize::SelectionSize (const kpAbstractSelection &sel) { return sel.size (); } // public static kpCommandSize::SizeType kpCommandSize::SelectionSize (const kpAbstractSelection *sel) { return (sel ? sel->size () : 0); } // public static kpCommandSize::SizeType kpCommandSize::StringSize (const QString &string) { #if DEBUG_KP_COMMAND_SIZE && 1 qCDebug(kpLogCommands) << "kpCommandSize::StringSize(" << string << ")" << " len=" << string.length () << " sizeof(QChar)=" << sizeof (QChar) << endl; #endif - return ((SizeType) string.length () * sizeof (QChar)); + return static_cast (static_cast (string.length ()) * sizeof (QChar)); } // public static kpCommandSize::SizeType kpCommandSize::PolygonSize (const QPolygon &points) { #if DEBUG_KP_COMMAND_SIZE && 1 qCDebug(kpLogCommands) << "kpCommandSize::PolygonSize() points.size=" << points.size () << " sizeof(QPoint)=" << sizeof (QPoint) << endl; #endif - return ((SizeType) points.size () * sizeof (QPoint)); + return static_cast (static_cast (points.size ()) * sizeof (QPoint)); } diff --git a/commands/tools/selection/text/kpToolTextBackspaceCommand.cpp b/commands/tools/selection/text/kpToolTextBackspaceCommand.cpp index d371d356..4ecb91d8 100644 --- a/commands/tools/selection/text/kpToolTextBackspaceCommand.cpp +++ b/commands/tools/selection/text/kpToolTextBackspaceCommand.cpp @@ -1,151 +1,152 @@ /* Copyright (c) 2003-2007 Clarence Dang All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #define DEBUG_KP_TOOL_TEXT 0 #include "kpToolTextBackspaceCommand.h" #include "layers/selections/text/kpTextSelection.h" #include "views/manager/kpViewManager.h" #include kpToolTextBackspaceCommand::kpToolTextBackspaceCommand (const QString &name, int row, int col, Action action, kpCommandEnvironment *environ) : kpNamedCommand (name, environ), m_row (row), m_col (col), m_numBackspaces (0) { viewManager ()->setTextCursorPosition (m_row, m_col); if (action == AddBackspaceNow) addBackspace (); } kpToolTextBackspaceCommand::~kpToolTextBackspaceCommand () { } // public void kpToolTextBackspaceCommand::addBackspace () { QList textLines = textSelection ()->textLines (); if (m_col > 0) { m_deletedText.prepend (textLines [m_row][m_col - 1]); textLines [m_row] = textLines [m_row].left (m_col - 1) + textLines [m_row].mid (m_col); m_col--; } else { if (m_row > 0) { int newCursorRow = m_row - 1; int newCursorCol = textLines [newCursorRow].length (); m_deletedText.prepend ('\n'); textLines [newCursorRow] += textLines [m_row]; textLines.erase (textLines.begin () + m_row); m_row = newCursorRow; m_col = newCursorCol; } } textSelection ()->setTextLines (textLines); viewManager ()->setTextCursorPosition (m_row, m_col); m_numBackspaces++; } // public virtual [base kpCommand] kpCommandSize::SizeType kpToolTextBackspaceCommand::size () const { - return (kpCommandSize::SizeType) m_deletedText.length () * sizeof (QChar); + return static_cast + (static_cast (m_deletedText.length ()) * sizeof (QChar)); } // public virtual [base kpCommand] void kpToolTextBackspaceCommand::execute () { viewManager ()->setTextCursorPosition (m_row, m_col); m_deletedText.clear (); int oldNumBackspaces = m_numBackspaces; m_numBackspaces = 0; for (int i = 0; i < oldNumBackspaces; i++) addBackspace (); } // public virtual [base kpCommand] void kpToolTextBackspaceCommand::unexecute () { viewManager ()->setTextCursorPosition (m_row, m_col); QList textLines = textSelection ()->textLines (); - for (int i = 0; i < (int) m_deletedText.length (); i++) + for (int i = 0; i < static_cast (m_deletedText.length ()); i++) { if (m_deletedText [i] == '\n') { const QString rightHalf = textLines [m_row].mid (m_col); textLines [m_row].truncate (m_col); textLines.insert (textLines.begin () + m_row + 1, rightHalf); m_row++; m_col = 0; } else { const QString leftHalf = textLines [m_row].left (m_col); const QString rightHalf = textLines [m_row].mid (m_col); textLines [m_row] = leftHalf + m_deletedText [i] + rightHalf; m_col++; } } m_deletedText.clear (); textSelection ()->setTextLines (textLines); viewManager ()->setTextCursorPosition (m_row, m_col); } diff --git a/commands/tools/selection/text/kpToolTextDeleteCommand.cpp b/commands/tools/selection/text/kpToolTextDeleteCommand.cpp index ea7cc8d2..9f01a1e9 100644 --- a/commands/tools/selection/text/kpToolTextDeleteCommand.cpp +++ b/commands/tools/selection/text/kpToolTextDeleteCommand.cpp @@ -1,139 +1,140 @@ /* Copyright (c) 2003-2007 Clarence Dang All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #define DEBUG_KP_TOOL_TEXT 0 #include "kpToolTextDeleteCommand.h" #include "layers/selections/text/kpTextSelection.h" #include "views/manager/kpViewManager.h" #include kpToolTextDeleteCommand::kpToolTextDeleteCommand (const QString &name, int row, int col, Action action, kpCommandEnvironment *environ) : kpNamedCommand (name, environ), m_row (row), m_col (col), m_numDeletes (0) { viewManager ()->setTextCursorPosition (m_row, m_col); if (action == AddDeleteNow) addDelete (); } kpToolTextDeleteCommand::~kpToolTextDeleteCommand () { } // public void kpToolTextDeleteCommand::addDelete () { QList textLines = textSelection ()->textLines (); - if (m_col < (int) textLines [m_row].length ()) + if (m_col < static_cast (textLines [m_row].length ())) { m_deletedText.prepend (textLines [m_row][m_col]); textLines [m_row] = textLines [m_row].left (m_col) + textLines [m_row].mid (m_col + 1); } else { - if (m_row < (int) textLines.size () - 1) + if (m_row < static_cast (textLines.size () - 1)) { m_deletedText.prepend ('\n'); textLines [m_row] += textLines [m_row + 1]; textLines.erase (textLines.begin () + m_row + 1); } } textSelection ()->setTextLines (textLines); viewManager ()->setTextCursorPosition (m_row, m_col); m_numDeletes++; } // public virtual [base kpCommand] kpCommandSize::SizeType kpToolTextDeleteCommand::size () const { - return (kpCommandSize::SizeType) m_deletedText.length () * sizeof (QChar); + return static_cast + (static_cast (m_deletedText.length ()) * sizeof (QChar)); } // public virtual [base kpCommand] void kpToolTextDeleteCommand::execute () { viewManager ()->setTextCursorPosition (m_row, m_col); m_deletedText.clear (); int oldNumDeletes = m_numDeletes; m_numDeletes = 0; for (int i = 0; i < oldNumDeletes; i++) addDelete (); } // public virtual [base kpCommand] void kpToolTextDeleteCommand::unexecute () { viewManager ()->setTextCursorPosition (m_row, m_col); QList textLines = textSelection ()->textLines (); - for (int i = 0; i < (int) m_deletedText.length (); i++) + for (int i = 0; i < static_cast (m_deletedText.length ()); i++) { if (m_deletedText [i] == '\n') { const QString rightHalf = textLines [m_row].mid (m_col); textLines [m_row].truncate (m_col); textLines.insert (textLines.begin () + m_row + 1, rightHalf); } else { const QString leftHalf = textLines [m_row].left (m_col); const QString rightHalf = textLines [m_row].mid (m_col); textLines [m_row] = leftHalf + m_deletedText [i] + rightHalf; } } m_deletedText.clear (); textSelection ()->setTextLines (textLines); viewManager ()->setTextCursorPosition (m_row, m_col); } diff --git a/commands/tools/selection/text/kpToolTextInsertCommand.cpp b/commands/tools/selection/text/kpToolTextInsertCommand.cpp index 2a95021b..d5d70a55 100644 --- a/commands/tools/selection/text/kpToolTextInsertCommand.cpp +++ b/commands/tools/selection/text/kpToolTextInsertCommand.cpp @@ -1,108 +1,109 @@ /* Copyright (c) 2003-2007 Clarence Dang All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #define DEBUG_KP_TOOL_TEXT 0 #include "kpToolTextInsertCommand.h" #include "layers/selections/text/kpTextSelection.h" #include "views/manager/kpViewManager.h" #include //--------------------------------------------------------------------- kpToolTextInsertCommand::kpToolTextInsertCommand (const QString &name, int row, int col, QString newText, kpCommandEnvironment *environ) : kpNamedCommand (name, environ), m_row (row), m_col (col) { viewManager ()->setTextCursorPosition (m_row, m_col); addText (newText); } //--------------------------------------------------------------------- // public void kpToolTextInsertCommand::addText (const QString &moreText) { if (moreText.isEmpty ()) return; QList textLines = textSelection ()->textLines (); const QString leftHalf = textLines [m_row].left (m_col); const QString rightHalf = textLines [m_row].mid (m_col); textLines [m_row] = leftHalf + moreText + rightHalf; textSelection ()->setTextLines (textLines); m_newText += moreText; m_col += moreText.length (); viewManager ()->setTextCursorPosition (m_row, m_col); } //--------------------------------------------------------------------- // public virtual [base kpCommand] kpCommandSize::SizeType kpToolTextInsertCommand::size () const { - return (kpCommandSize::SizeType) m_newText.length () * sizeof (QChar); + return static_cast + (static_cast (m_newText.length ()) * sizeof (QChar)); } //--------------------------------------------------------------------- // public virtual [base kpCommand] void kpToolTextInsertCommand::execute () { viewManager ()->setTextCursorPosition (m_row, m_col); QString text = m_newText; m_newText.clear (); addText (text); } //--------------------------------------------------------------------- // public virtual [base kpCommand] void kpToolTextInsertCommand::unexecute () { viewManager ()->setTextCursorPosition (m_row, m_col); QList textLines = textSelection ()->textLines (); const QString leftHalf = textLines [m_row].left (m_col - m_newText.length ()); const QString rightHalf = textLines [m_row].mid (m_col); textLines [m_row] = leftHalf + rightHalf; textSelection ()->setTextLines (textLines); m_col -= m_newText.length (); viewManager ()->setTextCursorPosition (m_row, m_col); } //--------------------------------------------------------------------- diff --git a/dialogs/imagelib/transforms/kpTransformResizeScaleDialog.cpp b/dialogs/imagelib/transforms/kpTransformResizeScaleDialog.cpp index e3dfa483..359bef9d 100644 --- a/dialogs/imagelib/transforms/kpTransformResizeScaleDialog.cpp +++ b/dialogs/imagelib/transforms/kpTransformResizeScaleDialog.cpp @@ -1,823 +1,823 @@ /* Copyright (c) 2003-2007 Clarence Dang Copyright (c) 2011 Martin Koller All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #define DEBUG_KP_TOOL_RESIZE_SCALE_DIALOG 0 #include "kpTransformResizeScaleDialog.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "kpLogCategories.h" #include #include #include #include "layers/selections/kpAbstractSelection.h" #include "kpDefs.h" #include "document/kpDocument.h" #include "layers/selections/text/kpTextSelection.h" #include "tools/kpTool.h" #include "environments/dialogs/imagelib/transforms/kpTransformDialogEnvironment.h" //--------------------------------------------------------------------- #define kpSettingResizeScaleLastKeepAspect "Resize Scale - Last Keep Aspect" #define kpSettingResizeScaleScaleType "Resize Scale - ScaleType" //--------------------------------------------------------------------- #define SET_VALUE_WITHOUT_SIGNAL_EMISSION(knuminput_instance,value) \ { \ knuminput_instance->blockSignals (true); \ knuminput_instance->setValue (value); \ knuminput_instance->blockSignals (false); \ } #define IGNORE_KEEP_ASPECT_RATIO(cmd) \ { \ m_ignoreKeepAspectRatio++; \ cmd; \ m_ignoreKeepAspectRatio--; \ } //--------------------------------------------------------------------- kpTransformResizeScaleDialog::kpTransformResizeScaleDialog ( kpTransformDialogEnvironment *_env, QWidget *parent) : QDialog (parent), m_environ (_env), m_ignoreKeepAspectRatio (0), m_lastType(kpTransformResizeScaleCommand::Resize) { setWindowTitle (i18nc ("@title:window", "Resize / Scale")); QDialogButtonBox *buttons = new QDialogButtonBox (QDialogButtonBox::Ok | QDialogButtonBox::Cancel, this); connect (buttons, SIGNAL (accepted()), this, SLOT (accept())); connect (buttons, SIGNAL (rejected()), this, SLOT (reject())); QWidget *baseWidget = new QWidget (this); QVBoxLayout *dialogLayout = new QVBoxLayout (this); dialogLayout->addWidget (baseWidget); dialogLayout->addWidget (buttons); QWidget *actOnBox = createActOnBox(baseWidget); QGroupBox *operationGroupBox = createOperationGroupBox(baseWidget); QGroupBox *dimensionsGroupBox = createDimensionsGroupBox(baseWidget); QVBoxLayout *baseLayout = new QVBoxLayout (baseWidget); baseLayout->setMargin(0); baseLayout->addWidget(actOnBox); baseLayout->addWidget(operationGroupBox); baseLayout->addWidget(dimensionsGroupBox); KConfigGroup cfg(KSharedConfig::openConfig(), kpSettingsGroupGeneral); setKeepAspectRatio(cfg.readEntry(kpSettingResizeScaleLastKeepAspect, false)); m_lastType = static_cast (cfg.readEntry(kpSettingResizeScaleScaleType, static_cast(kpTransformResizeScaleCommand::Resize))); slotActOnChanged (); m_newWidthInput->setFocus (); //enableButtonOk (!isNoOp ()); } //--------------------------------------------------------------------- // private kpDocument *kpTransformResizeScaleDialog::document () const { return m_environ->document (); } //--------------------------------------------------------------------- // private kpAbstractSelection *kpTransformResizeScaleDialog::selection () const { Q_ASSERT (document ()); return document ()->selection (); } //--------------------------------------------------------------------- // private kpTextSelection *kpTransformResizeScaleDialog::textSelection () const { Q_ASSERT (document ()); return document ()->textSelection (); } //--------------------------------------------------------------------- // private QWidget *kpTransformResizeScaleDialog::createActOnBox(QWidget *baseWidget) { QWidget *actOnBox = new QWidget (baseWidget); QLabel *actOnLabel = new QLabel (i18n ("Ac&t on:"), actOnBox); m_actOnCombo = new QComboBox (actOnBox); actOnLabel->setBuddy (m_actOnCombo); m_actOnCombo->insertItem (Image, i18n ("Entire Image")); if (selection ()) { QString selName = i18n ("Selection"); if (textSelection ()) selName = i18n ("Text Box"); m_actOnCombo->insertItem (Selection, selName); m_actOnCombo->setCurrentIndex (Selection); } else { actOnLabel->setEnabled (false); m_actOnCombo->setEnabled (false); } QHBoxLayout *lay = new QHBoxLayout (actOnBox); lay->setMargin (0); lay->addWidget (actOnLabel); lay->addWidget (m_actOnCombo, 1); connect (m_actOnCombo, SIGNAL (activated(int)), this, SLOT (slotActOnChanged())); return actOnBox; } //--------------------------------------------------------------------- static void toolButtonSetLook (QToolButton *button, const QString &iconName, const QString &name) { QPixmap icon = UserIcon (iconName); button->setIconSize (QSize (icon.width (), icon.height ())); button->setIcon (icon); button->setToolButtonStyle (Qt::ToolButtonTextUnderIcon); button->setText (name); button->setFocusPolicy (Qt::StrongFocus); button->setCheckable (true); } //--------------------------------------------------------------------- // private QGroupBox *kpTransformResizeScaleDialog::createOperationGroupBox (QWidget *baseWidget) { QGroupBox *operationGroupBox = new QGroupBox (i18n ("Operation"), baseWidget); operationGroupBox->setWhatsThis( i18n ("" "
    " "
  • Resize: The size of the picture will be" " increased" " by creating new areas to the right and/or bottom" " (filled in with the background color) or" " decreased by cutting" " it at the right and/or bottom.
  • " "
  • Scale: The picture will be expanded" " by duplicating pixels or squashed by dropping pixels.
  • " "
  • Smooth Scale: This is the same as" " Scale except that it blends neighboring" " pixels to produce a smoother looking picture.
  • " "
" "
")); m_resizeButton = new QToolButton (operationGroupBox); toolButtonSetLook (m_resizeButton, QLatin1String ("resize"), i18n ("&Resize")); m_scaleButton = new QToolButton (operationGroupBox); toolButtonSetLook (m_scaleButton, QLatin1String ("scale"), i18n ("&Scale")); m_smoothScaleButton = new QToolButton (operationGroupBox); toolButtonSetLook (m_smoothScaleButton, QLatin1String ("smooth_scale"), i18n ("S&mooth Scale")); QButtonGroup *resizeScaleButtonGroup = new QButtonGroup (baseWidget); resizeScaleButtonGroup->addButton (m_resizeButton); resizeScaleButtonGroup->addButton (m_scaleButton); resizeScaleButtonGroup->addButton (m_smoothScaleButton); QGridLayout *operationLayout = new QGridLayout (operationGroupBox ); operationLayout->addWidget (m_resizeButton, 0, 0, Qt::AlignCenter); operationLayout->addWidget (m_scaleButton, 0, 1, Qt::AlignCenter); operationLayout->addWidget (m_smoothScaleButton, 0, 2, Qt::AlignCenter); connect (m_resizeButton, SIGNAL (toggled(bool)), this, SLOT (slotTypeChanged())); connect (m_scaleButton, SIGNAL (toggled(bool)), this, SLOT (slotTypeChanged())); connect (m_smoothScaleButton, SIGNAL (toggled(bool)), this, SLOT (slotTypeChanged())); return operationGroupBox; } //--------------------------------------------------------------------- // private QGroupBox *kpTransformResizeScaleDialog::createDimensionsGroupBox(QWidget *baseWidget) { QGroupBox *dimensionsGroupBox = new QGroupBox (i18n ("Dimensions"), baseWidget); QLabel *widthLabel = new QLabel (i18n ("Width:"), dimensionsGroupBox); widthLabel->setAlignment (widthLabel->alignment () | Qt::AlignHCenter); QLabel *heightLabel = new QLabel (i18n ("Height:"), dimensionsGroupBox); heightLabel->setAlignment (heightLabel->alignment () | Qt::AlignHCenter); QLabel *originalLabel = new QLabel (i18n ("Original:"), dimensionsGroupBox); m_originalWidthInput = new QSpinBox; m_originalWidthInput->setRange(1, INT_MAX); - m_originalWidthInput->setValue(document()->width((bool)selection())); + m_originalWidthInput->setValue(document()->width(static_cast (selection()))); QLabel *xLabel0 = new QLabel (i18n ("x"), dimensionsGroupBox); m_originalHeightInput = new QSpinBox; m_originalHeightInput->setRange(1, INT_MAX); - m_originalHeightInput->setValue(document()->height((bool)selection())); + m_originalHeightInput->setValue(document()->height(static_cast (selection()))); QLabel *newLabel = new QLabel (i18n ("&New:"), dimensionsGroupBox); m_newWidthInput = new QSpinBox; m_newWidthInput->setRange(1, INT_MAX); QLabel *xLabel1 = new QLabel (i18n ("x"), dimensionsGroupBox); m_newHeightInput = new QSpinBox; m_newHeightInput->setRange(1, INT_MAX); QLabel *percentLabel = new QLabel (i18n ("&Percent:"), dimensionsGroupBox); m_percentWidthInput = new QDoubleSpinBox; m_percentWidthInput->setRange(0.01, 1000000); m_percentWidthInput->setValue(100); m_percentWidthInput->setSingleStep(1); m_percentWidthInput->setDecimals(2); m_percentWidthInput->setSuffix(i18n("%")); QLabel *xLabel2 = new QLabel (i18n ("x"), dimensionsGroupBox); m_percentHeightInput = new QDoubleSpinBox; m_percentHeightInput->setRange(0.01, 1000000); m_percentHeightInput->setValue(100); m_percentHeightInput->setSingleStep(1); m_percentHeightInput->setDecimals(2); m_percentHeightInput->setSuffix(i18n("%")); m_keepAspectRatioCheckBox = new QCheckBox (i18n ("Keep &aspect ratio"), dimensionsGroupBox); m_originalWidthInput->setEnabled (false); m_originalHeightInput->setEnabled (false); originalLabel->setBuddy (m_originalWidthInput); newLabel->setBuddy (m_newWidthInput); m_percentWidthInput->setValue (100); m_percentHeightInput->setValue (100); percentLabel->setBuddy (m_percentWidthInput); QGridLayout *dimensionsLayout = new QGridLayout (dimensionsGroupBox); dimensionsLayout->setColumnStretch (1/*column*/, 1); dimensionsLayout->setColumnStretch (3/*column*/, 1); dimensionsLayout->addWidget (widthLabel, 0, 1); dimensionsLayout->addWidget (heightLabel, 0, 3); dimensionsLayout->addWidget (originalLabel, 1, 0); dimensionsLayout->addWidget (m_originalWidthInput, 1, 1); dimensionsLayout->addWidget (xLabel0, 1, 2); dimensionsLayout->addWidget (m_originalHeightInput, 1, 3); dimensionsLayout->addWidget (newLabel, 2, 0); dimensionsLayout->addWidget (m_newWidthInput, 2, 1); dimensionsLayout->addWidget (xLabel1, 2, 2); dimensionsLayout->addWidget (m_newHeightInput, 2, 3); dimensionsLayout->addWidget (percentLabel, 3, 0); dimensionsLayout->addWidget (m_percentWidthInput, 3, 1); dimensionsLayout->addWidget (xLabel2, 3, 2); dimensionsLayout->addWidget (m_percentHeightInput, 3, 3); dimensionsLayout->addWidget (m_keepAspectRatioCheckBox, 4, 0, 1, 4); dimensionsLayout->setRowStretch (4/*row*/, 1); dimensionsLayout->setRowMinimumHeight (4/*row*/, dimensionsLayout->rowMinimumHeight (4) * 2); connect (m_newWidthInput, SIGNAL (valueChanged(int)), this, SLOT (slotWidthChanged(int))); connect (m_newHeightInput, SIGNAL (valueChanged(int)), this, SLOT (slotHeightChanged(int))); // COMPAT: KDoubleNumInput only fires valueChanged(double) once per // edit. It should either fire: // // 1. At the end of the edit (triggered by clicking or tabbing // away), like with KDE 3. // // OR // // 2. Once per keystroke. // // Bug in KDoubleNumInput. connect (m_percentWidthInput, SIGNAL (valueChanged(double)), this, SLOT (slotPercentWidthChanged(double))); connect (m_percentHeightInput, SIGNAL (valueChanged(double)), this, SLOT (slotPercentHeightChanged(double))); connect (m_keepAspectRatioCheckBox, SIGNAL (toggled(bool)), this, SLOT (setKeepAspectRatio(bool))); return dimensionsGroupBox; } //--------------------------------------------------------------------- // private void kpTransformResizeScaleDialog::widthFitHeightToAspectRatio () { if (m_keepAspectRatioCheckBox->isChecked () && !m_ignoreKeepAspectRatio) { // width / height = oldWidth / oldHeight // height = width * oldHeight / oldWidth const int newHeight = qRound (double (imageWidth ()) * double (originalHeight ()) / double (originalWidth ())); IGNORE_KEEP_ASPECT_RATIO (m_newHeightInput->setValue (newHeight)); } } //--------------------------------------------------------------------- // private void kpTransformResizeScaleDialog::heightFitWidthToAspectRatio () { if (m_keepAspectRatioCheckBox->isChecked () && !m_ignoreKeepAspectRatio) { // width / height = oldWidth / oldHeight // width = height * oldWidth / oldHeight const int newWidth = qRound (double (imageHeight ()) * double (originalWidth ()) / double (originalHeight ())); IGNORE_KEEP_ASPECT_RATIO (m_newWidthInput->setValue (newWidth)); } } //--------------------------------------------------------------------- // private bool kpTransformResizeScaleDialog::resizeEnabled () const { return (!actOnSelection () || (actOnSelection () && textSelection ())); } //--------------------------------------------------------------------- // private bool kpTransformResizeScaleDialog::scaleEnabled () const { return (!(actOnSelection () && textSelection ())); } //--------------------------------------------------------------------- // private bool kpTransformResizeScaleDialog::smoothScaleEnabled () const { return scaleEnabled (); } //--------------------------------------------------------------------- // public slot void kpTransformResizeScaleDialog::slotActOnChanged () { #if DEBUG_KP_TOOL_RESIZE_SCALE_DIALOG && 1 qCDebug(kpLogDialogs) << "kpTransformResizeScaleDialog::slotActOnChanged()"; #endif m_resizeButton->setEnabled (resizeEnabled ()); m_scaleButton->setEnabled (scaleEnabled ()); m_smoothScaleButton->setEnabled (smoothScaleEnabled ()); // TODO: somehow share logic with (resize|*scale)Enabled() if (actOnSelection ()) { if (textSelection ()) { m_resizeButton->setChecked (true); } else { if (m_lastType == kpTransformResizeScaleCommand::Scale) m_scaleButton->setChecked (true); else m_smoothScaleButton->setChecked (true); } } else { if (m_lastType == kpTransformResizeScaleCommand::Resize) m_resizeButton->setChecked (true); else if (m_lastType == kpTransformResizeScaleCommand::Scale) m_scaleButton->setChecked (true); else m_smoothScaleButton->setChecked (true); } m_originalWidthInput->setValue (originalWidth ()); m_originalHeightInput->setValue (originalHeight ()); m_newWidthInput->blockSignals (true); m_newHeightInput->blockSignals (true); m_newWidthInput->setMinimum (actOnSelection () ? selection ()->minimumWidth () : 1); m_newHeightInput->setMinimum (actOnSelection () ? selection ()->minimumHeight () : 1); m_newWidthInput->blockSignals (false); m_newHeightInput->blockSignals (false); IGNORE_KEEP_ASPECT_RATIO (slotPercentWidthChanged (m_percentWidthInput->value ())); IGNORE_KEEP_ASPECT_RATIO (slotPercentHeightChanged (m_percentHeightInput->value ())); setKeepAspectRatio (m_keepAspectRatioCheckBox->isChecked ()); } //--------------------------------------------------------------------- // public slot void kpTransformResizeScaleDialog::slotTypeChanged () { m_lastType = type (); } //--------------------------------------------------------------------- // public slot void kpTransformResizeScaleDialog::slotWidthChanged (int width) { #if DEBUG_KP_TOOL_RESIZE_SCALE_DIALOG && 1 qCDebug(kpLogDialogs) << "kpTransformResizeScaleDialog::slotWidthChanged(" << width << ")" << endl; #endif const double newPercentWidth = double (width) * 100 / double (originalWidth ()); SET_VALUE_WITHOUT_SIGNAL_EMISSION (m_percentWidthInput,newPercentWidth); widthFitHeightToAspectRatio (); //enableButtonOk (!isNoOp ()); } //--------------------------------------------------------------------- // public slot void kpTransformResizeScaleDialog::slotHeightChanged (int height) { #if DEBUG_KP_TOOL_RESIZE_SCALE_DIALOG && 1 qCDebug(kpLogDialogs) << "kpTransformResizeScaleDialog::slotHeightChanged(" << height << ")" << endl; #endif const double newPercentHeight = double (height) * 100 / double (originalHeight ()); SET_VALUE_WITHOUT_SIGNAL_EMISSION (m_percentHeightInput,newPercentHeight); heightFitWidthToAspectRatio (); //enableButtonOk (!isNoOp ()); } //--------------------------------------------------------------------- // public slot void kpTransformResizeScaleDialog::slotPercentWidthChanged (double percentWidth) { #if DEBUG_KP_TOOL_RESIZE_SCALE_DIALOG && 1 qCDebug(kpLogDialogs) << "kpTransformResizeScaleDialog::slotPercentWidthChanged(" << percentWidth << ")" << endl; #endif SET_VALUE_WITHOUT_SIGNAL_EMISSION (m_newWidthInput, qRound (percentWidth * originalWidth () / 100.0)); widthFitHeightToAspectRatio (); //enableButtonOk (!isNoOp ()); } //--------------------------------------------------------------------- // public slot void kpTransformResizeScaleDialog::slotPercentHeightChanged (double percentHeight) { #if DEBUG_KP_TOOL_RESIZE_SCALE_DIALOG && 1 qCDebug(kpLogDialogs) << "kpTransformResizeScaleDialog::slotPercentHeightChanged(" << percentHeight << ")" << endl; #endif SET_VALUE_WITHOUT_SIGNAL_EMISSION (m_newHeightInput, qRound (percentHeight * originalHeight () / 100.0)); heightFitWidthToAspectRatio (); //enableButtonOk (!isNoOp ()); } //--------------------------------------------------------------------- // public slot void kpTransformResizeScaleDialog::setKeepAspectRatio (bool on) { #if DEBUG_KP_TOOL_RESIZE_SCALE_DIALOG && 1 qCDebug(kpLogDialogs) << "kpTransformResizeScaleDialog::setKeepAspectRatio(" << on << ")" << endl; #endif if (on != m_keepAspectRatioCheckBox->isChecked ()) m_keepAspectRatioCheckBox->setChecked (on); if (on) widthFitHeightToAspectRatio (); } //--------------------------------------------------------------------- #undef IGNORE_KEEP_ASPECT_RATIO #undef SET_VALUE_WITHOUT_SIGNAL_EMISSION //--------------------------------------------------------------------- // private int kpTransformResizeScaleDialog::originalWidth () const { return document ()->width (actOnSelection ()); } //--------------------------------------------------------------------- // private int kpTransformResizeScaleDialog::originalHeight () const { return document ()->height (actOnSelection ()); } //--------------------------------------------------------------------- // public int kpTransformResizeScaleDialog::imageWidth () const { return m_newWidthInput->value (); } //--------------------------------------------------------------------- // public int kpTransformResizeScaleDialog::imageHeight () const { return m_newHeightInput->value (); } //--------------------------------------------------------------------- // public bool kpTransformResizeScaleDialog::actOnSelection () const { return (m_actOnCombo->currentIndex () == Selection); } //--------------------------------------------------------------------- // public kpTransformResizeScaleCommand::Type kpTransformResizeScaleDialog::type () const { if (m_resizeButton->isChecked ()) return kpTransformResizeScaleCommand::Resize; else if (m_scaleButton->isChecked ()) return kpTransformResizeScaleCommand::Scale; else return kpTransformResizeScaleCommand::SmoothScale; } //--------------------------------------------------------------------- // public bool kpTransformResizeScaleDialog::isNoOp () const { return (imageWidth () == originalWidth () && imageHeight () == originalHeight ()); } //--------------------------------------------------------------------- // private slot virtual [base QDialog] void kpTransformResizeScaleDialog::accept () { enum { eText, eSelection, eImage } actionTarget = eText; if (actOnSelection ()) { if (textSelection ()) { actionTarget = eText; } else { actionTarget = eSelection; } } else { actionTarget = eImage; } KLocalizedString message; QString caption, continueButtonText; // Note: If eText, can't Scale nor SmoothScale. // If eSelection, can't Resize. switch (type ()) { default: case kpTransformResizeScaleCommand::Resize: if (actionTarget == eText) { message = ki18n ("

Resizing the text box to %1x%2" " may take a substantial amount of memory." " This can reduce system" " responsiveness and cause other application resource" " problems.

" "

Are you sure you want to resize the text box?

"); caption = i18nc ("@title:window", "Resize Text Box?"); continueButtonText = i18n ("R&esize Text Box"); } else if (actionTarget == eImage) { message = ki18n ("

Resizing the image to %1x%2" " may take a substantial amount of memory." " This can reduce system" " responsiveness and cause other application resource" " problems.

" "

Are you sure you want to resize the image?

"); caption = i18nc ("@title:window", "Resize Image?"); continueButtonText = i18n ("R&esize Image"); } break; case kpTransformResizeScaleCommand::Scale: if (actionTarget == eImage) { message = ki18n ("

Scaling the image to %1x%2" " may take a substantial amount of memory." " This can reduce system" " responsiveness and cause other application resource" " problems.

" "

Are you sure you want to scale the image?

"); caption = i18nc ("@title:window", "Scale Image?"); continueButtonText = i18n ("Scal&e Image"); } else if (actionTarget == eSelection) { message = ki18n ("

Scaling the selection to %1x%2" " may take a substantial amount of memory." " This can reduce system" " responsiveness and cause other application resource" " problems.

" "

Are you sure you want to scale the selection?

"); caption = i18nc ("@title:window", "Scale Selection?"); continueButtonText = i18n ("Scal&e Selection"); } break; case kpTransformResizeScaleCommand::SmoothScale: if (actionTarget == eImage) { message = ki18n ("

Smooth Scaling the image to %1x%2" " may take a substantial amount of memory." " This can reduce system" " responsiveness and cause other application resource" " problems.

" "

Are you sure you want to smooth scale the image?

"); caption = i18nc ("@title:window", "Smooth Scale Image?"); continueButtonText = i18n ("Smooth Scal&e Image"); } else if (actionTarget == eSelection) { message = ki18n ("

Smooth Scaling the selection to %1x%2" " may take a substantial amount of memory." " This can reduce system" " responsiveness and cause other application resource" " problems.

" "

Are you sure you want to smooth scale the selection?

"); caption = i18nc ("@title:window", "Smooth Scale Selection?"); continueButtonText = i18n ("Smooth Scal&e Selection"); } break; } if (kpTool::warnIfBigImageSize (originalWidth (), originalHeight (), imageWidth (), imageHeight (), message.subs (imageWidth ()).subs (imageHeight ()).toString (), caption, continueButtonText, this)) { QDialog::accept (); } // store settings KConfigGroup cfg(KSharedConfig::openConfig(), kpSettingsGroupGeneral); cfg.writeEntry(kpSettingResizeScaleLastKeepAspect, m_keepAspectRatioCheckBox->isChecked()); cfg.writeEntry(kpSettingResizeScaleScaleType, static_cast(m_lastType)); cfg.sync(); } //--------------------------------------------------------------------- diff --git a/dialogs/kpDocumentSaveOptionsPreviewDialog.cpp b/dialogs/kpDocumentSaveOptionsPreviewDialog.cpp index 6ad750ad..7c7aa480 100644 --- a/dialogs/kpDocumentSaveOptionsPreviewDialog.cpp +++ b/dialogs/kpDocumentSaveOptionsPreviewDialog.cpp @@ -1,239 +1,239 @@ /* Copyright (c) 2003-2007 Clarence Dang 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_DOCUMENT_SAVE_OPTIONS_WIDGET 0 #include "kpDocumentSaveOptionsPreviewDialog.h" #include #include #include #include #include #include #include "kpLogCategories.h" #include #include "commands/kpCommandSize.h" #include "kpDefs.h" #include "document/kpDocument.h" #include "pixmapfx/kpPixmapFX.h" #include "generic/widgets/kpResizeSignallingLabel.h" #include "dialogs/imagelib/transforms/kpTransformPreviewDialog.h" // protected static const QSize kpDocumentSaveOptionsPreviewDialog::s_pixmapLabelMinimumSize (25, 25); kpDocumentSaveOptionsPreviewDialog::kpDocumentSaveOptionsPreviewDialog ( QWidget *parent ) : kpSubWindow (parent), m_filePixmap (nullptr), m_fileSize (0) { setWindowTitle (i18nc ("@title:window", "Save Preview")); QWidget *baseWidget = this;//new QWidget (this); //setMainWidget (baseWidget); QGridLayout *lay = new QGridLayout ( baseWidget ); m_filePixmapLabel = new kpResizeSignallingLabel (baseWidget); m_fileSizeLabel = new QLabel (baseWidget); m_filePixmapLabel->setMinimumSize (s_pixmapLabelMinimumSize); lay->addWidget (m_filePixmapLabel, 0, 0); lay->addWidget (m_fileSizeLabel, 1, 0, Qt::AlignHCenter); lay->setRowStretch (0, 1); connect (m_filePixmapLabel, SIGNAL (resized()), this, SLOT (updatePixmapPreview())); } kpDocumentSaveOptionsPreviewDialog::~kpDocumentSaveOptionsPreviewDialog () { delete m_filePixmap; } // public QSize kpDocumentSaveOptionsPreviewDialog::preferredMinimumSize () const { const int contentsWidth = 180; const int totalMarginsWidth = fontMetrics ().height (); return QSize (contentsWidth + totalMarginsWidth, contentsWidth * 3 / 4 + totalMarginsWidth); } // public slot void kpDocumentSaveOptionsPreviewDialog::setFilePixmapAndSize (const QImage &pixmap, qint64 fileSize) { delete m_filePixmap; m_filePixmap = new QImage (pixmap); updatePixmapPreview (); m_fileSize = fileSize; const kpCommandSize::SizeType pixmapSize = kpCommandSize::PixmapSize (pixmap); // (int cast is safe as long as the file size is not more than 20 million // -- i.e. INT_MAX / 100 -- times the pixmap size) const int percent = pixmapSize ? qMax (1, - (int) ((kpCommandSize::SizeType) fileSize * 100 / pixmapSize)) : + static_cast (static_cast (fileSize * 100 / pixmapSize))) : 0; #if DEBUG_KP_DOCUMENT_SAVE_OPTIONS_WIDGET qCDebug(kpLogDialogs) << "kpDocumentSaveOptionsPreviewDialog::setFilePixmapAndSize()" << " pixmapSize=" << pixmapSize << " fileSize=" << fileSize << " raw fileSize/pixmapSize%=" << (pixmapSize ? (kpCommandSize::SizeType) fileSize * 100 / pixmapSize : 0) << endl; #endif m_fileSizeLabel->setText (i18np ("1 byte (approx. %2%)", "%1 bytes (approx. %2%)", m_fileSize, percent)); } // public slot void kpDocumentSaveOptionsPreviewDialog::updatePixmapPreview () { #if DEBUG_KP_DOCUMENT_SAVE_OPTIONS_WIDGET qCDebug(kpLogDialogs) << "kpDocumentSaveOptionsPreviewDialog::updatePreviewPixmap()" << " filePixmapLabel.size=" << m_filePixmapLabel->size () << " filePixmap.size=" << m_filePixmap->size () << endl; #endif if (m_filePixmap) { int maxNewWidth = qMin (m_filePixmap->width (), m_filePixmapLabel->width ()), maxNewHeight = qMin (m_filePixmap->height (), m_filePixmapLabel->height ()); double keepsAspect = kpTransformPreviewDialog::aspectScale ( maxNewWidth, maxNewHeight, m_filePixmap->width (), m_filePixmap->height ()); #if DEBUG_KP_DOCUMENT_SAVE_OPTIONS_WIDGET qCDebug(kpLogDialogs) << "\tmaxNewWidth=" << maxNewWidth << " maxNewHeight=" << maxNewHeight << " keepsAspect=" << keepsAspect << endl; #endif const int newWidth = kpTransformPreviewDialog::scaleDimension ( m_filePixmap->width (), keepsAspect, 1, maxNewWidth); const int newHeight = kpTransformPreviewDialog::scaleDimension ( m_filePixmap->height (), keepsAspect, 1, maxNewHeight); #if DEBUG_KP_DOCUMENT_SAVE_OPTIONS_WIDGET qCDebug(kpLogDialogs) << "\tnewWidth=" << newWidth << " newHeight=" << newHeight << endl; #endif QImage transformedPixmap = kpPixmapFX::scale (*m_filePixmap, newWidth, newHeight); QImage labelPixmap (m_filePixmapLabel->width (), m_filePixmapLabel->height (), QImage::Format_ARGB32_Premultiplied); labelPixmap.fill(QColor(Qt::transparent).rgba()); kpPixmapFX::setPixmapAt (&labelPixmap, (labelPixmap.width () - transformedPixmap.width ()) / 2, (labelPixmap.height () - transformedPixmap.height ()) / 2, transformedPixmap); m_filePixmapLabel->setPixmap (QPixmap::fromImage(labelPixmap)); } else { m_filePixmapLabel->setPixmap (QPixmap ()); } } // protected virtual [base QWidget] void kpDocumentSaveOptionsPreviewDialog::closeEvent (QCloseEvent *e) { #if DEBUG_KP_DOCUMENT_SAVE_OPTIONS_WIDGET qCDebug(kpLogDialogs) << "kpDocumentSaveOptionsPreviewDialog::closeEvent()"; #endif QWidget::closeEvent (e); emit finished (); } // protected virtual [base QWidget] void kpDocumentSaveOptionsPreviewDialog::moveEvent (QMoveEvent *e) { #if DEBUG_KP_DOCUMENT_SAVE_OPTIONS_WIDGET qCDebug(kpLogDialogs) << "kpDocumentSaveOptionsPreviewDialog::moveEvent()"; #endif QWidget::moveEvent (e); emit moved (); } // protected virtual [base QWidget] void kpDocumentSaveOptionsPreviewDialog::resizeEvent (QResizeEvent *e) { #if DEBUG_KP_DOCUMENT_SAVE_OPTIONS_WIDGET qCDebug(kpLogDialogs) << "kpDocumentSaveOptionsPreviewDialog::resizeEvent()"; #endif QWidget::resizeEvent (e); emit resized (); } diff --git a/document/kpDocument_Selection.cpp b/document/kpDocument_Selection.cpp index b881dc31..c8488b84 100644 --- a/document/kpDocument_Selection.cpp +++ b/document/kpDocument_Selection.cpp @@ -1,340 +1,340 @@ /* Copyright (c) 2003-2007 Clarence Dang 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_DOCUMENT 0 #include "kpDocument.h" #include "kpDocumentPrivate.h" #include #include #include #include #include "kpLogCategories.h" #include #include "imagelib/kpColor.h" #include "kpDefs.h" #include "environments/document/kpDocumentEnvironment.h" #include "layers/selections/kpAbstractSelection.h" #include "layers/selections/image/kpAbstractImageSelection.h" #include "layers/selections/text/kpTextSelection.h" // public kpAbstractSelection *kpDocument::selection () const { return m_selection; } //--------------------------------------------------------------------- // public kpAbstractImageSelection *kpDocument::imageSelection () const { return dynamic_cast (m_selection); } //--------------------------------------------------------------------- // public kpTextSelection *kpDocument::textSelection () const { return dynamic_cast (m_selection); } //--------------------------------------------------------------------- // public void kpDocument::setSelection (const kpAbstractSelection &selection) { #if DEBUG_KP_DOCUMENT && 1 qCDebug(kpLogDocument) << "kpDocument::setSelection() sel boundingRect=" << selection.boundingRect () << endl; #endif d->environ->setQueueViewUpdates (); { - const bool hadSelection = (bool) m_selection; + const bool hadSelection = static_cast (m_selection); kpAbstractSelection *oldSelection = m_selection; // (must be called before giving the document a new selection, to // avoid a potential mess where switchToCompatibleTool() ends // the current selection tool, killing the new selection) bool isTextChanged = false; d->environ->switchToCompatibleTool (selection, &isTextChanged); Q_ASSERT (m_selection == oldSelection); m_selection = selection.clone (); // There's no need to uninitialize the old selection // (e.g. call disconnect()) since we delete it later. connect (m_selection, SIGNAL (changed(QRect)), this, SLOT (slotContentsChanged(QRect))); // // Now all kpDocument state has been set. // We can _only_ change the environment after that, as the environment // may access the document. Exception is above with // switchToCompatibleTool(). // d->environ->assertMatchingUIState (selection); // // Now all kpDocument and environment state has been set. // We can _only_ fire signals after that, as the signal receivers (the // "wider environment") may access the document and the environment. // #if DEBUG_KP_DOCUMENT && 1 qCDebug(kpLogDocument) << "\tcheck sel " << (int *) m_selection << " boundingRect=" << m_selection->boundingRect () << endl; #endif if (oldSelection) { if (oldSelection->hasContent ()) slotContentsChanged (oldSelection->boundingRect ()); else emit contentsChanged (oldSelection->boundingRect ()); delete oldSelection; oldSelection = nullptr; } if (m_selection->hasContent ()) slotContentsChanged (m_selection->boundingRect ()); else emit contentsChanged (m_selection->boundingRect ()); if (!hadSelection) emit selectionEnabled (true); if (isTextChanged) emit selectionIsTextChanged (textSelection ()); } d->environ->restoreQueueViewUpdates (); #if DEBUG_KP_DOCUMENT && 1 qCDebug(kpLogDocument) << "\tkpDocument::setSelection() ended"; #endif } //--------------------------------------------------------------------- // public kpImage kpDocument::getSelectedBaseImage () const { kpAbstractImageSelection *imageSel = imageSelection (); Q_ASSERT (imageSel); // Easy if we already have it :) const kpImage image = imageSel->baseImage (); if (!image.isNull ()) return image; const QRect boundingRect = imageSel->boundingRect (); Q_ASSERT (boundingRect.isValid ()); // OPT: This is very slow. Image / More Effects ... calls us twice // unnecessarily. return imageSel->givenImageMaskedByShape (getImageAt (boundingRect)); } //--------------------------------------------------------------------- // public void kpDocument::imageSelectionPullFromDocument (const kpColor &backgroundColor) { kpAbstractImageSelection *imageSel = imageSelection (); Q_ASSERT (imageSel); // Should not already have an image or we would not be pulling. Q_ASSERT (!imageSel->hasContent ()); const QRect boundingRect = imageSel->boundingRect (); Q_ASSERT (boundingRect.isValid ()); // // Get selection image from document // kpImage selectedImage = getSelectedBaseImage (); d->environ->setQueueViewUpdates (); imageSel->setBaseImage (selectedImage); // // Fill opaque bits of the hole in the document // #if !defined (QT_NO_DEBUG) && !defined (NDEBUG) if (imageSel->transparency ().isTransparent ()) { Q_ASSERT (backgroundColor == imageSel->transparency ().transparentColor ()); } else { // If this method is begin called by a tool, the assert does not // have to hold since transparentColor() might not be defined in Opaque // Mode. // // If we were called by a tricky sequence of undo/redo commands, the assert // does not have to hold for additional reason, which is that // kpMainWindow::setImageSelectionTransparency() does not have to // set in Opaque Mode. // // In practice, it probably does hold but I wouldn't bet on it. } #endif kpImage eraseImage(boundingRect.size(), QImage::Format_ARGB32_Premultiplied); eraseImage.fill(backgroundColor.toQRgb()); // only paint the region of the shape of the selection QPainter painter(m_image); painter.setClipRegion(imageSel->shapeRegion()); painter.setCompositionMode(QPainter::CompositionMode_Source); painter.drawImage(boundingRect.topLeft(), eraseImage); slotContentsChanged(boundingRect); d->environ->restoreQueueViewUpdates (); } //--------------------------------------------------------------------- // public void kpDocument::selectionDelete () { if ( !m_selection ) return; const QRect boundingRect = m_selection->boundingRect (); Q_ASSERT (boundingRect.isValid ()); const bool selectionHadContent = m_selection->hasContent (); delete m_selection; m_selection = nullptr; // HACK to prevent document from being modified when // user cancels dragging out a new selection // REFACTOR: Extract this out into a method. if (selectionHadContent) slotContentsChanged (boundingRect); else emit contentsChanged (boundingRect); emit selectionEnabled (false); } //--------------------------------------------------------------------- // public void kpDocument::selectionCopyOntoDocument (bool applySelTransparency) { // Empty selection, just doing nothing if ( !m_selection || !m_selection->hasContent() ) return; const QRect boundingRect = m_selection->boundingRect (); Q_ASSERT (boundingRect.isValid ()); if (imageSelection ()) { if (applySelTransparency) imageSelection ()->paint (m_image, rect ()); else imageSelection ()->paintWithBaseImage (m_image, rect ()); } else { // (for antialiasing with background) m_selection->paint (m_image, rect ()); } slotContentsChanged (boundingRect); } //--------------------------------------------------------------------- // public void kpDocument::selectionPushOntoDocument (bool applySelTransparency) { selectionCopyOntoDocument (applySelTransparency); selectionDelete (); } //--------------------------------------------------------------------- // public kpImage kpDocument::imageWithSelection () const { #if DEBUG_KP_DOCUMENT && 1 qCDebug(kpLogDocument) << "kpDocument::imageWithSelection()"; #endif // Have selection? // // It need not have any content because e.g. a text box with an opaque // background, but no content, is still visually there. if (m_selection) { #if DEBUG_KP_DOCUMENT && 1 qCDebug(kpLogDocument) << "\tselection @ " << m_selection->boundingRect (); #endif kpImage output = *m_image; // (this is a NOP for image selections without content) m_selection->paint (&output, rect ()); return output; } else { #if DEBUG_KP_DOCUMENT && 1 qCDebug(kpLogDocument) << "\tno selection"; #endif return *m_image; } } //--------------------------------------------------------------------- diff --git a/imagelib/effects/blitz.cpp b/imagelib/effects/blitz.cpp index 26de8e70..6866cf1c 100644 --- a/imagelib/effects/blitz.cpp +++ b/imagelib/effects/blitz.cpp @@ -1,668 +1,674 @@ // functions taken from qimageblitz (no longer maintained) /* Copyright (C) 1998, 1999, 2001, 2002, 2004, 2005, 2007 Daniel M. Duley (C) 2004 Zack Rusin (C) 2000 Josef Weidendorfer (C) 1999 Geert Jansen (C) 1998, 1999 Christian Tibirna (C) 1998, 1999 Dirk Mueller 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. */ /* Portions of this software were originally based on ImageMagick's algorithms. ImageMagick is copyrighted under the following conditions: Copyright (C) 2003 ImageMagick Studio, a non-profit organization dedicated to making software imaging solutions freely available. Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files ("ImageMagick"), to deal in ImageMagick without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of ImageMagick, and to permit persons to whom the ImageMagick is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of ImageMagick. The software is provided "as is", without warranty of any kind, express or implied, including but not limited to the warranties of merchantability, fitness for a particular purpose and noninfringement. In no event shall ImageMagick Studio be liable for any claim, damages or other liability, whether in an action of contract, tort or otherwise, arising from, out of or in connection with ImageMagick or the use or other dealings in ImageMagick. Except as contained in this notice, the name of the ImageMagick Studio shall not be used in advertising or otherwise to promote the sale, use or other dealings in ImageMagick without prior written authorization from the ImageMagick Studio. */ #include "blitz.h" #include #include #define M_SQ2PI 2.50662827463100024161235523934010416269302368164062 #define M_EPSILON 1.0e-6 #define CONVOLVE_ACC(weight, pixel) \ r+=((weight))*(qRed((pixel))); g+=((weight))*(qGreen((pixel))); \ b+=((weight))*(qBlue((pixel))); //-------------------------------------------------------------------------------- inline QRgb convertFromPremult(QRgb p) { int alpha = qAlpha(p); return(!alpha ? 0 : qRgba(255*qRed(p)/alpha, 255*qGreen(p)/alpha, 255*qBlue(p)/alpha, alpha)); } //-------------------------------------------------------------------------------- inline QRgb convertToPremult(QRgb p) { unsigned int a = p >> 24; unsigned int t = (p & 0xff00ff) * a; t = (t + ((t >> 8) & 0xff00ff) + 0x800080) >> 8; t &= 0xff00ff; p = ((p >> 8) & 0xff) * a; p = (p + ((p >> 8) & 0xff) + 0x80); p &= 0xff00; p |= t | (a << 24); return(p); } //-------------------------------------------------------------------------------- // These are used as accumulators typedef struct { quint32 red, green, blue, alpha; } IntegerPixel; typedef struct { // Yes, a normal pixel can be used instead but this is easier to read // and no shifts to get components. quint8 red, green, blue, alpha; } CharPixel; typedef struct { quint32 red, green, blue, alpha; } HistogramListItem; bool equalize(QImage &img) { if(img.isNull()) return(false); HistogramListItem *histogram; IntegerPixel *map; IntegerPixel intensity, high, low; CharPixel *equalize_map; int i, count; QRgb pixel, *dest; unsigned char r, g, b; if(img.depth() < 32){ img = img.convertToFormat(img.hasAlphaChannel() ? QImage::Format_ARGB32 : QImage::Format_RGB32); } count = img.width()*img.height(); map = new IntegerPixel[256]; histogram = new HistogramListItem[256]; equalize_map = new CharPixel[256]; // form histogram memset(histogram, 0, 256*sizeof(HistogramListItem)); dest = (QRgb *)img.bits(); if(img.format() == QImage::Format_ARGB32_Premultiplied){ for(i=0; i < count; ++i, ++dest){ pixel = convertFromPremult(*dest); histogram[qRed(pixel)].red++; histogram[qGreen(pixel)].green++; histogram[qBlue(pixel)].blue++; histogram[qAlpha(pixel)].alpha++; } } else{ for(i=0; i < count; ++i){ pixel = *dest++; histogram[qRed(pixel)].red++; histogram[qGreen(pixel)].green++; histogram[qBlue(pixel)].blue++; histogram[qAlpha(pixel)].alpha++; } } // integrate the histogram to get the equalization map memset(&intensity, 0, sizeof(IntegerPixel)); for(i=0; i < 256; ++i){ intensity.red += histogram[i].red; intensity.green += histogram[i].green; intensity.blue += histogram[i].blue; map[i] = intensity; } low = map[0]; high = map[255]; memset(equalize_map, 0, 256*sizeof(CharPixel)); for(i=0; i < 256; ++i){ if(high.red != low.red) - equalize_map[i].red=(unsigned char) + equalize_map[i].red = static_cast ((255*(map[i].red-low.red))/(high.red-low.red)); if(high.green != low.green) - equalize_map[i].green=(unsigned char) + equalize_map[i].green = static_cast ((255*(map[i].green-low.green))/(high.green-low.green)); if(high.blue != low.blue) - equalize_map[i].blue=(unsigned char) + equalize_map[i].blue = static_cast ((255*(map[i].blue-low.blue))/(high.blue-low.blue)); } // stretch the histogram and write dest = (QRgb *)img.bits(); if(img.format() == QImage::Format_ARGB32_Premultiplied){ for(i=0; i < count; ++i, ++dest){ pixel = convertFromPremult(*dest); - r = (low.red != high.red) ? equalize_map[qRed(pixel)].red : - qRed(pixel); - g = (low.green != high.green) ? equalize_map[qGreen(pixel)].green : - qGreen(pixel); - b = (low.blue != high.blue) ? equalize_map[qBlue(pixel)].blue : - qBlue(pixel); + r = static_cast ((low.red != high.red) ? + equalize_map[qRed(pixel)].red : qRed(pixel)); + + g = static_cast ((low.green != high.green) ? + equalize_map[qGreen(pixel)].green : qGreen(pixel)); + + b = static_cast ((low.blue != high.blue) ? + equalize_map[qBlue(pixel)].blue : qBlue(pixel)); + *dest = convertToPremult(qRgba(r, g, b, qAlpha(pixel))); } } else{ for(i=0; i < count; ++i){ pixel = *dest; - r = (low.red != high.red) ? equalize_map[qRed(pixel)].red : - qRed(pixel); - g = (low.green != high.green) ? equalize_map[qGreen(pixel)].green : - qGreen(pixel); - b = (low.blue != high.blue) ? equalize_map[qBlue(pixel)].blue : - qBlue(pixel); + r = static_cast ((low.red != high.red) ? + equalize_map[qRed(pixel)].red : qRed(pixel)); + + g = static_cast ((low.green != high.green) ? + equalize_map[qGreen(pixel)].green : qGreen(pixel)); + + b = static_cast ((low.blue != high.blue) ? + equalize_map[qBlue(pixel)].blue : qBlue(pixel)); + *dest++ = qRgba(r, g, b, qAlpha(pixel)); } } delete[] histogram; delete[] map; delete[] equalize_map; return(true); } //-------------------------------------------------------------------------------- QImage Blitz::blur(QImage &img, int radius) { QRgb *p1, *p2; int x, y, w, h, mx, my, mw, mh, mt, xx, yy; int a, r, g, b; int *as, *rs, *gs, *bs; if(radius < 1 || img.isNull() || img.width() < (radius << 1)) return(img); w = img.width(); h = img.height(); if(img.depth() < 8) img = img.convertToFormat(QImage::Format_Indexed8); QImage buffer(w, h, img.hasAlphaChannel() ? QImage::Format_ARGB32 : QImage::Format_RGB32); as = new int[w]; rs = new int[w]; gs = new int[w]; bs = new int[w]; QVector colorTable; if(img.format() == QImage::Format_Indexed8) colorTable = img.colorTable(); for(y = 0; y < h; y++){ my = y - radius; mh = (radius << 1) + 1; if(my < 0){ mh += my; my = 0; } if((my + mh) > h) mh = h - my; p1 = (QRgb *)buffer.scanLine(y); - memset(as, 0, w * sizeof(int)); - memset(rs, 0, w * sizeof(int)); - memset(gs, 0, w * sizeof(int)); - memset(bs, 0, w * sizeof(int)); + memset(as, 0, static_cast (w) * sizeof(int)); + memset(rs, 0, static_cast (w) * sizeof(int)); + memset(gs, 0, static_cast (w) * sizeof(int)); + memset(bs, 0, static_cast (w) * sizeof(int)); if(img.format() == QImage::Format_ARGB32_Premultiplied){ QRgb pixel; for(yy = 0; yy < mh; yy++){ p2 = (QRgb *)img.scanLine(yy + my); for(x = 0; x < w; x++, p2++){ pixel = convertFromPremult(*p2); as[x] += qAlpha(pixel); rs[x] += qRed(pixel); gs[x] += qGreen(pixel); bs[x] += qBlue(pixel); } } } else if(img.format() == QImage::Format_Indexed8){ QRgb pixel; unsigned char *ptr; for(yy = 0; yy < mh; yy++){ - ptr = (unsigned char *)img.scanLine(yy + my); + ptr = img.scanLine(yy + my); for(x = 0; x < w; x++, ptr++){ pixel = colorTable[*ptr]; as[x] += qAlpha(pixel); rs[x] += qRed(pixel); gs[x] += qGreen(pixel); bs[x] += qBlue(pixel); } } } else{ for(yy = 0; yy < mh; yy++){ p2 = (QRgb *)img.scanLine(yy + my); for(x = 0; x < w; x++, p2++){ as[x] += qAlpha(*p2); rs[x] += qRed(*p2); gs[x] += qGreen(*p2); bs[x] += qBlue(*p2); } } } for(x = 0; x < w; x++){ a = r = g = b = 0; mx = x - radius; mw = (radius << 1) + 1; if(mx < 0){ mw += mx; mx = 0; } if((mx + mw) > w) mw = w - mx; mt = mw * mh; for(xx = mx; xx < (mw + mx); xx++){ a += as[xx]; r += rs[xx]; g += gs[xx]; b += bs[xx]; } a = a / mt; r = r / mt; g = g / mt; b = b / mt; *p1++ = qRgba(r, g, b, a); } } delete[] as; delete[] rs; delete[] gs; delete[] bs; return(buffer); } //-------------------------------------------------------------------------------- int defaultConvolveMatrixSize(float radius, float sigma, bool quality) { int i, matrix_size; float normalize, value; - float sigma2 = sigma*sigma*2.0; - float sigmaSQ2PI = M_SQ2PI*sigma; + float sigma2 = sigma*sigma*2.0f; + float sigmaSQ2PI = static_cast(M_SQ2PI) * sigma; int max = quality ? 65535 : 255; - if(sigma == 0.0){ + if(sigma == 0.0f){ qWarning("Blitz::defaultConvolveMatrixSize(): Zero sigma is invalid!"); return(5); } - if(radius > 0.0) - return((int)(2.0*std::ceil(radius)+1.0)); + if(radius > 0.0f) + return(static_cast(2.0f * std::ceil(radius) + 1.0f)); matrix_size = 5; do{ normalize = 0.0; for(i=(-matrix_size/2); i <= (matrix_size/2); ++i) - normalize += std::exp(-((float) i*i)/sigma2) / sigmaSQ2PI; + normalize += std::exp(-(static_cast (i*i))/sigma2) / sigmaSQ2PI; i = matrix_size/2; - value = std::exp(-((float) i*i)/sigma2) / sigmaSQ2PI / normalize; + value = std::exp(-(static_cast (i*i))/sigma2) / sigmaSQ2PI / normalize; matrix_size += 2; - } while((int)(max*value) > 0); + } while(static_cast(max*value) > 0); matrix_size-=4; return(matrix_size); } //-------------------------------------------------------------------------------- QImage convolve(QImage &img, int matrix_size, float *matrix) { int i, x, y, w, h, matrix_x, matrix_y; int edge = matrix_size/2; QRgb *dest, *src, *s, **scanblock; float *m, *normalize_matrix, normalize; if(!(matrix_size % 2)){ qWarning("Blitz::convolve(): kernel width must be an odd number!"); return(img); } w = img.width(); h = img.height(); if(w < 3 || h < 3){ qWarning("Blitz::convolve(): Image is too small!"); return(img); } if(img.format() == QImage::Format_ARGB32_Premultiplied) img = img.convertToFormat(QImage::Format_ARGB32); else if(img.depth() < 32){ img = img.convertToFormat(img.hasAlphaChannel() ? QImage::Format_ARGB32 : QImage::Format_RGB32); } QImage buffer(w, h, img.format()); scanblock = new QRgb* [matrix_size]; normalize_matrix = new float[matrix_size*matrix_size]; // create normalized matrix normalize = 0.0; for(i=0; i < matrix_size*matrix_size; ++i) normalize += matrix[i]; - if(std::abs(normalize) <= M_EPSILON) - normalize = 1.0; - normalize = 1.0/normalize; + if(std::abs(normalize) <= static_cast (M_EPSILON)) + normalize = 1.0f; + normalize = 1.0f/normalize; for(i=0; i < matrix_size*matrix_size; ++i){ normalize_matrix[i] = normalize*matrix[i]; } // apply { // // // Non-MMX version // // float r, g, b; for(y=0; y < h; ++y){ src = (QRgb *)img.scanLine(y); dest = (QRgb *)buffer.scanLine(y); // Read in scanlines to pixel neighborhood. If the scanline is outside // the image use the top or bottom edge. for(x=y-edge, i=0; x <= y+edge; ++i, ++x){ scanblock[i] = (QRgb *) img.scanLine((x < 0) ? 0 : (x > h-1) ? h-1 : x); } // Now we are about to start processing scanlines. First handle the // part where the pixel neighborhood extends off the left edge. for(x=0; x-edge < 0 ; ++x){ r = g = b = 0.0; m = normalize_matrix; for(matrix_y = 0; matrix_y < matrix_size; ++matrix_y){ s = scanblock[matrix_y]; matrix_x = -edge; while(x+matrix_x < 0){ CONVOLVE_ACC(*m, *s); ++matrix_x; ++m; } while(matrix_x <= edge){ CONVOLVE_ACC(*m, *s); ++matrix_x; ++m; ++s; } } - r = r < 0.0 ? 0.0 : r > 255.0 ? 255.0 : r+0.5; - g = g < 0.0 ? 0.0 : g > 255.0 ? 255.0 : g+0.5; - b = b < 0.0 ? 0.0 : b > 255.0 ? 255.0 : b+0.5; - *dest++ = qRgba((unsigned char)r, (unsigned char)g, - (unsigned char)b, qAlpha(*src++)); + r = r < 0.0f ? 0.0f : r > 255.0f ? 255.0f : r + 0.5f; + g = g < 0.0f ? 0.0f : g > 255.0f ? 255.0f : g + 0.5f; + b = b < 0.0f ? 0.0f : b > 255.0f ? 255.0f : b + 0.5f; + *dest++ = qRgba(static_cast (r), static_cast (g), + static_cast (b), qAlpha(*src++)); } // Okay, now process the middle part where the entire neighborhood // is on the image. for(; x+edge < w; ++x){ m = normalize_matrix; r = g = b = 0.0; for(matrix_y = 0; matrix_y < matrix_size; ++matrix_y){ s = scanblock[matrix_y] + (x-edge); for(matrix_x = -edge; matrix_x <= edge; ++matrix_x, ++m, ++s){ CONVOLVE_ACC(*m, *s); } } - r = r < 0.0 ? 0.0 : r > 255.0 ? 255.0 : r+0.5; - g = g < 0.0 ? 0.0 : g > 255.0 ? 255.0 : g+0.5; - b = b < 0.0 ? 0.0 : b > 255.0 ? 255.0 : b+0.5; - *dest++ = qRgba((unsigned char)r, (unsigned char)g, - (unsigned char)b, qAlpha(*src++)); + r = r < 0.0f ? 0.0f : r > 255.0f ? 255.0f : r + 0.5f; + g = g < 0.0f ? 0.0f : g > 255.0f ? 255.0f : g + 0.5f; + b = b < 0.0f ? 0.0f : b > 255.0f ? 255.0f : b + 0.5f; + *dest++ = qRgba(static_cast (r), static_cast (g), + static_cast (b), qAlpha(*src++)); } // Finally process the right part where the neighborhood extends off // the right edge of the image for(; x < w; ++x){ r = g = b = 0.0; m = normalize_matrix; for(matrix_y = 0; matrix_y < matrix_size; ++matrix_y){ s = scanblock[matrix_y]; s += x-edge; matrix_x = -edge; while(x+matrix_x < w){ CONVOLVE_ACC(*m, *s); ++matrix_x; ++m; ++s; } --s; while(matrix_x <= edge){ CONVOLVE_ACC(*m, *s); ++matrix_x; ++m; } } - r = r < 0.0 ? 0.0 : r > 255.0 ? 255.0 : r+0.5; - g = g < 0.0 ? 0.0 : g > 255.0 ? 255.0 : g+0.5; - b = b < 0.0 ? 0.0 : b > 255.0 ? 255.0 : b+0.5; - *dest++ = qRgba((unsigned char)r, (unsigned char)g, - (unsigned char)b, qAlpha(*src++)); + r = r < 0.0f ? 0.0f : r > 255.0f ? 255.0f : r + 0.5f; + g = g < 0.0f ? 0.0f : g > 255.0f ? 255.0f : g + 0.5f; + b = b < 0.0f ? 0.0f : b > 255.0f ? 255.0f : b + 0.5f; + *dest++ = qRgba(static_cast (r), static_cast (g), + static_cast (b), qAlpha(*src++)); } } } delete[] scanblock; delete[] normalize_matrix; return(buffer); } //-------------------------------------------------------------------------------- QImage Blitz::gaussianSharpen(QImage &img, float radius, float sigma) { - if(sigma == 0.0){ + if(sigma == 0.0f){ qWarning("Blitz::gaussianSharpen(): Zero sigma is invalid!"); return(img); } int matrix_size = defaultConvolveMatrixSize(radius, sigma, true); int len = matrix_size*matrix_size; float alpha, *matrix = new float[len]; - float sigma2 = sigma*sigma*2.0; - float sigmaPI2 = 2.0*M_PI*sigma*sigma; + float sigma2 = sigma*sigma*2.0f; + float sigmaPI2 = 2.0f*static_cast (M_PI)*sigma*sigma; int half = matrix_size/2; int x, y, i=0, j=half; float normalize=0.0; for(y=(-half); y <= half; ++y, --j){ for(x=(-half); x <= half; ++x, ++i){ - alpha = std::exp(-((float)x*x+y*y)/sigma2); + alpha = std::exp(-(static_cast (x*x+y*y))/sigma2); matrix[i] = alpha/sigmaPI2; normalize += matrix[i]; } } - matrix[i/2]=(-2.0)*normalize; + matrix[i/2]=(-2.0f)*normalize; QImage result(convolve(img, matrix_size, matrix)); delete[] matrix; return(result); } //-------------------------------------------------------------------------------- QImage Blitz::emboss(QImage &img, float radius, float sigma) { - if(sigma == 0.0){ + if(sigma == 0.0f){ qWarning("Blitz::emboss(): Zero sigma is invalid!"); return(img); } int matrix_size = defaultConvolveMatrixSize(radius, sigma, true); int len = matrix_size*matrix_size; float alpha, *matrix = new float[len]; - float sigma2 = sigma*sigma*2.0; - float sigmaPI2 = 2.0*M_PI*sigma*sigma; + float sigma2 = sigma*sigma*2.0f; + float sigmaPI2 = 2.0f*static_cast (M_PI)*sigma*sigma; int half = matrix_size/2; int x, y, i=0, j=half; for(y=(-half); y <= half; ++y, --j){ for(x=(-half); x <= half; ++x, ++i){ - alpha = std::exp(-((float)x*x+y*y)/sigma2); - matrix[i]=((x < 0) || (y < 0) ? -8.0 : 8.0)*alpha/sigmaPI2; + alpha = std::exp(-(static_cast (x*x+y*y))/sigma2); + matrix[i]=((x < 0) || (y < 0) ? -8.0f : 8.0f)*alpha/sigmaPI2; if(x == j) matrix[i]=0.0; } } QImage result(convolve(img, matrix_size, matrix)); delete[] matrix; equalize(result); return(result); } //-------------------------------------------------------------------------------- QImage& Blitz::flatten(QImage &img, const QColor &ca, const QColor &cb) { if(img.isNull()) return(img); if(img.depth() == 1) { img.setColor(0, ca.rgb()); img.setColor(1, cb.rgb()); return(img); } int r1 = ca.red(); int r2 = cb.red(); int g1 = ca.green(); int g2 = cb.green(); int b1 = ca.blue(); int b2 = cb.blue(); int min = 0, max = 255; QRgb *data, *end; QVector cTable; if(img.format() == QImage::Format_Indexed8){ cTable = img.colorTable(); - data = (unsigned int *)cTable.data(); + data = static_cast (cTable.data()); end = data + img.colorCount(); } else{ data = (unsigned int *)img.scanLine(0); end = data + (img.width()*img.height()); } // get minimum and maximum graylevel QRgb *ptr = data; int mean; if(img.format() != QImage::Format_ARGB32_Premultiplied){ while(ptr != end){ mean = (qRed(*ptr) + qGreen(*ptr) + qBlue(*ptr)) / 3; min = qMin(min, mean); max = qMax(max, mean); ++ptr; } } else{ QRgb pixel; while(ptr != end){ pixel = convertFromPremult(*ptr); mean = (qRed(pixel) + qGreen(pixel) + qBlue(pixel)) / 3; min = qMin(min, mean); max = qMax(max, mean); ++ptr; } } // conversion factors - float sr = ((float) r2 - r1) / (max - min); - float sg = ((float) g2 - g1) / (max - min); - float sb = ((float) b2 - b1) / (max - min); + float sr = (static_cast (r2 - r1) / (max - min)); + float sg = (static_cast (g2 - g1) / (max - min)); + float sb = (static_cast (b2 - b1) / (max - min)); if(img.format() != QImage::Format_ARGB32_Premultiplied){ while(data != end){ mean = (qRed(*data) + qGreen(*data) + qBlue(*data)) / 3; - *data = qRgba((unsigned char)(sr * (mean - min) + r1 + 0.5), - (unsigned char)(sg * (mean - min) + g1 + 0.5), - (unsigned char)(sb * (mean - min) + b1 + 0.5), + *data = qRgba(static_cast (sr * (mean - min) + r1 + 0.5f), + static_cast (sg * (mean - min) + g1 + 0.5f), + static_cast (sb * (mean - min) + b1 + 0.5f), qAlpha(*data)); ++data; } } else{ QRgb pixel; while(data != end){ pixel = convertFromPremult(*data); mean = (qRed(pixel) + qGreen(pixel) + qBlue(pixel)) / 3; *data = - convertToPremult(qRgba((unsigned char)(sr * (mean - min) + r1 + 0.5), - (unsigned char)(sg * (mean - min) + g1 + 0.5), - (unsigned char)(sb * (mean - min) + b1 + 0.5), + convertToPremult(qRgba(static_cast (sr * (mean - min) + r1 + 0.5f), + static_cast (sg * (mean - min) + g1 + 0.5f), + static_cast (sb * (mean - min) + b1 + 0.5f), qAlpha(*data))); ++data; } } if(img.format() == QImage::Format_Indexed8) img.setColorTable(cTable); return(img); } //-------------------------------------------------------------------------------- diff --git a/imagelib/effects/kpEffectBalance.cpp b/imagelib/effects/kpEffectBalance.cpp index e34eaec3..0ff0e319 100644 --- a/imagelib/effects/kpEffectBalance.cpp +++ b/imagelib/effects/kpEffectBalance.cpp @@ -1,213 +1,213 @@ /* Copyright (c) 2003-2007 Clarence Dang 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_EFFECT_BALANCE 0 #include "kpEffectBalance.h" #include #include #include "kpLogCategories.h" #include "pixmapfx/kpPixmapFX.h" #if DEBUG_KP_EFFECT_BALANCE #include #endif static inline int between0And255 (int val) { if (val < 0) return 0; else if (val > 255) return 255; else return val; } static inline int brightness (int base, int strength) { return between0And255 (base + strength * 255 / 50); } static inline int contrast (int base, int strength) { return between0And255 ((base - 127) * (strength + 50) / 50 + 127); } static inline int gamma (int base, int strength) { return between0And255 (qRound (255.0 * pow (base / 255.0, 1.0 / pow (10., strength / 50.0)))); } static inline int brightnessContrastGamma (int base, int newBrightness, int newContrast, int newGamma) { return gamma (contrast (brightness (base, newBrightness), newContrast), newGamma); } static inline QRgb brightnessContrastGammaForRGB (QRgb rgb, int channels, int brightness, int contrast, int gamma) { int red = qRed (rgb); int green = qGreen (rgb); int blue = qBlue (rgb); if (channels & kpEffectBalance::Red) red = brightnessContrastGamma (red, brightness, contrast, gamma); if (channels & kpEffectBalance::Green) green = brightnessContrastGamma (green, brightness, contrast, gamma); if (channels & kpEffectBalance::Blue) blue = brightnessContrastGamma (blue, brightness, contrast, gamma); return qRgba (red, green, blue, qAlpha (rgb)); } // public static kpImage kpEffectBalance::applyEffect (const kpImage &image, int channels, int brightness, int contrast, int gamma) { #if DEBUG_KP_EFFECT_BALANCE qCDebug(kpLogImagelib) << "kpEffectBalance::applyEffect(" << "channels=" << channels << ",brightness=" << brightness << ",contrast=" << contrast << ",gamma=" << gamma << ")" << endl; QTime timer; timer.start (); #endif QImage qimage = image; #if DEBUG_KP_EFFECT_BALANCE qCDebug(kpLogImagelib) << "\tconvertToImage=" << timer.restart (); #endif quint8 transformRed [256], transformGreen [256], transformBlue [256]; for (int i = 0; i < 256; i++) { - quint8 applied = (quint8) brightnessContrastGamma (i, brightness, contrast, gamma); + quint8 applied = static_cast (brightnessContrastGamma (i, brightness, contrast, gamma)); if (channels & kpEffectBalance::Red) transformRed [i] = applied; else - transformRed [i] = i; + transformRed [i] = static_cast (i); if (channels & kpEffectBalance::Green) transformGreen [i] = applied; else - transformGreen [i] = i; + transformGreen [i] = static_cast (i); if (channels & kpEffectBalance::Blue) transformBlue [i] = applied; else - transformBlue [i] = i; + transformBlue [i] = static_cast (i); } #if DEBUG_KP_EFFECT_BALANCE qCDebug(kpLogImagelib) << "\tbuild lookup=" << timer.restart (); #endif if (qimage.depth () > 8) { for (int y = 0; y < qimage.height (); y++) { for (int x = 0; x < qimage.width (); x++) { const QRgb rgb = qimage.pixel (x, y); - const quint8 red = (quint8) qRed (rgb); - const quint8 green = (quint8) qGreen (rgb); - const quint8 blue = (quint8) qBlue (rgb); - const quint8 alpha = (quint8) qAlpha (rgb); + const quint8 red = static_cast (qRed (rgb)); + const quint8 green = static_cast (qGreen (rgb)); + const quint8 blue = static_cast (qBlue (rgb)); + const quint8 alpha = static_cast (qAlpha (rgb)); qimage.setPixel (x, y, qRgba (transformRed [red], transformGreen [green], transformBlue [blue], alpha)); #if 0 qimage.setPixel (x, y, brightnessContrastGammaForRGB (qimage.pixel (x, y), channels, brightness, contrast, gamma)); #endif } } } else { for (int i = 0; i < qimage.colorCount (); i++) { const QRgb rgb = qimage.color (i); - const quint8 red = (quint8) qRed (rgb); - const quint8 green = (quint8) qGreen (rgb); - const quint8 blue = (quint8) qBlue (rgb); - const quint8 alpha = (quint8) qAlpha (rgb); + const quint8 red = static_cast (qRed (rgb)); + const quint8 green = static_cast (qGreen (rgb)); + const quint8 blue = static_cast (qBlue (rgb)); + const quint8 alpha = static_cast (qAlpha (rgb)); qimage.setColor (i, qRgba (transformRed [red], transformGreen [green], transformBlue [blue], alpha)); #if 0 qimage.setColor (i, brightnessContrastGammaForRGB (qimage.color (i), channels, brightness, contrast, gamma)); #endif } } return qimage; } diff --git a/imagelib/effects/kpEffectBlurSharpen.cpp b/imagelib/effects/kpEffectBlurSharpen.cpp index 2e06e0e1..f3bf57a7 100644 --- a/imagelib/effects/kpEffectBlurSharpen.cpp +++ b/imagelib/effects/kpEffectBlurSharpen.cpp @@ -1,199 +1,200 @@ /* Copyright (c) 2003-2007 Clarence Dang 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_EFFECT_BLUR_SHARPEN 0 #include "kpEffectBlurSharpen.h" #include "blitz.h" #include "kpLogCategories.h" #include "pixmapfx/kpPixmapFX.h" #if DEBUG_KP_EFFECT_BLUR_SHARPEN #include #endif //--------------------------------------------------------------------- // // For info on "radius" and "sigma", see http://redskiesatnight.com/Articles/IMsharpen/ // // Daniel Duley says: // // // I don't think I can describe it any better than the article: The radius // controls many how pixels are taken into account when determining the value // of the center pixel. This controls the quality [and speed] of the result but not // necessarily the strength. The sigma controls how those neighboring pixels // are weighted depending on how far the are from the center one. This is // closer to strength, but not exactly >:) // // static QImage BlurQImage(const QImage &qimage, int strength) { if (strength == 0) return qimage; // The numbers that follow were picked by experimentation to try to get // an effect linearly proportional to and at the same time, // be fast enough. // // I still have no idea what "radius" means. const double RadiusMin = 1; const double RadiusMax = 10; const double radius = RadiusMin + (strength - 1) * (RadiusMax - RadiusMin) / (kpEffectBlurSharpen::MaxStrength - 1); #if DEBUG_KP_EFFECT_BLUR_SHARPEN qCDebug(kpLogImagelib) << "kpEffectBlurSharpen.cpp:BlurQImage(strength=" << strength << ")" << " radius=" << radius << endl; #endif QImage img(qimage); return Blitz::blur(img, qRound(radius)); } //--------------------------------------------------------------------- static QImage SharpenQImage (const QImage &qimage_, int strength) { QImage qimage = qimage_; if (strength == 0) return qimage; // The numbers that follow were picked by experimentation to try to get // an effect linearly proportional to and at the same time, // be fast enough. // // I still have no idea what "radius" and "sigma" mean. const double RadiusMin = .1; const double RadiusMax = 2.5; const double radius = RadiusMin + (strength - 1) * (RadiusMax - RadiusMin) / (kpEffectBlurSharpen::MaxStrength - 1); const double SigmaMin = .5; const double SigmaMax = 3.0; const double sigma = SigmaMin + (strength - 1) * (SigmaMax - SigmaMin) / (kpEffectBlurSharpen::MaxStrength - 1); const double RepeatMin = 1; const double RepeatMax = 2; const double repeat = qRound (RepeatMin + (strength - 1) * (RepeatMax - RepeatMin) / (kpEffectBlurSharpen::MaxStrength - 1)); // I guess these values are more proper as they use an auto-calculated // radius but they cause sharpen() to be too slow. #if 0 const double radius = 0/*auto-calculate*/; const double SigmaMin = .6; const double SigmaMax = 1.0; const double sigma = SigmaMin + (strength - 1) * (SigmaMax - SigmaMin) / (kpEffectBlurSharpen::MaxStrength - 1); const double RepeatMin = 1; const double RepeatMax = 3; const double repeat = qRound (RepeatMin + (strength - 1) * (RepeatMax - RepeatMin) / (kpEffectBlurSharpen::MaxStrength - 1)); #endif #if DEBUG_KP_EFFECT_BLUR_SHARPEN qCDebug(kpLogImagelib) << "kpEffectBlurSharpen.cpp:SharpenQImage(strength=" << strength << ")" << " radius=" << radius << " sigma=" << sigma << " repeat=" << repeat << endl; #endif for (int i = 0; i < repeat; i++) { #if DEBUG_KP_EFFECT_BLUR_SHARPEN QTime timer; timer.start (); #endif - qimage = Blitz::gaussianSharpen (qimage, radius, sigma); + qimage = Blitz::gaussianSharpen (qimage, static_cast (radius), + static_cast (sigma)); #if DEBUG_KP_EFFECT_BLUR_SHARPEN qCDebug(kpLogImagelib) << "\titeration #" + QString::number (i) << ": " + QString::number (timer.elapsed ()) << "ms" << endl; #endif } return qimage; } //--------------------------------------------------------------------- // public static kpImage kpEffectBlurSharpen::applyEffect (const kpImage &image, Type type, int strength) { #if DEBUG_KP_EFFECT_BLUR_SHARPEN qCDebug(kpLogImagelib) << "kpEffectBlurSharpen::applyEffect(image.rect=" << image.rect () << ",type=" << int (type) << ",strength=" << strength << ")" << endl; #endif Q_ASSERT (strength >= MinStrength && strength <= MaxStrength); if (type == Blur) return ::BlurQImage (image, strength); else if (type == Sharpen) return ::SharpenQImage (image, strength); else if (type == MakeConfidential) { QImage img(image); return Blitz::blur(img, qMin(20, img.width() / 2)); } else return kpImage(); } //--------------------------------------------------------------------- diff --git a/imagelib/effects/kpEffectHSV.cpp b/imagelib/effects/kpEffectHSV.cpp index 8829f1c5..aaafe2bf 100644 --- a/imagelib/effects/kpEffectHSV.cpp +++ b/imagelib/effects/kpEffectHSV.cpp @@ -1,173 +1,190 @@ /* Copyright (c) 2007 Mike Gashler All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ // TODO: Clarence's code review #include "kpEffectHSV.h" #include #include #include #include "kpLogCategories.h" #include "pixmapfx/kpPixmapFX.h" static void ColorToHSV(unsigned int c, float* pHue, float* pSaturation, float* pValue) { int r = qRed(c); int g = qGreen(c); int b = qBlue(c); int min; if(b >= g && b >= r) { // Blue min = qMin(r, g); if(b != min) { - *pHue = (float)(r - g) / ((b - min) * 6) + (float)2 / 3; - *pSaturation = (float)1 - (float)min / (float)b; + *pHue = static_cast (r - g) / ((b - min) * 6) + static_cast (2) / 3; + *pSaturation = 1.0f - static_cast (min) / static_cast (b); } else { *pHue = 0; *pSaturation = 0; } - *pValue = (float)b / 255; + *pValue = static_cast (b) / 255; } else if(g >= r) { // Green min = qMin(b, r); if(g != min) { - *pHue = (float)(b - r) / ((g - min) * 6) + (float)1 / 3; - *pSaturation = (float)1 - (float)min / (float)g; + *pHue = static_cast (b - r) / ((g - min) * 6) + static_cast (1) / 3; + *pSaturation = 1.0f - static_cast (min) / static_cast (g); } else { *pHue = 0; *pSaturation = 0; } - *pValue = (float)g / 255; + *pValue = static_cast (g) / 255; } else { // Red min = qMin(g, b); if(r != min) { - *pHue = (float)(g - b) / ((r - min) * 6); + *pHue = static_cast (g - b) / ((r - min) * 6); if(*pHue < 0) - (*pHue) += (float)1; - *pSaturation = (float)1 - (float)min / (float)r; + (*pHue) += 1.0f; + *pSaturation = 1.0f - static_cast (min) / static_cast (r); } else { *pHue = 0; *pSaturation = 0; } - *pValue = (float)r / 255; + *pValue = static_cast (r) / 255; } } static unsigned int HSVToColor(int alpha, float hue, float saturation, float value) { //Q_ASSERT (hue >= 0 && hue <= 1 && saturation >= 0 && saturation <= 1 && value >= 0 && value <= 1); - hue *= (float)5.999999; - int h = (int)hue; + hue *= 5.999999f; + int h = static_cast (hue); float f = hue - h; - float p = value * ((float)1 - saturation); - float q = value * ((float)1 - ((h & 1) == 0 ? (float)1 - f : f) * saturation); + float p = value * (1.0f - saturation); + float q = value * (1.0f - ((h & 1) == 0 ? 1.0f - f : f) * saturation); switch(h) { - case 0: return qRgba((int)(value * 255.999999), (int)(q * 255.999999), (int)(p * 255.999999), alpha); - case 1: return qRgba((int)(q * 255.999999), (int)(value * 255.999999), (int)(p * 255.999999), alpha); - case 2: return qRgba((int)(p * 255.999999), (int)(value * 255.999999), (int)(q * 255.999999), alpha); - case 3: return qRgba((int)(p * 255.999999), (int)(q * 255.999999), (int)(value * 255.999999), alpha); - case 4: return qRgba((int)(q * 255.999999), (int)(p * 255.999999), (int)(value * 255.999999), alpha); - case 5: return qRgba((int)(value * 255.999999), (int)(p * 255.999999), (int)(q * 255.999999), alpha); + case 0: return qRgba(static_cast (value * 255.999999f), + static_cast (q * 255.999999f), + static_cast (p * 255.999999f), alpha); + + case 1: return qRgba(static_cast (q * 255.999999f), + static_cast (value * 255.999999f), + static_cast (p * 255.999999f), alpha); + + case 2: return qRgba(static_cast (p * 255.999999f), + static_cast (value * 255.999999f), + static_cast (q * 255.999999f), alpha); + + case 3: return qRgba(static_cast (p * 255.999999f), + static_cast (q * 255.999999f), + static_cast (value * 255.999999f), alpha); + + case 4: return qRgba(static_cast (q * 255.999999f), + static_cast (p * 255.999999f), + static_cast (value * 255.999999f), alpha); + + case 5: return qRgba(static_cast (value * 255.999999f), + static_cast (p * 255.999999f), + static_cast (q * 255.999999f), alpha); } return qRgba(0, 0, 0, alpha); } static QRgb AdjustHSVInternal (QRgb pix, double hueDiv360, double saturation, double value) { float h, s, v; ::ColorToHSV(pix, &h, &s, &v); const int alpha = qAlpha(pix); - h += (float)hueDiv360; + h += static_cast (hueDiv360); h -= floor(h); - s = qMax((float)0, qMin((float)1, s + (float)saturation)); + s = qMax(0.0f, qMin(1.0f, s + static_cast (saturation))); - v = qMax((float)0, qMin((float)1, v + (float)value)); + v = qMax(0.0f, qMin(1.0f, v + static_cast (value))); return ::HSVToColor(alpha, h, s, v); } static void AdjustHSV (QImage* pImage, double hue, double saturation, double value) { hue /= 360; if (pImage->depth () > 8) { for (int y = 0; y < pImage->height (); y++) { for (int x = 0; x < pImage->width (); x++) { QRgb pix = pImage->pixel (x, y); pix = ::AdjustHSVInternal (pix, hue, saturation, value); pImage->setPixel (x, y, pix); } } } else { for (int i = 0; i < pImage->colorCount (); i++) { QRgb pix = pImage->color (i); pix = ::AdjustHSVInternal (pix, hue, saturation, value); pImage->setColor (i, pix); } } } // public static kpImage kpEffectHSV::applyEffect (const kpImage &image, double hue, double saturation, double value) { QImage qimage(image); ::AdjustHSV (&qimage, hue, saturation, value); return qimage; } diff --git a/imagelib/effects/kpEffectToneEnhance.cpp b/imagelib/effects/kpEffectToneEnhance.cpp index 201afd94..4c7b2317 100644 --- a/imagelib/effects/kpEffectToneEnhance.cpp +++ b/imagelib/effects/kpEffectToneEnhance.cpp @@ -1,283 +1,291 @@ /* Copyright (c) 2003-2007 Clarence Dang Copyright (c) 2006 Mike Gashler All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ // TODO: Clarence's code review #include "kpEffectToneEnhance.h" #include #include "kpLogCategories.h" #include "pixmapfx/kpPixmapFX.h" #define RED_WEIGHT 77 #define GREEN_WEIGHT 150 #define BLUE_WEIGHT 29 #define MAX_TONE_VALUE ((RED_WEIGHT + GREEN_WEIGHT + BLUE_WEIGHT) * 255) #define TONE_DROP_BITS 5 #define TONE_MAP_SIZE ((MAX_TONE_VALUE >> TONE_DROP_BITS) + 1) #define MAX_GRANULARITY 25 #define MIN_IMAGE_DIM 3 //--------------------------------------------------------------------- inline unsigned int ComputeTone(unsigned int color) { - return RED_WEIGHT * qRed(color) + GREEN_WEIGHT * qGreen(color) + BLUE_WEIGHT * qBlue(color); + return RED_WEIGHT * static_cast (qRed(color)) + + GREEN_WEIGHT * static_cast (qGreen(color)) + + BLUE_WEIGHT * static_cast (qBlue(color)); } //--------------------------------------------------------------------- inline unsigned int AdjustTone(unsigned int color, unsigned int oldTone, unsigned int newTone, double amount) { return qRgba( - qMax(0, qMin(255, (int) (amount * qRed(color) * newTone / oldTone + (1.0 - amount) * qRed(color)))), - qMax(0, qMin(255, (int) (amount * qGreen(color) * newTone / oldTone + (1.0 - amount) * qGreen(color)))), - qMax(0, qMin(255, (int) (amount * qBlue(color) * newTone / oldTone + (1.0 - amount) * qBlue(color)))), + qMax(0, qMin(255, static_cast (amount * qRed(color) * newTone / oldTone + (1.0 - amount) * qRed(color)))), + qMax(0, qMin(255, static_cast (amount * qGreen(color) * newTone / oldTone + (1.0 - amount) * qGreen(color)))), + qMax(0, qMin(255, static_cast (amount * qBlue(color) * newTone / oldTone + (1.0 - amount) * qBlue(color)))), qAlpha(color) ); } //--------------------------------------------------------------------- class kpEffectToneEnhanceApplier { public: kpEffectToneEnhanceApplier (); ~kpEffectToneEnhanceApplier (); void BalanceImageTone(QImage* pImage, double granularity, double amount); protected: int m_nToneMapGranularity, m_areaWid, m_areaHgt; unsigned int m_nComputedWid, m_nComputedHgt; // LOTODO: Use less error-prone QTL containers instead. unsigned int* m_pHistogram; unsigned int** m_pToneMaps; void DeleteToneMaps(); unsigned int* MakeToneMap(QImage* pImage, int x, int y, int nGranularity); void ComputeToneMaps(QImage* pImage, int nGranularity); unsigned int InterpolateNewTone(QImage* pImage, unsigned int oldTone, int x, int y, int nGranularity); }; //--------------------------------------------------------------------- kpEffectToneEnhanceApplier::kpEffectToneEnhanceApplier () { m_nToneMapGranularity = 0; m_areaWid = 0; m_areaHgt = 0; m_nComputedWid = 0; m_nComputedHgt = 0; m_pHistogram = new unsigned int[TONE_MAP_SIZE]; m_pToneMaps = nullptr; } //--------------------------------------------------------------------- kpEffectToneEnhanceApplier::~kpEffectToneEnhanceApplier () { DeleteToneMaps(); delete[] m_pHistogram; } //--------------------------------------------------------------------- // protected void kpEffectToneEnhanceApplier::DeleteToneMaps() { int nToneMaps = m_nToneMapGranularity * m_nToneMapGranularity; for(int i = 0; i < nToneMaps; i++) delete[] m_pToneMaps[i]; delete[] m_pToneMaps; m_pToneMaps = nullptr; m_nToneMapGranularity = 0; } //--------------------------------------------------------------------- // protected unsigned int* kpEffectToneEnhanceApplier::MakeToneMap(QImage* pImage, int u, int v, int nGranularity) { // Compute the region to make the tone map for int xx, yy; if(nGranularity > 1) { xx = u * (pImage->width() - 1) / (nGranularity - 1) - m_areaWid / 2; if(xx < 0) xx = 0; else if(xx + m_areaWid > pImage->width()) xx = pImage->width() - m_areaWid; yy = v * (pImage->width() - 1) / (nGranularity - 1) - m_areaHgt / 2; if(yy < 0) yy = 0; else if(yy + m_areaHgt > pImage->height()) yy = pImage->height() - m_areaHgt; } else { xx = 0; yy = 0; } // Make a tone histogram for the region memset(m_pHistogram, '\0', sizeof(unsigned int) * TONE_MAP_SIZE); int x, y; unsigned int tone; for(y = 0; y < m_areaHgt; y++) { for(x = 0; x < m_areaWid; x++) { tone = ComputeTone(pImage->pixel(xx + x, yy + y)); m_pHistogram[tone >> TONE_DROP_BITS]++; } } // Forward sum the tone histogram int i; for(i = 1; i < TONE_MAP_SIZE; i++) m_pHistogram[i] += m_pHistogram[i - 1]; // Compute the forward contribution to the tone map unsigned int total = m_pHistogram[i - 1]; unsigned int* pToneMap = new unsigned int[TONE_MAP_SIZE]; for(i = 0; i < TONE_MAP_SIZE; i++) - pToneMap[i] = (uint)((unsigned long long int)m_pHistogram[i] * MAX_TONE_VALUE / total); + pToneMap[i] = static_cast (static_cast (m_pHistogram[i] * MAX_TONE_VALUE / total)); /* // Undo the forward sum and reverse sum the tone histogram m_pHistogram[TONE_MAP_SIZE - 1] -= m_pHistogram[TONE_MAP_SIZE - 2]; for(i = TONE_MAP_SIZE - 2; i > 0; i--) { m_pHistogram[i] -= m_pHistogram[i - 1]; m_pHistogram[i] += m_pHistogram[i + 1]; } m_pHistogram[0] += m_pHistogram[1]; */ return pToneMap; } //--------------------------------------------------------------------- // protected void kpEffectToneEnhanceApplier::ComputeToneMaps(QImage* pImage, int nGranularity) { - if(nGranularity == m_nToneMapGranularity && pImage->width() == (int) m_nComputedWid && pImage->height() == (int) m_nComputedHgt) + if(nGranularity == m_nToneMapGranularity && pImage->width() == + static_cast (m_nComputedWid) && pImage->height() == static_cast (m_nComputedHgt)) { return; // We've already computed tone maps for this granularity } DeleteToneMaps(); m_pToneMaps = new unsigned int*[nGranularity * nGranularity]; m_nToneMapGranularity = nGranularity; - m_nComputedWid = pImage->width(); - m_nComputedHgt = pImage->height(); + m_nComputedWid = static_cast (pImage->width()); + m_nComputedHgt = static_cast (pImage->height()); int u, v; for(v = 0; v < nGranularity; v++) { for(u = 0; u < nGranularity; u++) m_pToneMaps[nGranularity * v + u] = MakeToneMap(pImage, u, v, nGranularity); } } //--------------------------------------------------------------------- // protected unsigned int kpEffectToneEnhanceApplier::InterpolateNewTone(QImage* pImage, unsigned int oldTone, int x, int y, int nGranularity) { oldTone = (oldTone >> TONE_DROP_BITS); if(m_nToneMapGranularity <= 1) return m_pToneMaps[0][oldTone]; int u = x * (nGranularity - 1) / pImage->width(); int v = y * (nGranularity - 1) / pImage->height(); unsigned int x1y1 = m_pToneMaps[m_nToneMapGranularity * v + u][oldTone]; unsigned int x2y1 = m_pToneMaps[m_nToneMapGranularity * v + u + 1][oldTone]; unsigned int x1y2 = m_pToneMaps[m_nToneMapGranularity * (v + 1) + u][oldTone]; unsigned int x2y2 = m_pToneMaps[m_nToneMapGranularity * (v + 1) + u + 1][oldTone]; int hFac = x - (u * (pImage->width() - 1) / (nGranularity - 1)); if(hFac > m_areaWid) hFac = m_areaWid; - unsigned int y1 = (x1y1 * (m_areaWid - hFac) + x2y1 * hFac) / m_areaWid; - unsigned int y2 = (x1y2 * (m_areaWid - hFac) + x2y2 * hFac) / m_areaWid; + unsigned int y1 = (x1y1 * (static_cast (m_areaWid) - static_cast (hFac)) + + x2y1 * static_cast (hFac)) / static_cast (m_areaWid); + + unsigned int y2 = (x1y2 * (static_cast (m_areaWid) - static_cast (hFac)) + + x2y2 * static_cast (hFac)) / static_cast (m_areaWid); + int vFac = y - (v * (pImage->height() - 1) / (nGranularity - 1)); if(vFac > m_areaHgt) vFac = m_areaHgt; - return (y1 * (m_areaHgt - vFac) + y2 * vFac) / m_areaHgt; + return (y1 * (static_cast (m_areaHgt) - static_cast (vFac)) + + y2 * static_cast (vFac)) / static_cast (m_areaHgt); } //--------------------------------------------------------------------- // public void kpEffectToneEnhanceApplier::BalanceImageTone(QImage* pImage, double granularity, double amount) { if(pImage->width() < MIN_IMAGE_DIM || pImage->height() < MIN_IMAGE_DIM) return; // the image is not big enough to perform this operation - int nGranularity = (int)(granularity * (MAX_GRANULARITY - 2)) + 1; + int nGranularity = static_cast (granularity * (MAX_GRANULARITY - 2)) + 1; m_areaWid = pImage->width() / nGranularity; if(m_areaWid < MIN_IMAGE_DIM) m_areaWid = MIN_IMAGE_DIM; m_areaHgt = pImage->height() / nGranularity; if(m_areaHgt < MIN_IMAGE_DIM) m_areaHgt = MIN_IMAGE_DIM; ComputeToneMaps(pImage, nGranularity); int x, y; unsigned int oldTone, newTone, col; for(y = 0; y < pImage->height(); y++) { for(x = 0; x < pImage->width(); x++) { col = pImage->pixel(x, y); oldTone = ComputeTone(col); newTone = InterpolateNewTone(pImage, oldTone, x, y, nGranularity); pImage->setPixel(x, y, AdjustTone(col, oldTone, newTone, amount)); } } } //--------------------------------------------------------------------- // public static kpImage kpEffectToneEnhance::applyEffect (const kpImage &image, double granularity, double amount) { - if (amount == 0) + if (amount == 0.0) return image; QImage qimage(image); // OPT: Cache the calculated values? kpEffectToneEnhanceApplier applier; applier.BalanceImageTone (&qimage, granularity, amount); return qimage; } //--------------------------------------------------------------------- diff --git a/imagelib/kpColor.cpp b/imagelib/kpColor.cpp index ff022d86..39070ae2 100644 --- a/imagelib/kpColor.cpp +++ b/imagelib/kpColor.cpp @@ -1,310 +1,310 @@ /* Copyright (c) 2003-2007 Clarence Dang 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_COLOR 0 #include "kpColor.h" #include #include "kpLogCategories.h" //--------------------------------------------------------------------- kpColor::kpColor() : m_rgbaIsValid(false), m_rgba(0), m_colorCacheIsValid(false) { } //--------------------------------------------------------------------- kpColor::kpColor (int red, int green, int blue, bool isTransparent) : m_rgba(0), m_colorCacheIsValid(false) { #if DEBUG_KP_COLOR qCDebug(kpLogImagelib) << "kpColor::(r=" << red << ",g=" << green << ",b=" << blue << ",isTrans=" << isTransparent << ")" << endl; #endif if (red < 0 || red > 255 || green < 0 || green > 255 || blue < 0 || blue > 255) { qCCritical(kpLogImagelib) << "kpColor::(r=" << red << ",g=" << green << ",b=" << blue << ",t=" << isTransparent << ") passed out of range values" << endl; m_rgbaIsValid = false; return; } m_rgba = qRgba (red, green, blue, isTransparent ? 0 : 255/*opaque*/); m_rgbaIsValid = true; } //--------------------------------------------------------------------- kpColor::kpColor (const QRgb &rgba) : m_colorCacheIsValid (false) { #if DEBUG_KP_COLOR qCDebug(kpLogImagelib) << "kpColor::(rgba=" << (int *) rgba << ")"; #endif m_rgba = rgba; m_rgbaIsValid = true; } //--------------------------------------------------------------------- kpColor::kpColor (const kpColor &rhs) : m_rgbaIsValid (rhs.m_rgbaIsValid), m_rgba (rhs.m_rgba), m_colorCacheIsValid (rhs.m_colorCacheIsValid), m_colorCache (rhs.m_colorCache) { #if DEBUG_KP_COLOR qCDebug(kpLogImagelib) << "kpColor::()"; #endif } //--------------------------------------------------------------------- // friend QDataStream &operator<< (QDataStream &stream, const kpColor &color) { stream << int (color.m_rgbaIsValid) << int (color.m_rgba); return stream; } //--------------------------------------------------------------------- // friend QDataStream &operator>> (QDataStream &stream, kpColor &color) { int a, b; stream >> a >> b; color.m_rgbaIsValid = a; - color.m_rgba = b; + color.m_rgba = static_cast (b); color.m_colorCacheIsValid = false; return stream; } //--------------------------------------------------------------------- kpColor &kpColor::operator= (const kpColor &rhs) { // (as soon as you add a ptr, you won't be complaining to me that this // method was unnecessary :)) if (this == &rhs) return *this; m_rgbaIsValid = rhs.m_rgbaIsValid; m_rgba = rhs.m_rgba; m_colorCacheIsValid = rhs.m_colorCacheIsValid; m_colorCache = rhs.m_colorCache; return *this; } bool kpColor::operator== (const kpColor &rhs) const { return isSimilarTo (rhs, kpColor::Exact); } bool kpColor::operator!= (const kpColor &rhs) const { return !(*this == rhs); } //--------------------------------------------------------------------- template inline dtype square (dtype val) { return val * val; } //--------------------------------------------------------------------- // public static int kpColor::processSimilarity (double colorSimilarity) { // sqrt (dr ^ 2 + dg ^ 2 + db ^ 2) <= colorSimilarity * sqrt (255 ^ 2 * 3) // dr ^ 2 + dg ^ 2 + db ^ 2 <= (colorSimilarity ^ 2) * (255 ^ 2 * 3) return int (square (colorSimilarity) * (square (255) * 3)); } //--------------------------------------------------------------------- bool kpColor::isSimilarTo (const kpColor &rhs, int processedSimilarity) const { // Are we the same? if (this == &rhs) return true; // Do we dither in terms of validity? if (isValid () != rhs.isValid ()) return false; // Are both of us invalid? if (!isValid ()) return true; // --- both are now valid --- if (m_rgba == rhs.m_rgba) return true; if (processedSimilarity == kpColor::Exact) return false; else { return (square (qRed (m_rgba) - qRed (rhs.m_rgba)) + square (qGreen (m_rgba) - qGreen (rhs.m_rgba)) + square (qBlue (m_rgba) - qBlue (rhs.m_rgba)) <= processedSimilarity); } } //--------------------------------------------------------------------- // public bool kpColor::isValid () const { return m_rgbaIsValid; } //--------------------------------------------------------------------- // public int kpColor::red () const { if (!m_rgbaIsValid) { qCCritical(kpLogImagelib) << "kpColor::red() called with invalid kpColor" << endl; return 0; } return qRed (m_rgba); } //--------------------------------------------------------------------- // public int kpColor::green () const { if (!m_rgbaIsValid) { qCCritical(kpLogImagelib) << "kpColor::green() called with invalid kpColor" << endl; return 0; } return qGreen (m_rgba); } //--------------------------------------------------------------------- // public int kpColor::blue () const { if (!m_rgbaIsValid) { qCCritical(kpLogImagelib) << "kpColor::blue() called with invalid kpColor" << endl; return 0; } return qBlue (m_rgba); } //--------------------------------------------------------------------- // public int kpColor::alpha () const { if (!m_rgbaIsValid) { qCCritical(kpLogImagelib) << "kpColor::alpha() called with invalid kpColor" << endl; return 0; } return qAlpha (m_rgba); } //--------------------------------------------------------------------- // public bool kpColor::isTransparent () const { return (alpha () == 0); } //--------------------------------------------------------------------- // public QRgb kpColor::toQRgb () const { if (!m_rgbaIsValid) { qCCritical(kpLogImagelib) << "kpColor::toQRgb() called with invalid kpColor" << endl; return 0; } return m_rgba; } //--------------------------------------------------------------------- // public QColor kpColor::toQColor () const { if (!m_rgbaIsValid) { qCCritical(kpLogImagelib) << "kpColor::toQColor() called with invalid kpColor" << endl; return Qt::black; } if (m_colorCacheIsValid) return m_colorCache; m_colorCache = QColor(qRed(m_rgba), qGreen(m_rgba), qBlue(m_rgba), qAlpha(m_rgba)); m_colorCacheIsValid = true; return m_colorCache; } //--------------------------------------------------------------------- diff --git a/imagelib/kpFloodFill.cpp b/imagelib/kpFloodFill.cpp index c0e04578..e3f28842 100644 --- a/imagelib/kpFloodFill.cpp +++ b/imagelib/kpFloodFill.cpp @@ -1,415 +1,415 @@ /* Copyright (c) 2003-2007 Clarence Dang 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_FLOOD_FILL 0 #include "kpFloodFill.h" #include #include #include #include #include #include "kpLogCategories.h" #include "kpColor.h" #include "kpImage.h" #include "kpDefs.h" #include "pixmapfx/kpPixmapFX.h" #include "tools/kpTool.h" //--------------------------------------------------------------------- class kpFillLine { public: kpFillLine (int y = -1, int x1 = -1, int x2 = -1) : m_y (y), m_x1 (x1), m_x2 (x2) { } static kpCommandSize::SizeType size () { return sizeof (kpFillLine); } int m_y, m_x1, m_x2; }; //--------------------------------------------------------------------- static kpCommandSize::SizeType FillLinesListSize (const QLinkedList &fillLines) { return (fillLines.size () * kpFillLine::size ()); } //--------------------------------------------------------------------- struct kpFloodFillPrivate { // // Copy of whatever was passed to the constructor. // kpImage *imagePtr; int x, y; kpColor color; int processedColorSimilarity; // // Set by Step 1. // kpColor colorToChange; // // Set by Step 2. // QLinkedList fillLines; QList < QLinkedList > fillLinesCache; QRect boundingRect; bool prepared; }; //--------------------------------------------------------------------- kpFloodFill::kpFloodFill (kpImage *image, int x, int y, const kpColor &color, int processedColorSimilarity) : d (new kpFloodFillPrivate ()) { d->imagePtr = image; d->x = x; d->y = y; d->color = color; d->processedColorSimilarity = processedColorSimilarity; d->prepared = false; } //--------------------------------------------------------------------- kpFloodFill::~kpFloodFill () { delete d; } //--------------------------------------------------------------------- // public kpColor kpFloodFill::color () const { return d->color; } //--------------------------------------------------------------------- // public int kpFloodFill::processedColorSimilarity () const { return d->processedColorSimilarity; } //--------------------------------------------------------------------- // public kpCommandSize::SizeType kpFloodFill::size () const { kpCommandSize::SizeType fillLinesCacheSize = 0; foreach (const QLinkedList &linesList, d->fillLinesCache) { fillLinesCacheSize += ::FillLinesListSize (linesList); } return ::FillLinesListSize(d->fillLines) + kpCommandSize::QImageSize(d->imagePtr) + fillLinesCacheSize; } //--------------------------------------------------------------------- // public void kpFloodFill::prepareColorToChange () { if (d->colorToChange.isValid ()) return; #if DEBUG_KP_FLOOD_FILL && 1 qCDebug(kpLogImagelib) << "kpFloodFill::prepareColorToChange()"; #endif d->colorToChange = kpPixmapFX::getColorAtPixel (*d->imagePtr, QPoint (d->x, d->y)); } //--------------------------------------------------------------------- // public kpColor kpFloodFill::colorToChange () { prepareColorToChange (); return d->colorToChange; } //--------------------------------------------------------------------- // Derived from the zSprite2 Graphics Engine // private kpColor kpFloodFill::pixelColor (int x, int y, bool *beenHere) const { if (beenHere) *beenHere = false; - Q_ASSERT (y >= 0 && y < (int) d->fillLinesCache.count ()); + Q_ASSERT (y >= 0 && y < static_cast (d->fillLinesCache.count ())); foreach (const kpFillLine &line, d->fillLinesCache [y]) { if (x >= line.m_x1 && x <= line.m_x2) { if (beenHere) *beenHere = true; return d->color; } } return kpPixmapFX::getColorAtPixel (*(d->imagePtr), QPoint (x, y)); } //--------------------------------------------------------------------- // private bool kpFloodFill::shouldGoTo (int x, int y) const { bool beenThere; const kpColor col = pixelColor (x, y, &beenThere); return (!beenThere && col.isSimilarTo (d->colorToChange, d->processedColorSimilarity)); } //--------------------------------------------------------------------- // private int kpFloodFill::findMinX (int y, int x) const { for (;;) { if (x < 0) return 0; if (shouldGoTo (x, y)) x--; else return x + 1; } } //--------------------------------------------------------------------- // private int kpFloodFill::findMaxX (int y, int x) const { for (;;) { if (x > d->imagePtr->width () - 1) return d->imagePtr->width () - 1; if (shouldGoTo (x, y)) x++; else return x - 1; } } //--------------------------------------------------------------------- // private void kpFloodFill::addLine (int y, int x1, int x2) { #if DEBUG_KP_FLOOD_FILL && 0 qCDebug(kpLogImagelib) << "kpFillCommand::fillAddLine (" << y << "," << x1 << "," << x2 << ")" << endl; #endif d->fillLines.append (kpFillLine (y, x1, x2)); d->fillLinesCache [y].append ( kpFillLine (y/*OPT: can determine from array index*/, x1, x2)); d->boundingRect = d->boundingRect.united (QRect (QPoint (x1, y), QPoint (x2, y))); } //--------------------------------------------------------------------- // private void kpFloodFill::findAndAddLines (const kpFillLine &fillLine, int dy) { // out of bounds? if (fillLine.m_y + dy < 0 || fillLine.m_y + dy >= d->imagePtr->height ()) return; for (int xnow = fillLine.m_x1; xnow <= fillLine.m_x2; xnow++) { // At current position, right colour? if (shouldGoTo (xnow, fillLine.m_y + dy)) { // Find minimum and maximum x values int minxnow = findMinX (fillLine.m_y + dy, xnow); int maxxnow = findMaxX (fillLine.m_y + dy, xnow); // Draw line addLine (fillLine.m_y + dy, minxnow, maxxnow); // Move x pointer xnow = maxxnow; } } } //--------------------------------------------------------------------- // public void kpFloodFill::prepare () { if (d->prepared) return; #if DEBUG_KP_FLOOD_FILL && 1 qCDebug(kpLogImagelib) << "kpFloodFill::prepare()"; #endif prepareColorToChange (); d->boundingRect = QRect (); #if DEBUG_KP_FLOOD_FILL && 1 qCDebug(kpLogImagelib) << "\tperforming NOP check"; #endif // get the color we need to replace if (d->processedColorSimilarity == 0 && d->color == d->colorToChange) { // need to do absolutely nothing (this is a significant optimization // for people who randomly click a lot over already-filled areas) d->prepared = true; // sync with all "return true"'s return; } #if DEBUG_KP_FLOOD_FILL && 1 qCDebug(kpLogImagelib) << "\tcreating fillLinesCache"; #endif // ready cache for (int i = 0; i < d->imagePtr->height (); i++) d->fillLinesCache.append (QLinkedList ()); #if DEBUG_KP_FLOOD_FILL && 1 qCDebug(kpLogImagelib) << "\tcreating fill lines"; #endif // draw initial line addLine (d->y, findMinX (d->y, d->x), findMaxX (d->y, d->x)); for (QLinkedList ::ConstIterator it = d->fillLines.begin (); it != d->fillLines.end (); ++it) { #if DEBUG_KP_FLOOD_FILL && 0 qCDebug(kpLogImagelib) << "Expanding from y=" << (*it).m_y << " x1=" << (*it).m_x1 << " x2=" << (*it).m_x2 << endl; #endif // // Make more lines above and below current line. // // WARNING: Adds to end of "fillLines" (the linked list we are iterating // through). Therefore, "fillLines" must remain a linked list // - you cannot change it into a vector. Also, do not use // "foreach" for this loop as that makes a copy of the linked // list at the start and won't see new lines. // findAndAddLines (*it, -1); findAndAddLines (*it, +1); } #if DEBUG_KP_FLOOD_FILL && 1 qCDebug(kpLogImagelib) << "\tfinalising memory usage"; #endif // finalize memory usage d->fillLinesCache.clear (); d->prepared = true; // sync with all "return true"'s } //--------------------------------------------------------------------- // public QRect kpFloodFill::boundingRect () { prepare (); return d->boundingRect; } //--------------------------------------------------------------------- // public void kpFloodFill::fill() { prepare(); QApplication::setOverrideCursor(Qt::WaitCursor); QPainter painter(d->imagePtr); // by definition, flood fill with a fully transparent color erases the pixels // and sets them to be fully transparent if ( d->color.isTransparent() ) painter.setCompositionMode(QPainter::CompositionMode_Clear); painter.setPen(d->color.toQColor()); foreach (const kpFillLine &l, d->fillLines) { if ( l.m_x1 == l.m_x2 ) painter.drawPoint(l.m_x1, l.m_y); else painter.drawLine(l.m_x1, l.m_y, l.m_x2, l.m_y); } QApplication::restoreOverrideCursor(); } //--------------------------------------------------------------------- diff --git a/imagelib/transforms/kpTransformAutoCrop.cpp b/imagelib/transforms/kpTransformAutoCrop.cpp index b1f9dd7f..389d9fff 100644 --- a/imagelib/transforms/kpTransformAutoCrop.cpp +++ b/imagelib/transforms/kpTransformAutoCrop.cpp @@ -1,766 +1,763 @@ /* Copyright (c) 2003-2007 Clarence Dang All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ // TODO: Color Similarity is obviously useful in Autocrop but it isn't // obvious as to how to implement it. The current heuristic, // for each side, chooses an arbitrary reference color for which // all other candidate pixels in that side are tested against // for similarity. But if the reference color happens to be at // one extreme of the range of colors in that side, then pixels // at the other extreme would not be deemed similar enough. The // key is to find the median color as the reference but how do // you do this if you don't know which pixels to sample in the first // place (that's what you're trying to find)? Chicken and egg situation. // // The other heuristic that is in doubt is the use of the average // color in determining the similarity of sides (it is possible // to get vastly differently colors in both sides yet they will be // considered similar). #define DEBUG_KP_TOOL_AUTO_CROP 0 #include "kpTransformAutoCrop.h" #include "layers/selections/image/kpAbstractImageSelection.h" #include "widgets/toolbars/kpColorToolBar.h" #include "environments/commands/kpCommandEnvironment.h" #include "commands/kpCommandHistory.h" #include "document/kpDocument.h" #include "mainWindow/kpMainWindow.h" #include "imagelib/kpPainter.h" #include "pixmapfx/kpPixmapFX.h" #include "layers/selections/image/kpRectangularImageSelection.h" #include "generic/kpSetOverrideCursorSaver.h" #include "tools/kpTool.h" #include "views/manager/kpViewManager.h" #include "kpLogCategories.h" #include #include #include //--------------------------------------------------------------------- class kpTransformAutoCropBorder { public: // WARNING: Only call the with imagePtr = 0 if you are going to use // operator= to fill it in with a valid imagePtr immediately // afterwards. kpTransformAutoCropBorder (const kpImage *imagePtr = nullptr, int processedColorSimilarity = 0); kpCommandSize::SizeType size () const; const kpImage *image () const; int processedColorSimilarity () const; QRect rect () const; int left () const; int right () const; int top () const; int bottom () const; kpColor referenceColor () const; kpColor averageColor () const; bool isSingleColor () const; // (returns true on success (even if no rect) or false on error) bool calculate (int isX, int dir); bool fillsEntireImage () const; bool exists () const; void invalidate (); private: const kpImage *m_imagePtr; int m_processedColorSimilarity; QRect m_rect; kpColor m_referenceColor; int m_redSum, m_greenSum, m_blueSum; bool m_isSingleColor; }; kpTransformAutoCropBorder::kpTransformAutoCropBorder (const kpImage *imagePtr, int processedColorSimilarity) : m_imagePtr (imagePtr), m_processedColorSimilarity (processedColorSimilarity) { invalidate (); } // public kpCommandSize::SizeType kpTransformAutoCropBorder::size () const { return sizeof (kpTransformAutoCropBorder); } // public const kpImage *kpTransformAutoCropBorder::image () const { return m_imagePtr; } // public int kpTransformAutoCropBorder::processedColorSimilarity () const { return m_processedColorSimilarity; } // public QRect kpTransformAutoCropBorder::rect () const { return m_rect; } // public int kpTransformAutoCropBorder::left () const { return m_rect.left (); } // public int kpTransformAutoCropBorder::right () const { return m_rect.right (); } // public int kpTransformAutoCropBorder::top () const { return m_rect.top (); } // public int kpTransformAutoCropBorder::bottom () const { return m_rect.bottom (); } // public kpColor kpTransformAutoCropBorder::referenceColor () const { return m_referenceColor; } // public kpColor kpTransformAutoCropBorder::averageColor () const { if (!m_rect.isValid ()) return kpColor::Invalid; if (m_referenceColor.isTransparent ()) return kpColor::Transparent; else if (m_processedColorSimilarity == 0) return m_referenceColor; else { int numPixels = (m_rect.width () * m_rect.height ()); Q_ASSERT (numPixels > 0); return kpColor (m_redSum / numPixels, m_greenSum / numPixels, m_blueSum / numPixels); } } //--------------------------------------------------------------------- bool kpTransformAutoCropBorder::isSingleColor () const { return m_isSingleColor; } //--------------------------------------------------------------------- // public bool kpTransformAutoCropBorder::calculate (int isX, int dir) { #if DEBUG_KP_TOOL_AUTO_CROP && 1 qCDebug(kpLogImagelib) << "kpTransformAutoCropBorder::calculate() CALLED!"; #endif int maxX = m_imagePtr->width () - 1; int maxY = m_imagePtr->height () - 1; QImage qimage = *m_imagePtr; Q_ASSERT (!qimage.isNull ()); // (sync both branches) if (isX) { int numCols = 0; int startX = (dir > 0) ? 0 : maxX; kpColor col = kpPixmapFX::getColorAtPixel (qimage, startX, 0); for (int x = startX; x >= 0 && x <= maxX; x += dir) { int y; for (y = 0; y <= maxY; y++) { if (!kpPixmapFX::getColorAtPixel (qimage, x, y).isSimilarTo (col, m_processedColorSimilarity)) break; } if (y <= maxY) break; else numCols++; } if (numCols) { m_rect = kpPainter::normalizedRect(QPoint(startX, 0), QPoint(startX + (numCols - 1) * dir, maxY)); m_referenceColor = col; } } else { int numRows = 0; int startY = (dir > 0) ? 0 : maxY; kpColor col = kpPixmapFX::getColorAtPixel (qimage, 0, startY); for (int y = startY; y >= 0 && y <= maxY; y += dir) { int x; for (x = 0; x <= maxX; x++) { if (!kpPixmapFX::getColorAtPixel (qimage, x, y).isSimilarTo (col, m_processedColorSimilarity)) break; } if (x <= maxX) break; else numRows++; } if (numRows) { m_rect = kpPainter::normalizedRect(QPoint(0, startY), QPoint(maxX, startY + (numRows - 1) * dir)); m_referenceColor = col; } } if (m_rect.isValid ()) { m_isSingleColor = true; if (m_processedColorSimilarity != 0) { for (int y = m_rect.top (); y <= m_rect.bottom (); y++) { for (int x = m_rect.left (); x <= m_rect.right (); x++) { kpColor colAtPixel = kpPixmapFX::getColorAtPixel (qimage, x, y); if (m_isSingleColor && colAtPixel != m_referenceColor) m_isSingleColor = false; m_redSum += colAtPixel.red (); m_greenSum += colAtPixel.green (); m_blueSum += colAtPixel.blue (); } } } } return true; } // public bool kpTransformAutoCropBorder::fillsEntireImage () const { return (m_rect == m_imagePtr->rect ()); } // public bool kpTransformAutoCropBorder::exists () const { // (will use in an addition so make sure returns 1 or 0) return (m_rect.isValid () ? 1 : 0); } // public void kpTransformAutoCropBorder::invalidate () { m_rect = QRect (); m_referenceColor = kpColor::Invalid; m_redSum = m_greenSum = m_blueSum = 0; m_isSingleColor = false; } struct kpTransformAutoCropCommandPrivate { bool actOnSelection; kpTransformAutoCropBorder leftBorder, rightBorder, topBorder, botBorder; kpImage *leftImage, *rightImage, *topImage, *botImage; QRect contentsRect; int oldWidth, oldHeight; kpAbstractImageSelection *oldSelectionPtr; }; // REFACTOR: Move to /commands/ kpTransformAutoCropCommand::kpTransformAutoCropCommand (bool actOnSelection, const kpTransformAutoCropBorder &leftBorder, const kpTransformAutoCropBorder &rightBorder, const kpTransformAutoCropBorder &topBorder, const kpTransformAutoCropBorder &botBorder, kpCommandEnvironment *environ) : kpNamedCommand(text(actOnSelection, DontShowAccel), environ), d (new kpTransformAutoCropCommandPrivate ()) { d->actOnSelection = actOnSelection; d->leftBorder = leftBorder; d->rightBorder = rightBorder; d->topBorder = topBorder; d->botBorder = botBorder; d->leftImage = nullptr; d->rightImage = nullptr; d->topImage = nullptr; d->botImage = nullptr; kpDocument *doc = document (); Q_ASSERT (doc); d->oldWidth = doc->width (d->actOnSelection); d->oldHeight = doc->height (d->actOnSelection); d->oldSelectionPtr = nullptr; } //--------------------------------------------------------------------- kpTransformAutoCropCommand::~kpTransformAutoCropCommand () { deleteUndoImages (); delete d->oldSelectionPtr; delete d; } //--------------------------------------------------------------------- // public static QString kpTransformAutoCropCommand::text(bool actOnSelection, int options) { if (actOnSelection) { if (options & kpTransformAutoCropCommand::ShowAccel) return i18n ("Remove Internal B&order"); else return i18n ("Remove Internal Border"); } else { if (options & kpTransformAutoCropCommand::ShowAccel) return i18n ("Autocr&op"); else return i18n ("Autocrop"); } } //--------------------------------------------------------------------- // public virtual [base kpCommand] kpCommandSize::SizeType kpTransformAutoCropCommand::size () const { return d->leftBorder.size () + d->rightBorder.size () + d->topBorder.size () + d->botBorder.size () + ImageSize (d->leftImage) + ImageSize (d->rightImage) + ImageSize (d->topImage) + ImageSize (d->botImage) + SelectionSize (d->oldSelectionPtr); } //--------------------------------------------------------------------- // private void kpTransformAutoCropCommand::getUndoImage (const kpTransformAutoCropBorder &border, kpImage **image) { kpDocument *doc = document (); Q_ASSERT (doc); #if DEBUG_KP_TOOL_AUTO_CROP && 1 qCDebug(kpLogImagelib) << "kpTransformAutoCropCommand::getUndoImage()"; qCDebug(kpLogImagelib) << "\timage=" << image << " border: rect=" << border.rect () << " isSingleColor=" << border.isSingleColor () << endl; #endif if (image && border.exists () && !border.isSingleColor ()) { if (*image) { #if DEBUG_KP_TOOL_AUTO_CROP && 1 qCDebug(kpLogImagelib) << "\talready have *image - delete it"; #endif delete *image; } *image = new kpImage ( kpPixmapFX::getPixmapAt (doc->image (d->actOnSelection), border.rect ())); } } // private void kpTransformAutoCropCommand::getUndoImages () { getUndoImage (d->leftBorder, &d->leftImage); getUndoImage (d->rightBorder, &d->rightImage); getUndoImage (d->topBorder, &d->topImage); getUndoImage (d->botBorder, &d->botImage); } // private void kpTransformAutoCropCommand::deleteUndoImages () { #if DEBUG_KP_TOOL_AUTO_CROP && 1 qCDebug(kpLogImagelib) << "kpTransformAutoCropCommand::deleteUndoImages()"; #endif delete d->leftImage; d->leftImage = nullptr; delete d->rightImage; d->rightImage = nullptr; delete d->topImage; d->topImage = nullptr; delete d->botImage; d->botImage = nullptr; } // public virtual [base kpCommand] void kpTransformAutoCropCommand::execute () { if (!d->contentsRect.isValid ()) d->contentsRect = contentsRect (); getUndoImages (); kpDocument *doc = document (); Q_ASSERT (doc); kpImage imageWithoutBorder = kpTool::neededPixmap (doc->image (d->actOnSelection), d->contentsRect); if (!d->actOnSelection) doc->setImage (imageWithoutBorder); else { d->oldSelectionPtr = doc->imageSelection ()->clone (); d->oldSelectionPtr->setBaseImage (kpImage ()); // d->contentsRect is relative to the top of the sel // while sel is relative to the top of the doc QRect rect = d->contentsRect; rect.translate (d->oldSelectionPtr->x (), d->oldSelectionPtr->y ()); kpRectangularImageSelection sel ( rect, imageWithoutBorder, d->oldSelectionPtr->transparency ()); doc->setSelection (sel); environ ()->somethingBelowTheCursorChanged (); } } // public virtual [base kpCommand] void kpTransformAutoCropCommand::unexecute () { #if DEBUG_KP_TOOL_AUTO_CROP && 1 qCDebug(kpLogImagelib) << "kpTransformAutoCropCommand::unexecute()"; #endif kpDocument *doc = document (); Q_ASSERT (doc); kpImage image (d->oldWidth, d->oldHeight, QImage::Format_ARGB32_Premultiplied); // restore the position of the center image kpPixmapFX::setPixmapAt (&image, d->contentsRect, doc->image (d->actOnSelection)); // draw the borders const kpTransformAutoCropBorder *borders [] = { &d->leftBorder, &d->rightBorder, &d->topBorder, &d->botBorder, nullptr }; const kpImage *images [] = { d->leftImage, d->rightImage, d->topImage, d->botImage, nullptr }; const kpImage **p = images; for (const kpTransformAutoCropBorder **b = borders; *b; b++, p++) { if (!(*b)->exists ()) continue; if ((*b)->isSingleColor ()) { kpColor col = (*b)->referenceColor (); #if DEBUG_KP_TOOL_AUTO_CROP && 1 qCDebug(kpLogImagelib) << "\tdrawing border " << (*b)->rect () << " rgb=" << (int *) col.toQRgb () /* %X hack */ << endl; #endif const QRect r = (*b)->rect (); kpPainter::fillRect (&image, r.x (), r.y (), r.width (), r.height (), col); } else { #if DEBUG_KP_TOOL_AUTO_CROP && 1 qCDebug(kpLogImagelib) << "\trestoring border image " << (*b)->rect (); #endif if (*p) { // REFACTOR: Add equivalent method to kpPainter and use. kpPixmapFX::setPixmapAt (&image, (*b)->rect (), **p); } } } if (!d->actOnSelection) doc->setImage (image); else { d->oldSelectionPtr->setBaseImage (image); doc->setSelection (*d->oldSelectionPtr); delete d->oldSelectionPtr; d->oldSelectionPtr = nullptr; environ ()->somethingBelowTheCursorChanged (); } deleteUndoImages (); } // private QRect kpTransformAutoCropCommand::contentsRect () const { const kpImage image = document ()->image (d->actOnSelection); QPoint topLeft (d->leftBorder.exists () ? d->leftBorder.rect ().right () + 1 : 0, d->topBorder.exists () ? d->topBorder.rect ().bottom () + 1 : 0); QPoint botRight (d->rightBorder.exists () ? d->rightBorder.rect ().left () - 1 : image.width () - 1, d->botBorder.exists () ? d->botBorder.rect ().top () - 1 : image.height () - 1); return QRect (topLeft, botRight); } static void ShowNothingToAutocropMessage (kpMainWindow *mainWindow, bool actOnSelection) { kpSetOverrideCursorSaver cursorSaver (Qt::ArrowCursor); if (actOnSelection) { KMessageBox::information (mainWindow, i18n ("KolourPaint cannot remove the selection's internal border as it" " could not be located."), i18nc ("@title:window", "Cannot Remove Internal Border"), "NothingToAutoCrop"); } else { KMessageBox::information (mainWindow, i18n ("KolourPaint cannot automatically crop the image as its" " border could not be located."), i18nc ("@title:window", "Cannot Autocrop"), "NothingToAutoCrop"); } } bool kpTransformAutoCrop (kpMainWindow *mainWindow) { #if DEBUG_KP_TOOL_AUTO_CROP qCDebug(kpLogImagelib) << "kpTransformAutoCrop() CALLED!"; #endif Q_ASSERT (mainWindow); kpDocument *doc = mainWindow->document (); Q_ASSERT (doc); // OPT: if already pulled selection image, no need to do it again here kpImage image = doc->selection () ? doc->getSelectedBaseImage () : doc->image (); Q_ASSERT (!image.isNull ()); kpViewManager *vm = mainWindow->viewManager (); Q_ASSERT (vm); int processedColorSimilarity = mainWindow->colorToolBar ()->processedColorSimilarity (); kpTransformAutoCropBorder leftBorder (&image, processedColorSimilarity), rightBorder (&image, processedColorSimilarity), topBorder (&image, processedColorSimilarity), botBorder (&image, processedColorSimilarity); kpSetOverrideCursorSaver cursorSaver (Qt::WaitCursor); mainWindow->colorToolBar ()->flashColorSimilarityToolBarItem (); // TODO: With Colour Similarity, a lot of weird (and wonderful) things can // happen resulting in a huge number of code paths. Needs refactoring // and regression testing. // // TODO: e.g. When the top fills entire rect but bot doesn't we could // invalidate top and continue autocrop. int numRegions = 0; if (!leftBorder.calculate (true/*x*/, +1/*going right*/) || leftBorder.fillsEntireImage () || !rightBorder.calculate (true/*x*/, -1/*going left*/) || rightBorder.fillsEntireImage () || !topBorder.calculate (false/*y*/, +1/*going down*/) || topBorder.fillsEntireImage () || !botBorder.calculate (false/*y*/, -1/*going up*/) || botBorder.fillsEntireImage () || ((numRegions = leftBorder.exists () + rightBorder.exists () + topBorder.exists () + botBorder.exists ()) == 0)) { #if DEBUG_KP_TOOL_AUTO_CROP qCDebug(kpLogImagelib) << "\tcan't find border; leftBorder.rect=" << leftBorder.rect () << " rightBorder.rect=" << rightBorder.rect () << " topBorder.rect=" << topBorder.rect () << " botBorder.rect=" << botBorder.rect () << endl; #endif - ::ShowNothingToAutocropMessage (mainWindow, (bool) doc->selection ()); + ::ShowNothingToAutocropMessage (mainWindow, static_cast (doc->selection ())); return false; } #if DEBUG_KP_TOOL_AUTO_CROP qCDebug(kpLogImagelib) << "\tnumRegions=" << numRegions; qCDebug(kpLogImagelib) << "\t\tleft=" << leftBorder.rect () << " refCol=" << (leftBorder.exists () ? (int *) leftBorder.referenceColor ().toQRgb () : 0) << " avgCol=" << (leftBorder.exists () ? (int *) leftBorder.averageColor ().toQRgb () : 0) << endl; qCDebug(kpLogImagelib) << "\t\tright=" << rightBorder.rect () << " refCol=" << (rightBorder.exists () ? (int *) rightBorder.referenceColor ().toQRgb () : 0) << " avgCol=" << (rightBorder.exists () ? (int *) rightBorder.averageColor ().toQRgb () : 0) << endl; qCDebug(kpLogImagelib) << "\t\ttop=" << topBorder.rect () << " refCol=" << (topBorder.exists () ? (int *) topBorder.referenceColor ().toQRgb () : 0) << " avgCol=" << (topBorder.exists () ? (int *) topBorder.averageColor ().toQRgb () : 0) << endl; qCDebug(kpLogImagelib) << "\t\tbot=" << botBorder.rect () << " refCol=" << (botBorder.exists () ? (int *) botBorder.referenceColor ().toQRgb () : 0) << " avgCol=" << (botBorder.exists () ? (int *) botBorder.averageColor ().toQRgb () : 0) << endl; #endif // In case e.g. the user pastes a solid, coloured-in rectangle, // we favor killing the bottom and right regions // (these regions probably contain the unwanted whitespace due // to the doc being bigger than the pasted selection to start with). // // We also kill if they kiss or even overlap. if (leftBorder.exists () && rightBorder.exists ()) { const kpColor leftCol = leftBorder.averageColor (); const kpColor rightCol = rightBorder.averageColor (); if ((numRegions == 2 && !leftCol.isSimilarTo (rightCol, processedColorSimilarity)) || leftBorder.right () >= rightBorder.left () - 1) // kissing or overlapping { #if DEBUG_KP_TOOL_AUTO_CROP qCDebug(kpLogImagelib) << "\tignoring left border"; #endif leftBorder.invalidate (); } } if (topBorder.exists () && botBorder.exists ()) { const kpColor topCol = topBorder.averageColor (); const kpColor botCol = botBorder.averageColor (); if ((numRegions == 2 && !topCol.isSimilarTo (botCol, processedColorSimilarity)) || topBorder.bottom () >= botBorder.top () - 1) // kissing or overlapping { #if DEBUG_KP_TOOL_AUTO_CROP qCDebug(kpLogImagelib) << "\tignoring top border"; #endif topBorder.invalidate (); } } mainWindow->addImageOrSelectionCommand ( - new kpTransformAutoCropCommand ( - (bool) doc->selection (), - leftBorder, rightBorder, - topBorder, botBorder, - mainWindow->commandEnvironment ())); + new kpTransformAutoCropCommand (static_cast (doc->selection ()), + leftBorder, rightBorder, topBorder, botBorder, mainWindow->commandEnvironment ())); return true; } diff --git a/kpViewScrollableContainer.cpp b/kpViewScrollableContainer.cpp index 33c3b87e..2e6227b3 100644 --- a/kpViewScrollableContainer.cpp +++ b/kpViewScrollableContainer.cpp @@ -1,1180 +1,1183 @@ /* Copyright (c) 2003-2007 Clarence Dang Copyright (c) 2011 Martin Koller 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_VIEW_SCROLLABLE_CONTAINER 0 #include "kpViewScrollableContainer.h" #include #include #include #include #include #include #include #include #include "kpLogCategories.h" #include #include "kpDefs.h" #include "pixmapfx/kpPixmapFX.h" #include "views/kpView.h" #include "generic/kpWidgetMapper.h" //--------------------------------------------------------------------- // (Pulled from out of Thurston's hat) static const int DragScrollLeftTopMargin = 0; static const int DragScrollRightBottomMargin = 16; // scrollbarish static const int DragScrollInterval = 150; static const int DragScrollInitialInterval = DragScrollInterval * 2; static const int DragScrollNumPixels = 10; static const int DragDistanceFromRectMaxFor1stMultiplier = 50; static const int DragDistanceFromRectMaxFor2ndMultiplier = 100; //--------------------------------------------------------------------- //--------------------------------------------------------------------- // a transparent widget above all others in the viewport used only while resizing the document // to be able to show the resize lines above everything else class kpOverlay : public QWidget { public: kpOverlay(QWidget *parent, kpViewScrollableContainer *container) : QWidget(parent), m_container(container) { } void paintEvent(QPaintEvent *) override { m_container->drawResizeLines(); } private: kpViewScrollableContainer *m_container; }; //--------------------------------------------------------------------- const int kpGrip::Size = 5; //--------------------------------------------------------------------- kpGrip::kpGrip (GripType type, QWidget *parent) : QWidget(parent), m_type (type), m_startPoint (KP_INVALID_POINT), m_currentPoint (KP_INVALID_POINT), m_shouldReleaseMouseButtons (false) { setCursor(cursorForType(m_type)); setMouseTracking(true); // mouseMoveEvent's even when no mousebtn down setAutoFillBackground(true); setBackgroundRole(QPalette::Highlight); setFixedSize(kpGrip::Size, kpGrip::Size); } //--------------------------------------------------------------------- // public kpGrip::GripType kpGrip::type () const { return m_type; } //--------------------------------------------------------------------- // public static QCursor kpGrip::cursorForType (GripType type) { switch (type) { case kpGrip::Bottom: return Qt::SizeVerCursor; break; // one day you'll forget case kpGrip::Right: return Qt::SizeHorCursor; break; // one day you'll forget case kpGrip::BottomRight: return Qt::SizeFDiagCursor; break; // one day you'll forget } return Qt::ArrowCursor; } //--------------------------------------------------------------------- // public bool kpGrip::containsCursor() { return isVisible() && QRect(mapToGlobal(rect().topLeft()), mapToGlobal(rect().bottomRight())).contains(QCursor::pos()); } //--------------------------------------------------------------------- // public bool kpGrip::isDrawing () const { return (m_startPoint != KP_INVALID_POINT); } //--------------------------------------------------------------------- // public QString kpGrip::haventBegunDrawUserMessage () const { return i18n ("Left drag the handle to resize the image."); } //--------------------------------------------------------------------- // public QString kpGrip::userMessage () const { return m_userMessage; } //--------------------------------------------------------------------- // public void kpGrip::setUserMessage (const QString &message) { // Don't do NOP checking here since another grip might have changed // the message so an apparent NOP for this grip is not a NOP in the // global sense (kpViewScrollableContainer::slotGripStatusMessageChanged()). m_userMessage = message; emit statusMessageChanged (message); } //--------------------------------------------------------------------- // protected void kpGrip::cancel () { #if DEBUG_KP_VIEW_SCROLLABLE_CONTAINER qCDebug(kpLogMisc) << "kpGrip::cancel()"; #endif if (m_currentPoint == KP_INVALID_POINT) return; m_startPoint = KP_INVALID_POINT; m_currentPoint = KP_INVALID_POINT; setUserMessage (i18n ("Resize Image: Let go of all the mouse buttons.")); setCursor (Qt::ArrowCursor); m_shouldReleaseMouseButtons = true; releaseKeyboard (); emit cancelledDraw (); } //--------------------------------------------------------------------- // protected virtual [base QWidget] void kpGrip::keyReleaseEvent (QKeyEvent *e) { if (m_startPoint != KP_INVALID_POINT && e->key () == Qt::Key_Escape) { cancel (); } } //--------------------------------------------------------------------- // protected virtual [base QWidget] void kpGrip::mousePressEvent (QMouseEvent *e) { if (m_startPoint == KP_INVALID_POINT && (e->buttons () & Qt::MouseButtonMask) == Qt::LeftButton) { m_startPoint = e->pos (); m_currentPoint = e->pos (); emit beganDraw (); grabKeyboard (); setUserMessage (i18n ("Resize Image: Right click to cancel.")); setCursor (cursorForType (m_type)); } else { if (m_startPoint != KP_INVALID_POINT) cancel (); } } //--------------------------------------------------------------------- // public QPoint kpGrip::viewDeltaPoint () const { if (m_startPoint == KP_INVALID_POINT) return KP_INVALID_POINT; const QPoint point = mapFromGlobal (QCursor::pos ()); // TODO: this is getting out of sync with m_currentPoint return QPoint (((m_type & kpGrip::Right) ? point.x () - m_startPoint.x () : 0), ((m_type & kpGrip::Bottom) ? point.y () - m_startPoint.y () : 0)); } //--------------------------------------------------------------------- // public void kpGrip::mouseMovedTo (const QPoint &point, bool dueToDragScroll) { if (m_startPoint == KP_INVALID_POINT) return; m_currentPoint = point; emit continuedDraw (((m_type & kpGrip::Right) ? point.x () - m_startPoint.x () : 0), ((m_type & kpGrip::Bottom) ? point.y () - m_startPoint.y () : 0), dueToDragScroll); } //--------------------------------------------------------------------- // protected virtual [base QWidget] void kpGrip::mouseMoveEvent (QMouseEvent *e) { #if DEBUG_KP_VIEW_SCROLLABLE_CONTAINER qCDebug(kpLogMisc) << "kpGrip::mouseMoveEvent() m_startPoint=" << m_startPoint << " stateAfter: buttons=" << (int *) (int) e->buttons () << endl; #endif if (m_startPoint == KP_INVALID_POINT) { if ((e->buttons () & Qt::MouseButtonMask) == 0) setUserMessage (haventBegunDrawUserMessage ()); return; } mouseMovedTo (e->pos (), false/*not due to drag scroll*/); } //--------------------------------------------------------------------- // protected virtual [base QWidget] void kpGrip::mouseReleaseEvent (QMouseEvent *e) { #if DEBUG_KP_VIEW_SCROLLABLE_CONTAINER qCDebug(kpLogMisc) << "kpGrip::mouseReleaseEvent() m_startPoint=" << m_startPoint << " stateAfter: buttons=" << (int *) (int) e->buttons () << endl; #endif if (m_startPoint != KP_INVALID_POINT) { const int dx = m_currentPoint.x () - m_startPoint.x (), dy = m_currentPoint.y () - m_startPoint.y (); m_currentPoint = KP_INVALID_POINT; m_startPoint = KP_INVALID_POINT; releaseKeyboard (); emit endedDraw ((m_type & kpGrip::Right) ? dx : 0, (m_type & kpGrip::Bottom) ? dy : 0); } if ((e->buttons () & Qt::MouseButtonMask) == 0) { m_shouldReleaseMouseButtons = false; setUserMessage(QString()); setCursor (cursorForType (m_type)); releaseKeyboard (); emit releasedAllButtons (); } } //--------------------------------------------------------------------- // protected virtual [base QWidget] void kpGrip::enterEvent (QEvent * /*e*/) { #if DEBUG_KP_VIEW_SCROLLABLE_CONTAINER qCDebug(kpLogMisc) << "kpGrip::enterEvent()" << " m_startPoint=" << m_startPoint << " shouldReleaseMouseButtons=" << m_shouldReleaseMouseButtons << endl; #endif if (m_startPoint == KP_INVALID_POINT && !m_shouldReleaseMouseButtons) { #if DEBUG_KP_VIEW_SCROLLABLE_CONTAINER qCDebug(kpLogMisc) << "\tsending message"; #endif setUserMessage (haventBegunDrawUserMessage ()); } } //--------------------------------------------------------------------- // protected virtual [base QWidget] void kpGrip::leaveEvent (QEvent * /*e*/) { #if DEBUG_KP_VIEW_SCROLLABLE_CONTAINER qCDebug(kpLogMisc) << "kpGrip::leaveEvent()" << " m_startPoint=" << m_startPoint << " shouldReleaseMouseButtons=" << m_shouldReleaseMouseButtons << endl; #endif if (m_startPoint == KP_INVALID_POINT && !m_shouldReleaseMouseButtons) { setUserMessage(QString()); } } //--------------------------------------------------------------------- //--------------------------------------------------------------------- //--------------------------------------------------------------------- // TODO: Are we checking for m_view == 0 often enough? Also an issue in KDE 3. kpViewScrollableContainer::kpViewScrollableContainer(QWidget *parent) : QScrollArea(parent), m_view(nullptr), m_overlay(new kpOverlay(viewport(), this)), m_docResizingGrip (nullptr), m_dragScrollTimer (new QTimer (this)), m_zoomLevel (100), m_scrollTimerRunOnce (false), m_resizeRoundedLastViewX (-1), m_resizeRoundedLastViewY (-1), m_resizeRoundedLastViewDX (0), m_resizeRoundedLastViewDY (0), m_haveMovedFromOriginalDocSize (false) { // the base widget holding the documents view plus the resize grips setWidget(new QWidget(viewport())); m_bottomGrip = new kpGrip(kpGrip::Bottom, widget()); m_rightGrip = new kpGrip(kpGrip::Right, widget()); m_bottomRightGrip = new kpGrip(kpGrip::BottomRight, widget()); m_bottomGrip->setObjectName(QLatin1String("Bottom Grip")); m_rightGrip->setObjectName(QLatin1String("Right Grip")); m_bottomRightGrip->setObjectName(QLatin1String("BottomRight Grip")); m_bottomGrip->hide (); connectGripSignals (m_bottomGrip); m_rightGrip->hide (); connectGripSignals (m_rightGrip); m_bottomRightGrip->hide (); connectGripSignals (m_bottomRightGrip); connect (horizontalScrollBar(), SIGNAL(valueChanged(int)), this, SLOT(slotContentsMoved())); connect (verticalScrollBar(), SIGNAL(valueChanged(int)), this, SLOT(slotContentsMoved())); connect (m_dragScrollTimer, SIGNAL (timeout()), this, SLOT (slotDragScroll())); m_overlay->hide(); } //--------------------------------------------------------------------- // protected void kpViewScrollableContainer::connectGripSignals (kpGrip *grip) { connect (grip, SIGNAL (beganDraw()), this, SLOT (slotGripBeganDraw())); connect (grip, SIGNAL (continuedDraw(int,int,bool)), this, SLOT (slotGripContinuedDraw(int,int,bool))); connect (grip, SIGNAL (cancelledDraw()), this, SLOT (slotGripCancelledDraw())); connect (grip, SIGNAL (endedDraw(int,int)), this, SLOT (slotGripEndedDraw(int,int))); connect (grip, SIGNAL (statusMessageChanged(QString)), this, SLOT (slotGripStatusMessageChanged(QString))); connect (grip, SIGNAL (releasedAllButtons()), this, SLOT (recalculateStatusMessage())); } //--------------------------------------------------------------------- // public QSize kpViewScrollableContainer::newDocSize () const { return newDocSize (m_resizeRoundedLastViewDX, m_resizeRoundedLastViewDY); } //--------------------------------------------------------------------- // public bool kpViewScrollableContainer::haveMovedFromOriginalDocSize () const { return m_haveMovedFromOriginalDocSize; } //--------------------------------------------------------------------- // public QString kpViewScrollableContainer::statusMessage () const { return m_gripStatusMessage; } //--------------------------------------------------------------------- // public void kpViewScrollableContainer::clearStatusMessage () { #if DEBUG_KP_VIEW_SCROLLABLE_CONTAINER && 1 qCDebug(kpLogMisc) << "kpViewScrollableContainer::clearStatusMessage()"; #endif m_bottomRightGrip->setUserMessage(QString()); m_bottomGrip->setUserMessage(QString()); m_rightGrip->setUserMessage(QString()); } //--------------------------------------------------------------------- // protected QSize kpViewScrollableContainer::newDocSize (int viewDX, int viewDY) const { if (!m_view) return QSize (); if (!docResizingGrip ()) return QSize (); - const int docX = (int) m_view->transformViewToDocX (m_view->width () + viewDX); - const int docY = (int) m_view->transformViewToDocY (m_view->height () + viewDY); + const int docX = static_cast (m_view->transformViewToDocX (m_view->width () + viewDX)); + const int docY = static_cast (m_view->transformViewToDocY (m_view->height () + viewDY)); return QSize (qMax (1, docX), qMax (1, docY)); } //--------------------------------------------------------------------- // protected void kpViewScrollableContainer::calculateDocResizingGrip () { if (m_bottomRightGrip->isDrawing ()) m_docResizingGrip = m_bottomRightGrip; else if (m_bottomGrip->isDrawing ()) m_docResizingGrip = m_bottomGrip; else if (m_rightGrip->isDrawing ()) m_docResizingGrip = m_rightGrip; else m_docResizingGrip = nullptr; } //--------------------------------------------------------------------- // protected kpGrip *kpViewScrollableContainer::docResizingGrip () const { return m_docResizingGrip; } //--------------------------------------------------------------------- // protected int kpViewScrollableContainer::bottomResizeLineWidth () const { if (!docResizingGrip ()) return -1; if (!m_view) return -1; if (docResizingGrip ()->type () & kpGrip::Bottom) return qMax (m_view->zoomLevelY () / 100, 1); else return 1; } //--------------------------------------------------------------------- // protected int kpViewScrollableContainer::rightResizeLineWidth () const { if (!docResizingGrip ()) return -1; if (!m_view) return -1; if (docResizingGrip ()->type () & kpGrip::Right) return qMax (m_view->zoomLevelX () / 100, 1); else return 1; } //--------------------------------------------------------------------- // protected QRect kpViewScrollableContainer::bottomResizeLineRect () const { if (m_resizeRoundedLastViewX < 0 || m_resizeRoundedLastViewY < 0) return QRect (); QRect visibleArea = QRect(QPoint(horizontalScrollBar()->value(),verticalScrollBar()->value()), viewport()->size()); return QRect (QPoint (0, m_resizeRoundedLastViewY), QPoint (m_resizeRoundedLastViewX - 1, m_resizeRoundedLastViewY + bottomResizeLineWidth () - 1)).intersected(visibleArea); } //--------------------------------------------------------------------- // protected QRect kpViewScrollableContainer::rightResizeLineRect () const { if (m_resizeRoundedLastViewX < 0 || m_resizeRoundedLastViewY < 0) return QRect (); QRect visibleArea = QRect(QPoint(horizontalScrollBar()->value(),verticalScrollBar()->value()), viewport()->size()); return QRect (QPoint (m_resizeRoundedLastViewX, 0), QPoint (m_resizeRoundedLastViewX + rightResizeLineWidth () - 1, m_resizeRoundedLastViewY - 1)).intersected(visibleArea); } //--------------------------------------------------------------------- // protected QRect kpViewScrollableContainer::bottomRightResizeLineRect () const { if (m_resizeRoundedLastViewX < 0 || m_resizeRoundedLastViewY < 0) return QRect (); QRect visibleArea = QRect(QPoint(horizontalScrollBar()->value(),verticalScrollBar()->value()), viewport()->size()); return QRect (QPoint (m_resizeRoundedLastViewX, m_resizeRoundedLastViewY), QPoint (m_resizeRoundedLastViewX + rightResizeLineWidth () - 1, m_resizeRoundedLastViewY + bottomResizeLineWidth () - 1)).intersected(visibleArea); } //--------------------------------------------------------------------- // private QRect kpViewScrollableContainer::mapViewToViewport (const QRect &viewRect) { if (!viewRect.isValid ()) return QRect (); QRect ret = viewRect; ret.translate (-horizontalScrollBar()->value() - viewport()->x(), -verticalScrollBar()->value() - viewport()->y()); return ret; } //--------------------------------------------------------------------- void kpViewScrollableContainer::drawResizeLines () { static const char *stipple[] = { "8 8 2 1", ". c #000000", "# c #ffffff", "....####", "....####", "....####", "....####", "####....", "####....", "####....", "####...." }; QPainter p(m_overlay); p.setBackground(QPixmap(stipple)); const QRect rightRect = rightResizeLineRect(); if ( rightRect.isValid() ) { QRect rect = mapViewToViewport(rightRect); p.setBrushOrigin(rect.x(), rect.y()); p.eraseRect(rect); } const QRect bottomRect = bottomResizeLineRect(); if ( bottomRect.isValid() ) { QRect rect = mapViewToViewport(bottomRect); p.setBrushOrigin(rect.x(), rect.y()); p.eraseRect(rect); } const QRect bottomRightRect = bottomRightResizeLineRect (); if ( bottomRightRect.isValid() ) { QRect rect = mapViewToViewport(bottomRightRect); p.setBrushOrigin(rect.x(), rect.y()); p.eraseRect(rect); } } //--------------------------------------------------------------------- // protected void kpViewScrollableContainer::updateResizeLines (int viewX, int viewY, int viewDX, int viewDY) { #if DEBUG_KP_VIEW_SCROLLABLE_CONTAINER && 0 qCDebug(kpLogMisc) << "kpViewScrollableContainer::updateResizeLines(" << viewX << "," << viewY << ")" << " oldViewX=" << m_resizeRoundedLastViewX << " oldViewY=" << m_resizeRoundedLastViewY << " viewDX=" << viewDX << " viewDY=" << viewDY << endl; #endif if (viewX >= 0 && viewY >= 0) { - m_resizeRoundedLastViewX = (int) m_view->transformDocToViewX ((int) m_view->transformViewToDocX (viewX)); - m_resizeRoundedLastViewY = (int) m_view->transformDocToViewY ((int) m_view->transformViewToDocY (viewY)); + m_resizeRoundedLastViewX = + static_cast (m_view->transformDocToViewX (m_view->transformViewToDocX (viewX))); + + m_resizeRoundedLastViewY = + static_cast (m_view->transformDocToViewY (m_view->transformViewToDocY (viewY))); m_resizeRoundedLastViewDX = viewDX; m_resizeRoundedLastViewDY = viewDY; } else { m_resizeRoundedLastViewX = -1; m_resizeRoundedLastViewY = -1; m_resizeRoundedLastViewDX = 0; m_resizeRoundedLastViewDY = 0; } m_overlay->update(); } //--------------------------------------------------------------------- // protected slot void kpViewScrollableContainer::slotGripBeganDraw () { if (!m_view) return; m_overlay->resize(viewport()->size()); // make it cover whole viewport m_overlay->move(viewport()->pos()); m_overlay->show(); m_overlay->raise(); // make it top-most calculateDocResizingGrip (); m_haveMovedFromOriginalDocSize = false; updateResizeLines (m_view->width (), m_view->height (), 0/*viewDX*/, 0/*viewDY*/); emit beganDocResize (); } //--------------------------------------------------------------------- // protected slot void kpViewScrollableContainer::slotGripContinuedDraw (int inViewDX, int inViewDY, bool dueToDragScroll) { int viewDX = inViewDX, viewDY = inViewDY; #if DEBUG_KP_VIEW_SCROLLABLE_CONTAINER qCDebug(kpLogMisc) << "kpViewScrollableContainer::slotGripContinuedDraw(" << viewDX << "," << viewDY << ") size=" << newDocSize (viewDX, viewDY) << " dueToDragScroll=" << dueToDragScroll << endl; #endif if (!m_view) return; if (!dueToDragScroll && beginDragScroll(m_view->zoomLevelX ())) { const QPoint newViewDeltaPoint = docResizingGrip ()->viewDeltaPoint (); viewDX = newViewDeltaPoint.x (); viewDY = newViewDeltaPoint.y (); #if DEBUG_KP_VIEW_SCROLLABLE_CONTAINER qCDebug(kpLogMisc) << "\tdrag scrolled - new view delta point=" << newViewDeltaPoint << endl; #endif } m_haveMovedFromOriginalDocSize = true; - updateResizeLines (qMax (1, qMax (m_view->width () + viewDX, (int) m_view->transformDocToViewX (1))), - qMax (1, qMax (m_view->height () + viewDY, (int) m_view->transformDocToViewY (1))), + updateResizeLines (qMax (1, qMax (m_view->width () + viewDX, static_cast (m_view->transformDocToViewX (1)))), + qMax (1, qMax (m_view->height () + viewDY, static_cast (m_view->transformDocToViewY (1)))), viewDX, viewDY); emit continuedDocResize (newDocSize ()); } //--------------------------------------------------------------------- // protected slot void kpViewScrollableContainer::slotGripCancelledDraw () { m_haveMovedFromOriginalDocSize = false; updateResizeLines (-1, -1, 0, 0); calculateDocResizingGrip (); emit cancelledDocResize (); endDragScroll (); m_overlay->hide(); } //--------------------------------------------------------------------- // protected slot void kpViewScrollableContainer::slotGripEndedDraw (int viewDX, int viewDY) { #if DEBUG_KP_VIEW_SCROLLABLE_CONTAINER qCDebug(kpLogMisc) << "kpViewScrollableContainer::slotGripEndedDraw(" << viewDX << "," << viewDY << ") size=" << newDocSize (viewDX, viewDY) << endl; #endif if (!m_view) return; const QSize newSize = newDocSize (viewDX, viewDY); m_haveMovedFromOriginalDocSize = false; // must erase lines before view size changes updateResizeLines (-1, -1, 0, 0); calculateDocResizingGrip (); emit endedDocResize (newSize); endDragScroll (); m_overlay->hide(); } //--------------------------------------------------------------------- // protected slot void kpViewScrollableContainer::slotGripStatusMessageChanged (const QString &string) { if (string == m_gripStatusMessage) return; m_gripStatusMessage = string; emit statusMessageChanged (string); } //--------------------------------------------------------------------- // public slot void kpViewScrollableContainer::recalculateStatusMessage () { #if DEBUG_KP_VIEW_SCROLLABLE_CONTAINER qCDebug(kpLogMisc) << "kpViewScrollabelContainer::recalculateStatusMessage()"; qCDebug(kpLogMisc) << "\tQCursor::pos=" << QCursor::pos () << " global visibleRect=" << kpWidgetMapper::toGlobal (this, QRect(0, 0, viewport->width(), viewport->height())) << endl; #endif // HACK: After dragging to a new size, handles move so that they are now // under the mouse pointer but no mouseMoveEvent() is generated for // any grip. This also handles the case of canceling over any // grip. // if (kpWidgetMapper::toGlobal (this, QRect(0, 0, viewport()->width(), viewport()->height())) .contains (QCursor::pos ())) { if ( m_bottomRightGrip->containsCursor() ) { m_bottomRightGrip->setUserMessage (i18n ("Left drag the handle to resize the image.")); } else if ( m_bottomGrip->containsCursor() ) { m_bottomGrip->setUserMessage (i18n ("Left drag the handle to resize the image.")); } else if ( m_rightGrip->containsCursor() ) { m_rightGrip->setUserMessage (i18n ("Left drag the handle to resize the image.")); } else { clearStatusMessage (); } } else { clearStatusMessage (); } } //--------------------------------------------------------------------- // protected slot void kpViewScrollableContainer::slotContentsMoved () { kpGrip *grip = docResizingGrip (); if (grip) { grip->mouseMovedTo (grip->mapFromGlobal (QCursor::pos ()), true/*moved due to drag scroll*/); } m_overlay->move(viewport()->pos()); m_overlay->update(); emit contentsMoved(); } //--------------------------------------------------------------------- // protected void kpViewScrollableContainer::disconnectViewSignals () { disconnect (m_view, SIGNAL (sizeChanged(QSize)), this, SLOT (updateGrips())); disconnect (m_view, SIGNAL (destroyed()), this, SLOT (slotViewDestroyed())); } //--------------------------------------------------------------------- // protected void kpViewScrollableContainer::connectViewSignals () { connect (m_view, SIGNAL (sizeChanged(QSize)), this, SLOT (updateGrips())); connect (m_view, SIGNAL (destroyed()), this, SLOT (slotViewDestroyed())); } //--------------------------------------------------------------------- // public kpView *kpViewScrollableContainer::view () const { return m_view; } //--------------------------------------------------------------------- // public void kpViewScrollableContainer::setView (kpView *view) { if (m_view == view) return; if (m_view) { disconnectViewSignals (); } m_view = view; if ( m_view ) { m_view->setParent(widget()); m_view->show(); } updateGrips (); if (m_view) { connectViewSignals (); } } //--------------------------------------------------------------------- // public slot void kpViewScrollableContainer::updateGrips () { if (m_view) { widget()->resize(m_view->size() + m_bottomRightGrip->size()); // to make the grip more easily "touchable" make it as high as the view m_rightGrip->setFixedHeight(m_view->height()); m_rightGrip->move(m_view->width(), 0); // to make the grip more easily "touchable" make it as wide as the view m_bottomGrip->setFixedWidth(m_view->width()); m_bottomGrip->move(0, m_view->height ()); m_bottomRightGrip->move(m_view->width(), m_view->height()); } m_bottomGrip->setHidden (m_view == nullptr); m_rightGrip->setHidden (m_view == nullptr); m_bottomRightGrip->setHidden (m_view == nullptr); recalculateStatusMessage (); } //--------------------------------------------------------------------- // protected slot void kpViewScrollableContainer::slotViewDestroyed () { m_view = nullptr; updateGrips (); } //--------------------------------------------------------------------- // public slot bool kpViewScrollableContainer::beginDragScroll(int zoomLevel, bool *didSomething) { if (didSomething) *didSomething = false; m_zoomLevel = zoomLevel; const QPoint p = mapFromGlobal (QCursor::pos ()); bool stopDragScroll = true; bool scrolled = false; if (!noDragScrollRect ().contains (p)) { if (m_dragScrollTimer->isActive ()) { if (m_scrollTimerRunOnce) { scrolled = slotDragScroll (); } } else { m_scrollTimerRunOnce = false; m_dragScrollTimer->start (DragScrollInitialInterval); } stopDragScroll = false; } if (stopDragScroll) m_dragScrollTimer->stop (); if (didSomething) *didSomething = scrolled; return scrolled; } //--------------------------------------------------------------------- // public slot bool kpViewScrollableContainer::beginDragScroll(int zoomLevel) { return beginDragScroll(zoomLevel, nullptr/*don't want scrolled notification*/); } //--------------------------------------------------------------------- // public slot bool kpViewScrollableContainer::endDragScroll () { if (m_dragScrollTimer->isActive ()) { m_dragScrollTimer->stop (); return true; } else { return false; } } //--------------------------------------------------------------------- static int distanceFromRectToMultiplier (int dist) { if (dist < 0) return 0; else if (dist < DragDistanceFromRectMaxFor1stMultiplier) return 1; else if (dist < DragDistanceFromRectMaxFor2ndMultiplier) return 2; else return 4; } //--------------------------------------------------------------------- // protected slot bool kpViewScrollableContainer::slotDragScroll (bool *didSomething) { bool scrolled = false; if (didSomething) *didSomething = false; const QRect rect = noDragScrollRect (); const QPoint pos = mapFromGlobal (QCursor::pos ()); int dx = 0, dy = 0; int dxMultiplier = 0, dyMultiplier = 0; if (pos.x () < rect.left ()) { dx = -DragScrollNumPixels; dxMultiplier = distanceFromRectToMultiplier (rect.left () - pos.x ()); } else if (pos.x () > rect.right ()) { dx = +DragScrollNumPixels; dxMultiplier = distanceFromRectToMultiplier (pos.x () - rect.right ()); } if (pos.y () < rect.top ()) { dy = -DragScrollNumPixels; dyMultiplier = distanceFromRectToMultiplier (rect.top () - pos.y ()); } else if (pos.y () > rect.bottom ()) { dy = +DragScrollNumPixels; dyMultiplier = distanceFromRectToMultiplier (pos.y () - rect.bottom ()); } dx *= dxMultiplier;// * qMax (1, m_zoomLevel / 100); dy *= dyMultiplier;// * qMax (1, m_zoomLevel / 100); if (dx || dy) { const int oldContentsX = horizontalScrollBar()->value (), oldContentsY = verticalScrollBar()->value (); horizontalScrollBar()->setValue(oldContentsX + dx); verticalScrollBar()->setValue(oldContentsY + dy); scrolled = (oldContentsX != horizontalScrollBar()->value () || oldContentsY != verticalScrollBar()->value ()); if (scrolled) { QRegion region = QRect (horizontalScrollBar()->value (), verticalScrollBar()->value (), viewport()->width(), viewport()->height()); region -= QRect (oldContentsX, oldContentsY, viewport()->width(), viewport()->height()); // Repaint newly exposed region immediately to reduce tearing // of scrollView. m_view->repaint (region); } } m_dragScrollTimer->start (DragScrollInterval); m_scrollTimerRunOnce = true; if (didSomething) *didSomething = scrolled; return scrolled; } //--------------------------------------------------------------------- // protected slot bool kpViewScrollableContainer::slotDragScroll () { return slotDragScroll (nullptr/*don't want scrolled notification*/); } //--------------------------------------------------------------------- // protected virtual void kpViewScrollableContainer::wheelEvent (QWheelEvent *e) { e->ignore (); if (m_view) m_view->wheelEvent (e); if ( !e->isAccepted() ) QScrollArea::wheelEvent(e); } -//--------------------------------------------------------------------- +//--------------------------------------------------------------------------------- QRect kpViewScrollableContainer::noDragScrollRect () const { return QRect (DragScrollLeftTopMargin, DragScrollLeftTopMargin, width () - DragScrollLeftTopMargin - DragScrollRightBottomMargin, height () - DragScrollLeftTopMargin - DragScrollRightBottomMargin); } //--------------------------------------------------------------------- // protected virtual [base QScrollView] void kpViewScrollableContainer::resizeEvent (QResizeEvent *e) { QScrollArea::resizeEvent (e); emit resized (); } //--------------------------------------------------------------------- diff --git a/layers/selections/text/kpTextSelection_Cursor.cpp b/layers/selections/text/kpTextSelection_Cursor.cpp index 853a53ff..8d847158 100644 --- a/layers/selections/text/kpTextSelection_Cursor.cpp +++ b/layers/selections/text/kpTextSelection_Cursor.cpp @@ -1,126 +1,126 @@ /* Copyright (c) 2003-2007 Clarence Dang Copyright (c) 2010 Tasuku Suzuki 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_SELECTION 0 #include "kpTextSelection.h" #include "kpTextSelectionPrivate.h" #include "kpDefs.h" #include "kpTextStyle.h" #include "kpPreeditText.h" #include "kpLogCategories.h" #include #include // public int kpTextSelection::closestTextRowForPoint (const QPoint &point) const { if (!pointIsInTextArea (point)) return -1; const QFontMetrics fontMetrics (d->textStyle.fontMetrics ()); int row = (point.y () - textAreaRect ().y ()) / fontMetrics.lineSpacing (); - if (row >= (int) d->textLines.size ()) + if (row >= static_cast (d->textLines.size ())) row = d->textLines.size () - 1; return row; } // public int kpTextSelection::closestTextColForPoint (const QPoint &point) const { int row = closestTextRowForPoint (point); - if (row < 0 || row >= (int) d->textLines.size ()) + if (row < 0 || row >= static_cast (d->textLines.size ())) return -1; const int localX = point.x () - textAreaRect ().x (); const QFontMetrics fontMetrics (d->textStyle.fontMetrics ()); // (should be 0 but call just in case) int charLocalLeft = fontMetrics.width (d->textLines [row], 0); // OPT: binary search or guess location then move - for (int col = 0; col < (int) d->textLines [row].length (); col++) + for (int col = 0; col < static_cast (d->textLines [row].length ()); col++) { // OPT: fontMetrics::charWidth() might be faster const int nextCharLocalLeft = fontMetrics.width (d->textLines [row], col + 1); if (localX <= (charLocalLeft + nextCharLocalLeft) / 2) return col; charLocalLeft = nextCharLocalLeft; } return d->textLines [row].length ()/*past end of line*/; } //--------------------------------------------------------------------- // public QPoint kpTextSelection::pointForTextRowCol (int row, int col) const { kpPreeditText preeditText = d->preeditText; if ((row < 0 || col < 0) || (preeditText.isEmpty () && - (row >= (int) d->textLines.size () || col > (int) d->textLines [row].length ()))) + (row >= static_cast (d->textLines.size ()) || col > static_cast (d->textLines [row].length ())))) { #if DEBUG_KP_SELECTION && 1 qCDebug(kpLogLayers) << "kpTextSelection::pointForTextRowCol(" << row << "," << col << ") out of range" << " textLines='" << text () << "'" << endl; #endif return KP_INVALID_POINT; } const QFontMetrics fontMetrics (d->textStyle.fontMetrics ()); QString line = (d->textLines.count () > row) ? d->textLines[row] : QString (); if (row == preeditText.position ().y ()) { line.insert (preeditText.position ().x (), preeditText.preeditString ()); } const int x = fontMetrics.width (line.left (col)); const int y = row * fontMetrics.height () + (row >= 1 ? row * fontMetrics.leading () : 0); return textAreaRect ().topLeft () + QPoint (x, y); } //--------------------------------------------------------------------- diff --git a/layers/tempImage/kpTempImage.cpp b/layers/tempImage/kpTempImage.cpp index a1084e04..7a16dc54 100644 --- a/layers/tempImage/kpTempImage.cpp +++ b/layers/tempImage/kpTempImage.cpp @@ -1,218 +1,218 @@ /* Copyright (c) 2003-2007 Clarence Dang All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include "layers/tempImage/kpTempImage.h" #include "pixmapfx/kpPixmapFX.h" #include "views/manager/kpViewManager.h" #include //--------------------------------------------------------------------- kpTempImage::kpTempImage (bool isBrush, RenderMode renderMode, const QPoint &topLeft, const kpImage &image) : m_isBrush (isBrush), m_renderMode (renderMode), m_topLeft (topLeft), m_image (image), m_width (image.width ()), m_height (image.height ()), m_userFunction (nullptr), m_userData (nullptr) { // Use below constructor for that. Q_ASSERT (renderMode != UserFunction); } //--------------------------------------------------------------------- kpTempImage::kpTempImage (bool isBrush, const QPoint &topLeft, UserFunctionType userFunction, void *userData, int width, int height) : m_isBrush (isBrush), m_renderMode (UserFunction), m_topLeft (topLeft), m_width (width), m_height (height), m_userFunction (userFunction), m_userData (userData) { Q_ASSERT (m_userFunction); } //--------------------------------------------------------------------- kpTempImage::kpTempImage (const kpTempImage &rhs) : m_isBrush (rhs.m_isBrush), m_renderMode (rhs.m_renderMode), m_topLeft (rhs.m_topLeft), m_image (rhs.m_image), m_width (rhs.m_width), m_height (rhs.m_height), m_userFunction (rhs.m_userFunction), m_userData (rhs.m_userData) { } //--------------------------------------------------------------------- kpTempImage &kpTempImage::operator= (const kpTempImage &rhs) { if (this == &rhs) return *this; m_isBrush = rhs.m_isBrush; m_renderMode = rhs.m_renderMode; m_topLeft = rhs.m_topLeft; m_image = rhs.m_image; m_width = rhs.m_width; m_height = rhs.m_height; m_userFunction = rhs.m_userFunction; m_userData = rhs.m_userData; return *this; } //--------------------------------------------------------------------- // public bool kpTempImage::isBrush () const { return m_isBrush; } //--------------------------------------------------------------------- // public kpTempImage::RenderMode kpTempImage::renderMode () const { return m_renderMode; } //--------------------------------------------------------------------- // public QPoint kpTempImage::topLeft () const { return m_topLeft; } //--------------------------------------------------------------------- // public kpImage kpTempImage::image () const { return m_image; } //--------------------------------------------------------------------- // public kpTempImage::UserFunctionType kpTempImage::userFunction () const { return m_userFunction; } //--------------------------------------------------------------------- // public void *kpTempImage::userData () const { return m_userData; } //--------------------------------------------------------------------- // public bool kpTempImage::isVisible (const kpViewManager *vm) const { - return m_isBrush ? (bool) vm->viewUnderCursor () : true; + return m_isBrush ? static_cast (vm->viewUnderCursor ()) : true; } //--------------------------------------------------------------------- // public QRect kpTempImage::rect () const { return QRect (m_topLeft.x (), m_topLeft.y (), m_width, m_height); } //--------------------------------------------------------------------- // public int kpTempImage::width () const { return m_width; } //--------------------------------------------------------------------- // public int kpTempImage::height () const { return m_height; } //--------------------------------------------------------------------- // public bool kpTempImage::paintMayAddMask () const { return (m_renderMode == SetImage || m_renderMode == UserFunction); } //--------------------------------------------------------------------- // public void kpTempImage::paint (kpImage *destImage, const QRect &docRect) const { const QPoint REL_TOP_LEFT = m_topLeft - docRect.topLeft (); switch (m_renderMode) { case SetImage: { kpPixmapFX::setPixmapAt(destImage, REL_TOP_LEFT, m_image); break; } case PaintImage: { kpPixmapFX::paintPixmapAt(destImage, REL_TOP_LEFT, m_image); break; } case UserFunction: { m_userFunction(destImage, REL_TOP_LEFT, m_userData); break; } } } //--------------------------------------------------------------------- diff --git a/mainWindow/kpMainWindow_Edit.cpp b/mainWindow/kpMainWindow_Edit.cpp index 27827bec..b230c5d8 100644 --- a/mainWindow/kpMainWindow_Edit.cpp +++ b/mainWindow/kpMainWindow_Edit.cpp @@ -1,919 +1,919 @@ /* Copyright (c) 2003-2007 Clarence Dang Copyright (c) 2011 Martin Koller All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include "kpMainWindow.h" #include "kpMainWindowPrivate.h" #include #include #include #include #include #include #include #include #include "kpLogCategories.h" #include #include #include #include #include #include "layers/selections/image/kpAbstractImageSelection.h" #include "widgets/toolbars/kpColorToolBar.h" #include "commands/kpCommandHistory.h" #include "document/kpDocument.h" #include "imagelib/kpDocumentMetaInfo.h" #include "document/kpDocumentSaveOptions.h" #include "layers/selections/image/kpImageSelectionTransparency.h" #include "commands/kpMacroCommand.h" #include "pixmapfx/kpPixmapFX.h" #include "layers/selections/image/kpRectangularImageSelection.h" #include "layers/selections/kpSelectionDrag.h" #include "generic/kpSetOverrideCursorSaver.h" #include "layers/selections/text/kpTextSelection.h" #include "tools/kpTool.h" #include "commands/tools/selection/text/kpToolTextGiveContentCommand.h" #include "commands/tools/selection/kpToolSelectionCreateCommand.h" #include "commands/tools/selection/kpToolSelectionDestroyCommand.h" #include "commands/tools/selection/text/kpToolTextEnterCommand.h" #include "commands/tools/selection/text/kpToolTextInsertCommand.h" #include "imagelib/transforms/kpTransformCrop.h" #include "commands/imagelib/transforms/kpTransformResizeScaleCommand.h" #include "views/manager/kpViewManager.h" #include "kpViewScrollableContainer.h" #include "views/kpZoomedView.h" //--------------------------------------------------------------------- // private void kpMainWindow::setupEditMenuActions () { KActionCollection *ac = actionCollection (); // Undo/Redo // CONFIG: Need GUI for config history size. d->commandHistory = new kpCommandHistory (true/*read config*/, this); if (d->configFirstTime) { // (so that cfg-file-editing user can modify in the meantime) d->commandHistory->writeConfig (); } d->actionCut = KStandardAction::cut (this, SLOT (slotCut()), ac); d->actionCopy = KStandardAction::copy (this, SLOT (slotCopy()), ac); d->actionPaste = KStandardAction::paste (this, SLOT (slotPaste()), ac); d->actionPasteInNewWindow = ac->addAction ("edit_paste_in_new_window"); d->actionPasteInNewWindow->setText (i18n ("Paste in &New Window")); connect (d->actionPasteInNewWindow, SIGNAL (triggered(bool)), SLOT (slotPasteInNewWindow())); ac->setDefaultShortcut (d->actionPasteInNewWindow, Qt::CTRL + Qt::SHIFT + Qt::Key_V); //d->actionDelete = KStandardAction::clear (this, SLOT (slotDelete()), ac); d->actionDelete = ac->addAction ("edit_clear"); d->actionDelete->setText (i18n ("&Delete Selection")); connect (d->actionDelete, SIGNAL (triggered(bool)), SLOT (slotDelete())); d->actionSelectAll = KStandardAction::selectAll (this, SLOT (slotSelectAll()), ac); d->actionDeselect = KStandardAction::deselect (this, SLOT (slotDeselect()), ac); d->actionCopyToFile = ac->addAction ("edit_copy_to_file"); d->actionCopyToFile->setText (i18n ("C&opy to File...")); connect (d->actionCopyToFile, SIGNAL (triggered(bool)), SLOT (slotCopyToFile())); d->actionPasteFromFile = ac->addAction ("edit_paste_from_file"); d->actionPasteFromFile->setText (i18n ("Paste &From File...")); connect (d->actionPasteFromFile, SIGNAL (triggered(bool)), SLOT (slotPasteFromFile())); d->editMenuDocumentActionsEnabled = false; enableEditMenuDocumentActions (false); // Paste should always be enabled, as long as there is something to paste // (independent of whether we have a document or not) connect (QApplication::clipboard (), SIGNAL (dataChanged()), this, SLOT (slotEnablePaste())); slotEnablePaste (); } //--------------------------------------------------------------------- // private void kpMainWindow::enableEditMenuDocumentActions (bool enable) { // d->actionCut // d->actionCopy // d->actionPaste // d->actionPasteInNewWindow // d->actionDelete d->actionSelectAll->setEnabled (enable); // d->actionDeselect d->editMenuDocumentActionsEnabled = enable; // d->actionCopyToFile // Unlike d->actionPaste, we disable this if there is no document. // This is because "File / Open" would do the same thing, if there is // no document. d->actionPasteFromFile->setEnabled (enable); } //--------------------------------------------------------------------- // public QMenu *kpMainWindow::selectionToolRMBMenu () { return qobject_cast (guiFactory ()->container ("selectionToolRMBMenu", this)); } //--------------------------------------------------------------------- // private slot void kpMainWindow::slotCut () { #if DEBUG_KP_MAIN_WINDOW && 1 qCDebug(kpLogMainWindow) << "kpMainWindow::slotCut() CALLED"; #endif kpSetOverrideCursorSaver cursorSaver (Qt::WaitCursor); Q_ASSERT (d->document && d->document->selection ()); toolEndShape (); slotCopy (); slotDelete (); } //--------------------------------------------------------------------- static QMimeData *NewTextMimeData (const QString &text) { QMimeData *md = new QMimeData (); md->setText (text); return md; } //--------------------------------------------------------------------- // private slot void kpMainWindow::slotCopy () { #if DEBUG_KP_MAIN_WINDOW && 1 qCDebug(kpLogMainWindow) << "kpMainWindow::slotCopy() CALLED"; #endif kpSetOverrideCursorSaver cursorSaver (Qt::WaitCursor); Q_ASSERT (d->document && d->document->selection ()); toolEndShape (); kpAbstractSelection *sel = d->document->selection ()->clone (); if (dynamic_cast (sel)) { kpTextSelection *textSel = static_cast (sel); if (!textSel->text ().isEmpty ()) { QApplication::clipboard ()->setMimeData ( ::NewTextMimeData (textSel->text ()), QClipboard::Clipboard); // SYNC: Normally, users highlight text and press CTRL+C. // Highlighting text copies it to the X11 "middle // mouse button" clipboard. CTRL+C copies it to the // separate, Windows-like "CTRL+V" clipboard. // // However, KolourPaint doesn't support highlighting. // So when they press CTRL+C to copy all text, simulate // the highlighting by copying the text to the "middle // mouse button" clipboard. We don't do this for images // as no one ever middle-mouse-pastes images. // // Note that we don't share the QMimeData pointer with // the above in case Qt doesn't expect it. // // Once we change KolourPaint to support highlighted text // and CTRL+C to copy only the highlighted text, delete // this code. QApplication::clipboard ()->setMimeData ( ::NewTextMimeData (textSel->text ()), QClipboard::Selection); } } else if (dynamic_cast (sel)) { kpAbstractImageSelection *imageSel = static_cast (sel); // Transparency doesn't get sent across the aether so nuke it now // so that transparency mask doesn't get needlessly recalculated // if we ever call sel.setBaseImage(). imageSel->setTransparency (kpImageSelectionTransparency ()); kpImage rawImage; if (imageSel->hasContent ()) rawImage = imageSel->baseImage (); else rawImage = d->document->getSelectedBaseImage (); imageSel->setBaseImage ( rawImage ); QApplication::clipboard ()->setMimeData ( new kpSelectionDrag (*imageSel), QClipboard::Clipboard); } else Q_ASSERT (!"Unknown selection type"); delete sel; } //--------------------------------------------------------------------- // private slot void kpMainWindow::slotEnablePaste () { const QMimeData *md = QApplication::clipboard()->mimeData(QClipboard::Clipboard); // It's faster to test for QMimeData::hasText() first due to the // lazy evaluation of the '||' operator. const bool shouldEnable = md && (md->hasText() || kpSelectionDrag::canDecode(md)); d->actionPasteInNewWindow->setEnabled(shouldEnable); d->actionPaste->setEnabled(shouldEnable); } //--------------------------------------------------------------------- // private QRect kpMainWindow::calcUsefulPasteRect (int imageWidth, int imageHeight) { #if DEBUG_KP_MAIN_WINDOW && 1 qCDebug(kpLogMainWindow) << "kpMainWindow::calcUsefulPasteRect(" << imageWidth << "," << imageHeight << ")" << endl; #endif Q_ASSERT (d->document); // TODO: 1st choice is to paste sel near but not overlapping last deselect point if (d->mainView && d->scrollView) { const QPoint viewTopLeft (d->scrollView->horizontalScrollBar()->value (), d->scrollView->verticalScrollBar()->value ()); const QPoint docTopLeft = d->mainView->transformViewToDoc (viewTopLeft); if ((docTopLeft.x () + imageWidth <= d->document->width () && docTopLeft.y () + imageHeight <= d->document->height ()) || imageWidth <= docTopLeft.x () || imageHeight <= docTopLeft.y ()) { return QRect (docTopLeft.x (), docTopLeft.y (), imageWidth, imageHeight); } } return QRect (0, 0, imageWidth, imageHeight); } //--------------------------------------------------------------------- // private void kpMainWindow::paste(const kpAbstractSelection &sel, bool forceTopLeft) { #if DEBUG_KP_MAIN_WINDOW && 1 qCDebug(kpLogMainWindow) << "kpMainWindow::paste(forceTopLeft=" << forceTopLeft << ")" << endl; #endif kpSetOverrideCursorSaver cursorSaver (Qt::WaitCursor); toolEndShape (); // // Make sure we've got a document (esp. with File/Close) // if (!d->document) { kpDocument *newDoc = new kpDocument ( sel.width (), sel.height (), documentEnvironment ()); // will also create viewManager setDocument (newDoc); } // // Paste as new selection // const kpAbstractImageSelection *imageSel = dynamic_cast (&sel); if (imageSel && imageSel->hasContent () && imageSel->transparency ().isTransparent ()) { d->colorToolBar->flashColorSimilarityToolBarItem (); } kpAbstractSelection *selInUsefulPos = sel.clone (); if (!forceTopLeft) selInUsefulPos->moveTo (calcUsefulPasteRect (sel.width (), sel.height ()).topLeft ()); // TODO: Should use kpCommandHistory::addCreateSelectionCommand(), // as well, to really support pasting selection borders. addDeselectFirstCommand (new kpToolSelectionCreateCommand ( dynamic_cast (selInUsefulPos) ? i18n ("Text: Create Box") : i18n ("Selection: Create"), *selInUsefulPos, commandEnvironment ())); delete selInUsefulPos; #if DEBUG_KP_MAIN_WINDOW && 1 qCDebug(kpLogMainWindow) << "sel.size=" << QSize (sel.width (), sel.height ()) << " document.size=" << QSize (d->document->width (), d->document->height ()) << endl; #endif // If the selection is bigger than the document, automatically // resize the document (with the option of Undo'ing) to fit // the selection. // // No annoying dialog necessary. // if (sel.width () > d->document->width () || sel.height () > d->document->height ()) { d->commandHistory->addCommand ( new kpTransformResizeScaleCommand ( false/*act on doc, not sel*/, qMax (sel.width (), d->document->width ()), qMax (sel.height (), d->document->height ()), kpTransformResizeScaleCommand::Resize, commandEnvironment ())); } } //--------------------------------------------------------------------- // public void kpMainWindow::pasteText (const QString &text, bool forceNewTextSelection, const QPoint &newTextSelectionTopLeft) { #if DEBUG_KP_MAIN_WINDOW && 1 qCDebug(kpLogMainWindow) << "kpMainWindow::pasteText(" << text << ",forceNewTextSelection=" << forceNewTextSelection << ",newTextSelectionTopLeft=" << newTextSelectionTopLeft << ")" << endl; #endif if ( text.isEmpty() ) return; kpSetOverrideCursorSaver cursorSaver (Qt::WaitCursor); toolEndShape (); QStringList textLines = text.split('\n'); if (!forceNewTextSelection && d->document && d->document->textSelection () && d->commandHistory && d->viewManager) { #if DEBUG_KP_MAIN_WINDOW && 1 qCDebug(kpLogMainWindow) << "\treusing existing Text Selection"; #endif d->viewManager->setQueueUpdates(); kpTextSelection *textSel = d->document->textSelection (); if (!textSel->hasContent ()) { #if DEBUG_KP_MAIN_WINDOW && 1 qCDebug(kpLogMainWindow) << "\t\tneeds content"; #endif commandHistory ()->addCreateSelectionCommand ( new kpToolSelectionCreateCommand ( i18n ("Text: Create Box"), *textSel, commandEnvironment ()), false/*no exec*/); } kpMacroCommand *macroCmd = new kpMacroCommand (i18n ("Text: Paste"), commandEnvironment ()); // (yes, this is the same check as the previous "if") if (!textSel->hasContent ()) { kpCommand *giveContentCmd = new kpToolTextGiveContentCommand ( *textSel, QString ()/*uninteresting child of macro cmd*/, commandEnvironment ()); giveContentCmd->execute (); macroCmd->addCommand (giveContentCmd); } - for (int i = 0; i < (int) textLines.size (); i++) + for (int i = 0; i < static_cast (textLines.size ()); i++) { if (i > 0) { macroCmd->addCommand ( new kpToolTextEnterCommand ( QString()/*uninteresting child of macroCmd*/, d->viewManager->textCursorRow (), d->viewManager->textCursorCol (), kpToolTextEnterCommand::AddEnterNow, commandEnvironment ())); } macroCmd->addCommand ( new kpToolTextInsertCommand ( QString()/*uninteresting child of macroCmd*/, d->viewManager->textCursorRow (), d->viewManager->textCursorCol (), textLines [i], commandEnvironment ())); } d->commandHistory->addCommand (macroCmd, false/*no exec*/); d->viewManager->restoreQueueUpdates(); } else { #if DEBUG_KP_MAIN_WINDOW && 1 qCDebug(kpLogMainWindow) << "\tcreating Text Selection"; #endif const kpTextStyle ts = textStyle (); const QFontMetrics fontMetrics = ts.fontMetrics (); int height = textLines.size () * fontMetrics.height (); if (textLines.size () >= 1) height += (textLines.size () - 1) * fontMetrics.leading (); int width = 0; for (QList ::const_iterator it = textLines.constBegin (); it != textLines.constEnd (); ++it) { const int w = fontMetrics.width (*it); if (w > width) width = w; } // limit the size to avoid memory overflow width = qMin(qMax(QApplication::desktop()->width(), d->document ? d->document->width() : 0), width); height = qMin(qMax(QApplication::desktop()->height(), d->document ? d->document->height() : 0), height); const int selWidth = qMax (kpTextSelection::MinimumWidthForTextStyle (ts), width + kpTextSelection::TextBorderSize () * 2); const int selHeight = qMax (kpTextSelection::MinimumHeightForTextStyle (ts), height + kpTextSelection::TextBorderSize () * 2); kpTextSelection newTextSel (QRect (0, 0, selWidth, selHeight), textLines, ts); if (newTextSelectionTopLeft != KP_INVALID_POINT) { newTextSel.moveTo (newTextSelectionTopLeft); paste (newTextSel, true/*force topLeft*/); } else { paste (newTextSel); } } } //--------------------------------------------------------------------- // public void kpMainWindow::pasteTextAt (const QString &text, const QPoint &point, bool allowNewTextSelectionPointShift) { #if DEBUG_KP_MAIN_WINDOW && 1 qCDebug(kpLogMainWindow) << "kpMainWindow::pasteTextAt(" << text << ",point=" << point << ",allowNewTextSelectionPointShift=" << allowNewTextSelectionPointShift << ")" << endl; #endif kpSetOverrideCursorSaver cursorSaver (Qt::WaitCursor); toolEndShape (); if (d->document && d->document->textSelection () && d->document->textSelection ()->pointIsInTextArea (point)) { kpTextSelection *textSel = d->document->textSelection (); int row, col; if (textSel->hasContent ()) { row = textSel->closestTextRowForPoint (point); col = textSel->closestTextColForPoint (point); } else { row = col = 0; } d->viewManager->setTextCursorPosition (row, col); pasteText (text); } else { QPoint pointToUse = point; if (allowNewTextSelectionPointShift) { // TODO: In terms of doc pixels, would be inconsistent behaviour // based on zoomLevel of view. // pointToUse -= QPoint (-view->selectionResizeHandleAtomicSize (), // -view->selectionResizeHandleAtomicSize ()); } pasteText (text, true/*force new text selection*/, pointToUse); } } //--------------------------------------------------------------------- // public slot void kpMainWindow::slotPaste() { kpSetOverrideCursorSaver cursorSaver(Qt::WaitCursor); toolEndShape(); const QMimeData *mimeData = QApplication::clipboard()->mimeData(QClipboard::Clipboard); kpAbstractImageSelection *sel = kpSelectionDrag::decode(mimeData); if ( sel ) { sel->setTransparency(imageSelectionTransparency()); paste(*sel); delete sel; } else if ( mimeData->hasText() ) { pasteText(mimeData->text()); } else { kpSetOverrideCursorSaver cursorSaver(Qt::ArrowCursor); KMessageBox::sorry(this, i18n("KolourPaint cannot paste the contents of" " the clipboard as it has an unknown format."), i18n("Cannot Paste")); } } //--------------------------------------------------------------------- // private slot void kpMainWindow::slotPasteInNewWindow () { #if DEBUG_KP_MAIN_WINDOW && 1 qCDebug(kpLogMainWindow) << "kpMainWindow::slotPasteInNewWindow() CALLED"; #endif kpSetOverrideCursorSaver cursorSaver (Qt::WaitCursor); toolEndShape (); // // Pasting must ensure that: // // Requirement 1. the document is the same size as the image to be pasted. // Requirement 2. transparent pixels in the image must remain as transparent. // kpMainWindow *win = new kpMainWindow (nullptr/*no document*/); win->show (); // Make "Edit / Paste in New Window" always paste white pixels as white. // Don't let selection transparency get in the way and paste them as // transparent. kpImageSelectionTransparency transparency = win->imageSelectionTransparency (); if (transparency.isTransparent ()) { #if DEBUG_KP_MAIN_WINDOW && 1 qCDebug(kpLogMainWindow) << "\tchanging image selection transparency to opaque"; #endif transparency.setOpaque (); // Since we are setting selection transparency programmatically // -- as opposed to in response to user input -- this will not // affect the selection transparency tool option widget's "last used" // config setting. win->setImageSelectionTransparency (transparency); } // (this handles Requirement 1. above) win->slotPaste (); // if slotPaste could not decode clipboard data, no document was created if ( win->document() ) { // (this handles Requirement 2. above; // slotDeselect() is not enough unless the document is filled with the // transparent color in advance) win->slotCrop(); } } //--------------------------------------------------------------------- // public slot void kpMainWindow::slotDelete () { #if DEBUG_KP_MAIN_WINDOW && 1 qCDebug(kpLogMainWindow) << "kpMainWindow::slotDelete() CALLED"; #endif if (!d->actionDelete->isEnabled ()) { #if DEBUG_KP_MAIN_WINDOW && 1 qCDebug(kpLogMainWindow) << "\taction not enabled - was probably called from kpTool::keyPressEvent()"; #endif return; } Q_ASSERT (d->document && d->document->selection ()); toolEndShape (); addImageOrSelectionCommand (new kpToolSelectionDestroyCommand ( d->document->textSelection () ? i18n ("Text: Delete Box") : // not to be confused with i18n ("Text: Delete") i18n ("Selection: Delete"), false/*no push onto doc*/, commandEnvironment ())); } //--------------------------------------------------------------------- // private slot void kpMainWindow::slotSelectAll () { #if DEBUG_KP_MAIN_WINDOW && 1 qCDebug(kpLogMainWindow) << "kpMainWindow::slotSelectAll() CALLED"; #endif Q_ASSERT (d->document); toolEndShape (); if (d->document->selection ()) slotDeselect (); // just the border - don't actually pull image from doc yet d->document->setSelection ( kpRectangularImageSelection (d->document->rect (), imageSelectionTransparency ())); if (tool ()) tool ()->somethingBelowTheCursorChanged (); } //--------------------------------------------------------------------- // private void kpMainWindow::addDeselectFirstCommand (kpCommand *cmd) { #if DEBUG_KP_MAIN_WINDOW && 1 qCDebug(kpLogMainWindow) << "kpMainWindow::addDeselectFirstCommand(" << cmd << ")" << endl; #endif kpAbstractSelection *sel = d->document->selection (); #if DEBUG_KP_MAIN_WINDOW && 1 qCDebug(kpLogMainWindow) << "\tsel=" << sel; #endif if (sel) { // if you just dragged out something with no action then // forget the drag if (!sel->hasContent ()) { #if DEBUG_KP_MAIN_WINDOW && 1 qCDebug(kpLogMainWindow) << "\tjust a fresh border - was nop - delete"; #endif d->document->selectionDelete (); if (tool ()) tool ()->somethingBelowTheCursorChanged (); if (cmd) d->commandHistory->addCommand (cmd); } else { #if DEBUG_KP_MAIN_WINDOW && 1 qCDebug(kpLogMainWindow) << "\treal selection with image - push onto doc cmd"; #endif kpCommand *deselectCommand = new kpToolSelectionDestroyCommand ( dynamic_cast (sel) ? i18n ("Text: Finish") : i18n ("Selection: Deselect"), true/*push onto document*/, commandEnvironment ()); if (cmd) { kpMacroCommand *macroCmd = new kpMacroCommand (cmd->name (), commandEnvironment ()); macroCmd->addCommand (deselectCommand); macroCmd->addCommand (cmd); d->commandHistory->addCommand (macroCmd); } else d->commandHistory->addCommand (deselectCommand); } } else { if (cmd) d->commandHistory->addCommand (cmd); } } //--------------------------------------------------------------------- // public slot void kpMainWindow::slotDeselect () { #if DEBUG_KP_MAIN_WINDOW && 1 qCDebug(kpLogMainWindow) << "kpMainWindow::slotDeselect() CALLED"; #endif Q_ASSERT (d->document && d->document->selection ()); toolEndShape (); addDeselectFirstCommand (nullptr); } //--------------------------------------------------------------------- // private slot void kpMainWindow::slotCopyToFile () { #if DEBUG_KP_MAIN_WINDOW qCDebug(kpLogMainWindow) << "kpMainWindow::slotCopyToFile()"; #endif toolEndShape (); if (!d->document->selection ()) return; kpImage imageToSave; if (d->document->imageSelection ()) { kpAbstractImageSelection *imageSel = d->document->imageSelection (); if (!imageSel->hasContent ()) { // Not a floating selection - user has just selected a region; // haven't pulled it off yet so probably don't expect and can't // visualize selection transparency so give opaque, not transparent // image. imageToSave = d->document->getSelectedBaseImage (); } else imageToSave = imageSel->transparentImage (); } else if (d->document->textSelection ()) { imageToSave = d->document->textSelection ()->approximateImage (); } else Q_ASSERT (!"Unknown selection type"); kpDocumentSaveOptions chosenSaveOptions; bool allowOverwritePrompt, allowLossyPrompt; QUrl chosenURL = askForSaveURL (i18nc ("@title:window", "Copy to File"), d->lastCopyToURL.url (), imageToSave, d->lastCopyToSaveOptions, kpDocumentMetaInfo (), kpSettingsGroupEditCopyTo, false/*allow remote files*/, &chosenSaveOptions, d->copyToFirstTime, &allowOverwritePrompt, &allowLossyPrompt); if (chosenURL.isEmpty ()) return; if (!kpDocument::savePixmapToFile (imageToSave, chosenURL, chosenSaveOptions, kpDocumentMetaInfo (), allowOverwritePrompt, allowLossyPrompt, this)) { return; } addRecentURL (chosenURL); d->lastCopyToURL = chosenURL; d->lastCopyToSaveOptions = chosenSaveOptions; d->copyToFirstTime = false; } //--------------------------------------------------------------------- // private slot void kpMainWindow::slotPasteFromFile () { #if DEBUG_KP_MAIN_WINDOW qCDebug(kpLogMainWindow) << "kpMainWindow::slotPasteFromFile()"; #endif toolEndShape (); QList urls = askForOpenURLs(i18nc ("@title:window", "Paste From File"), false/*only 1 URL*/); if (urls.count () != 1) return; QUrl url = urls.first (); kpImage image = kpDocument::getPixmapFromFile (url, false/*show error message if doesn't exist*/, this); if (image.isNull ()) return; addRecentURL (url); paste (kpRectangularImageSelection ( QRect (0, 0, image.width (), image.height ()), image, imageSelectionTransparency ())); } //--------------------------------------------------------------------- diff --git a/mainWindow/kpMainWindow_Image.cpp b/mainWindow/kpMainWindow_Image.cpp index 56d088df..6248a1f9 100644 --- a/mainWindow/kpMainWindow_Image.cpp +++ b/mainWindow/kpMainWindow_Image.cpp @@ -1,619 +1,619 @@ /* Copyright (c) 2003-2007 Clarence Dang All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include "mainWindow/kpMainWindow.h" #include "kpMainWindowPrivate.h" #include "layers/selections/image/kpAbstractImageSelection.h" #include "imagelib/kpColor.h" #include "kpDefs.h" #include "widgets/toolbars/kpColorToolBar.h" #include "commands/kpCommandHistory.h" #include "document/kpDocument.h" #include "commands/imagelib/effects/kpEffectInvertCommand.h" #include "commands/imagelib/effects/kpEffectReduceColorsCommand.h" #include "dialogs/imagelib/effects/kpEffectsDialog.h" #include "commands/imagelib/effects/kpEffectClearCommand.h" #include "commands/imagelib/effects/kpEffectGrayscaleCommand.h" #include "commands/kpMacroCommand.h" #include "layers/selections/text/kpTextSelection.h" #include "commands/tools/selection/kpToolSelectionCreateCommand.h" #include "commands/tools/selection/kpToolSelectionPullFromDocumentCommand.h" #include "commands/tools/selection/text/kpToolTextGiveContentCommand.h" #include "imagelib/transforms/kpTransformAutoCrop.h" #include "imagelib/transforms/kpTransformCrop.h" #include "environments/dialogs/imagelib/transforms/kpTransformDialogEnvironment.h" #include "commands/imagelib/transforms/kpTransformFlipCommand.h" #include "commands/imagelib/transforms/kpTransformResizeScaleCommand.h" #include "dialogs/imagelib/transforms/kpTransformResizeScaleDialog.h" #include "commands/imagelib/transforms/kpTransformRotateCommand.h" #include "dialogs/imagelib/transforms/kpTransformRotateDialog.h" #include "commands/imagelib/transforms/kpTransformSkewCommand.h" #include "dialogs/imagelib/transforms/kpTransformSkewDialog.h" #include "views/manager/kpViewManager.h" #include "commands/imagelib/effects/kpEffectBlurSharpenCommand.h" #include "imagelib/effects/kpEffectBlurSharpen.h" #include "kpLogCategories.h" #include #include #include #include #include #include #include #include //--------------------------------------------------------------------- // private kpTransformDialogEnvironment *kpMainWindow::transformDialogEnvironment () { if (!d->transformDialogEnvironment) d->transformDialogEnvironment = new kpTransformDialogEnvironment (this); return d->transformDialogEnvironment; } //--------------------------------------------------------------------- // private bool kpMainWindow::isSelectionActive () const { return (d->document ? bool (d->document->selection ()) : false); } //--------------------------------------------------------------------- // private bool kpMainWindow::isTextSelection () const { return (d->document && d->document->textSelection ()); } //--------------------------------------------------------------------- // private QString kpMainWindow::autoCropText () const { return kpTransformAutoCropCommand::text(isSelectionActive(), kpTransformAutoCropCommand::ShowAccel); } //--------------------------------------------------------------------- // private void kpMainWindow::setupImageMenuActions () { KActionCollection *ac = actionCollection (); d->actionResizeScale = ac->addAction ("image_resize_scale"); d->actionResizeScale->setText (i18n ("R&esize / Scale...")); connect (d->actionResizeScale, SIGNAL (triggered(bool)), SLOT (slotResizeScale())); ac->setDefaultShortcut (d->actionResizeScale, Qt::CTRL + Qt::Key_E); d->actionCrop = ac->addAction ("image_crop"); d->actionCrop->setText (i18n ("Se&t as Image (Crop)")); connect (d->actionCrop, SIGNAL (triggered(bool)), SLOT (slotCrop())); ac->setDefaultShortcut (d->actionCrop, Qt::CTRL + Qt::Key_T); d->actionAutoCrop = ac->addAction ("image_auto_crop"); d->actionAutoCrop->setText (autoCropText ()); connect (d->actionAutoCrop, SIGNAL (triggered(bool)), SLOT (slotAutoCrop())); ac->setDefaultShortcut (d->actionAutoCrop, Qt::CTRL + Qt::Key_U); d->actionFlip = ac->addAction ("image_flip"); d->actionFlip->setText (i18n ("&Flip (upside down)")); connect (d->actionFlip, SIGNAL (triggered(bool)), SLOT (slotFlip())); ac->setDefaultShortcut (d->actionFlip, Qt::CTRL + Qt::Key_F); d->actionMirror = ac->addAction ("image_mirror"); d->actionMirror->setText (i18n ("Mirror (horizontally)")); connect (d->actionMirror, SIGNAL (triggered(bool)), SLOT (slotMirror())); //ac->setDefaultShortcut (d->actionMirror, Qt::CTRL + Qt::Key_M); d->actionRotate = ac->addAction ("image_rotate"); d->actionRotate->setText (i18n ("&Rotate...")); d->actionRotate->setIcon(KDE::icon("transform-rotate")); connect (d->actionRotate, SIGNAL (triggered(bool)), SLOT (slotRotate())); ac->setDefaultShortcut (d->actionRotate, Qt::CTRL + Qt::Key_R); d->actionRotateLeft = ac->addAction ("image_rotate_270deg"); d->actionRotateLeft->setText (i18n ("Rotate &Left")); d->actionRotateLeft->setIcon(KDE::icon("object-rotate-left")); connect (d->actionRotateLeft, SIGNAL (triggered(bool)), SLOT (slotRotate270())); ac->setDefaultShortcut (d->actionRotateLeft, Qt::CTRL + Qt::SHIFT + Qt::Key_Left); d->actionRotateRight = ac->addAction ("image_rotate_90deg"); d->actionRotateRight->setText (i18n ("Rotate Righ&t")); d->actionRotateRight->setIcon(KDE::icon("object-rotate-right")); connect (d->actionRotateRight, SIGNAL (triggered(bool)), SLOT (slotRotate90())); ac->setDefaultShortcut (d->actionRotateRight, Qt::CTRL + Qt::SHIFT + Qt::Key_Right); d->actionSkew = ac->addAction ("image_skew"); d->actionSkew->setText (i18n ("S&kew...")); connect (d->actionSkew, SIGNAL (triggered(bool)), SLOT (slotSkew())); ac->setDefaultShortcut (d->actionSkew, Qt::CTRL + Qt::Key_K); d->actionConvertToBlackAndWhite = ac->addAction ("image_convert_to_black_and_white"); d->actionConvertToBlackAndWhite->setText (i18n ("Reduce to Mo&nochrome (Dithered)")); connect (d->actionConvertToBlackAndWhite, SIGNAL (triggered(bool)), SLOT (slotConvertToBlackAndWhite())); d->actionConvertToGrayscale = ac->addAction ("image_convert_to_grayscale"); d->actionConvertToGrayscale->setText (i18n ("Reduce to &Grayscale")); connect (d->actionConvertToGrayscale, SIGNAL (triggered(bool)), SLOT (slotConvertToGrayscale())); d->actionInvertColors = ac->addAction ("image_invert_colors"); d->actionInvertColors->setText (i18n ("&Invert Colors")); connect (d->actionInvertColors, SIGNAL (triggered(bool)), SLOT (slotInvertColors())); ac->setDefaultShortcut (d->actionInvertColors, Qt::CTRL + Qt::Key_I); d->actionClear = ac->addAction ("image_clear"); d->actionClear->setText (i18n ("C&lear")); connect (d->actionClear, SIGNAL (triggered(bool)), SLOT (slotClear())); ac->setDefaultShortcut (d->actionClear, Qt::CTRL + Qt::SHIFT + Qt::Key_N); d->actionBlur = ac->addAction("image_make_confidential"); d->actionBlur->setText(i18n("Make Confidential")); connect(d->actionBlur, SIGNAL(triggered(bool)), SLOT(slotMakeConfidential())); d->actionMoreEffects = ac->addAction ("image_more_effects"); d->actionMoreEffects->setText (i18n ("&More Effects...")); connect (d->actionMoreEffects, SIGNAL (triggered(bool)), SLOT (slotMoreEffects())); ac->setDefaultShortcut (d->actionMoreEffects, Qt::CTRL + Qt::Key_M); enableImageMenuDocumentActions (false); } //--------------------------------------------------------------------- // private void kpMainWindow::enableImageMenuDocumentActions (bool enable) { d->actionResizeScale->setEnabled (enable); d->actionCrop->setEnabled (enable); d->actionAutoCrop->setEnabled (enable); d->actionFlip->setEnabled (enable); d->actionMirror->setEnabled (enable); d->actionRotate->setEnabled (enable); d->actionRotateLeft->setEnabled (enable); d->actionRotateRight->setEnabled (enable); d->actionSkew->setEnabled (enable); d->actionConvertToBlackAndWhite->setEnabled (enable); d->actionConvertToGrayscale->setEnabled (enable); d->actionInvertColors->setEnabled (enable); d->actionClear->setEnabled (enable); d->actionBlur->setEnabled (enable); d->actionMoreEffects->setEnabled (enable); d->imageMenuDocumentActionsEnabled = enable; } //--------------------------------------------------------------------- // private slot void kpMainWindow::slotImageMenuUpdateDueToSelection () { // SYNC: kolourpaintui.rc const QString MenuBarItemTextImage = i18nc ( "Image/Selection Menu caption - make sure the translation has" " the same accel as the Select&ion translation", "&Image"); const QString MenuBarItemTextSelection = i18nc ( "Image/Selection Menu caption - make sure that translation has" " the same accel as the &Image translation", "Select&ion"); Q_ASSERT (menuBar ()); foreach (QAction *action, menuBar ()->actions ()) { if (action->text () == MenuBarItemTextImage || action->text () == MenuBarItemTextSelection) { if (isSelectionActive ()) action->setText (MenuBarItemTextSelection); else action->setText (MenuBarItemTextImage); break; } } d->actionResizeScale->setEnabled (d->imageMenuDocumentActionsEnabled); d->actionCrop->setEnabled (d->imageMenuDocumentActionsEnabled && isSelectionActive ()); const bool enable = (d->imageMenuDocumentActionsEnabled && !isTextSelection ()); d->actionAutoCrop->setText (autoCropText ()); d->actionAutoCrop->setEnabled (enable); d->actionFlip->setEnabled (enable); d->actionMirror->setEnabled (enable); d->actionRotate->setEnabled (enable); d->actionRotateLeft->setEnabled (enable); d->actionRotateRight->setEnabled (enable); d->actionSkew->setEnabled (enable); d->actionConvertToBlackAndWhite->setEnabled (enable); d->actionConvertToGrayscale->setEnabled (enable); d->actionInvertColors->setEnabled (enable); d->actionClear->setEnabled (enable); d->actionBlur->setEnabled (enable); d->actionMoreEffects->setEnabled (enable); } //--------------------------------------------------------------------- // public kpColor kpMainWindow::backgroundColor (bool ofSelection) const { if (ofSelection) return kpColor::Transparent; else { Q_ASSERT (d->colorToolBar); return d->colorToolBar->backgroundColor (); } } //--------------------------------------------------------------------- // public // REFACTOR: sync: Code dup with kpAbstractSelectionTool::addNeedingContentCommand(). void kpMainWindow::addImageOrSelectionCommand (kpCommand *cmd, bool addSelCreateCmdIfSelAvail, bool addSelContentCmdIfSelAvail) { #if DEBUG_KP_MAIN_WINDOW && 1 qCDebug(kpLogMainWindow) << "kpMainWindow::addImageOrSelectionCommand()" << " addSelCreateCmdIfSelAvail=" << addSelCreateCmdIfSelAvail << " addSelContentCmdIfSelAvail=" << addSelContentCmdIfSelAvail << endl; #endif Q_ASSERT (d->document); if (d->viewManager) d->viewManager->setQueueUpdates (); kpAbstractSelection *sel = d->document->selection (); #if DEBUG_KP_MAIN_WINDOW && 1 qCDebug(kpLogMainWindow) << "\timage sel=" << sel << " sel->hasContent=" << (sel ? sel->hasContent () : 0) << endl; #endif if (addSelCreateCmdIfSelAvail && sel && !sel->hasContent ()) { QString createCmdName; if (dynamic_cast (sel)) createCmdName = i18n ("Selection: Create"); else if (dynamic_cast (sel)) createCmdName = i18n ("Text: Create Box"); else Q_ASSERT (!"Unknown selection type"); // create selection region commandHistory ()->addCreateSelectionCommand ( new kpToolSelectionCreateCommand ( createCmdName, *sel, commandEnvironment ()), false/*no exec - user already dragged out sel*/); } if (addSelContentCmdIfSelAvail && sel && !sel->hasContent ()) { kpAbstractImageSelection *imageSel = dynamic_cast (sel); kpTextSelection *textSel = dynamic_cast (sel); if (imageSel && imageSel->transparency ().isTransparent ()) d->colorToolBar->flashColorSimilarityToolBarItem (); kpMacroCommand *macroCmd = new kpMacroCommand (cmd->name (), commandEnvironment ()); if (imageSel) { macroCmd->addCommand ( new kpToolSelectionPullFromDocumentCommand ( *imageSel, backgroundColor (), QString()/*uninteresting child of macro cmd*/, commandEnvironment ())); } else if (textSel) { macroCmd->addCommand ( new kpToolTextGiveContentCommand ( *textSel, QString()/*uninteresting child of macro cmd*/, commandEnvironment ())); } else Q_ASSERT (!"Unknown selection type"); macroCmd->addCommand (cmd); d->commandHistory->addCommand (macroCmd); } else { d->commandHistory->addCommand (cmd); } if (d->viewManager) d->viewManager->restoreQueueUpdates (); } //--------------------------------------------------------------------- // private slot void kpMainWindow::slotResizeScale () { toolEndShape (); kpTransformResizeScaleDialog dialog(transformDialogEnvironment(), this); if (dialog.exec () && !dialog.isNoOp ()) { kpTransformResizeScaleCommand *cmd = new kpTransformResizeScaleCommand ( dialog.actOnSelection (), dialog.imageWidth (), dialog.imageHeight (), dialog.type (), commandEnvironment ()); bool addSelCreateCommand = (dialog.actOnSelection () || cmd->scaleSelectionWithImage ()); bool addSelContentCommand = dialog.actOnSelection (); addImageOrSelectionCommand ( cmd, addSelCreateCommand, addSelContentCommand); // Resized document? if (!dialog.actOnSelection () && dialog.type () == kpTransformResizeScaleCommand::Resize) { // TODO: this should be the responsibility of kpDocument saveDefaultDocSize (QSize (dialog.imageWidth (), dialog.imageHeight ())); } } } //--------------------------------------------------------------------- // public slot void kpMainWindow::slotCrop () { toolEndShape (); Q_ASSERT (d->document && d->document->selection ()); ::kpTransformCrop (this); } //--------------------------------------------------------------------- // private slot void kpMainWindow::slotAutoCrop () { toolEndShape (); ::kpTransformAutoCrop (this); } //--------------------------------------------------------------------- // private slot void kpMainWindow::slotFlip() { toolEndShape(); addImageOrSelectionCommand( new kpTransformFlipCommand(d->document->selection(), false, true, commandEnvironment())); } //--------------------------------------------------------------------- // private slot void kpMainWindow::slotMirror() { toolEndShape(); addImageOrSelectionCommand( new kpTransformFlipCommand(d->document->selection(), true, false, commandEnvironment())); } //--------------------------------------------------------------------- // private slot void kpMainWindow::slotRotate () { toolEndShape (); - kpTransformRotateDialog dialog ((bool) d->document->selection (), + kpTransformRotateDialog dialog (static_cast (d->document->selection ()), transformDialogEnvironment (), this); if (dialog.exec () && !dialog.isNoOp ()) { addImageOrSelectionCommand ( new kpTransformRotateCommand (d->document->selection (), dialog.angle (), commandEnvironment ())); } } // private slot void kpMainWindow::slotRotate270 () { toolEndShape (); // TODO: Special command name instead of just "Rotate"? addImageOrSelectionCommand ( new kpTransformRotateCommand ( d->document->selection (), 270, commandEnvironment ())); } // private slot void kpMainWindow::slotRotate90 () { toolEndShape (); // TODO: Special command name instead of just "Rotate"? addImageOrSelectionCommand ( new kpTransformRotateCommand ( d->document->selection (), 90, commandEnvironment ())); } // private slot void kpMainWindow::slotSkew () { toolEndShape (); - kpTransformSkewDialog dialog ((bool) d->document->selection (), + kpTransformSkewDialog dialog (static_cast (d->document->selection ()), transformDialogEnvironment (), this); if (dialog.exec () && !dialog.isNoOp ()) { addImageOrSelectionCommand ( new kpTransformSkewCommand (d->document->selection (), dialog.horizontalAngle (), dialog.verticalAngle (), commandEnvironment ())); } } //--------------------------------------------------------------------- // private slot void kpMainWindow::slotConvertToBlackAndWhite () { toolEndShape (); addImageOrSelectionCommand ( new kpEffectReduceColorsCommand (1/*depth*/, true/*dither*/, d->document->selection (), commandEnvironment ())); } //--------------------------------------------------------------------- // private slot void kpMainWindow::slotConvertToGrayscale () { toolEndShape (); addImageOrSelectionCommand ( new kpEffectGrayscaleCommand (d->document->selection (), commandEnvironment ())); } //-------------------------------------------------------------------------------- // private slot void kpMainWindow::slotInvertColors () { toolEndShape (); addImageOrSelectionCommand ( new kpEffectInvertCommand (d->document->selection (), commandEnvironment ())); } //-------------------------------------------------------------------------------- // private slot void kpMainWindow::slotClear () { toolEndShape (); addImageOrSelectionCommand ( new kpEffectClearCommand ( d->document->selection (), backgroundColor (), commandEnvironment ())); } //-------------------------------------------------------------------------------- void kpMainWindow::slotMakeConfidential() { toolEndShape(); addImageOrSelectionCommand( new kpEffectBlurSharpenCommand(kpEffectBlurSharpen::MakeConfidential, kpEffectBlurSharpen::MaxStrength, d->document->selection(), commandEnvironment())); } //-------------------------------------------------------------------------------- // private slot void kpMainWindow::slotMoreEffects () { toolEndShape (); - kpEffectsDialog dialog ((bool) d->document->selection (), + kpEffectsDialog dialog (static_cast (d->document->selection ()), transformDialogEnvironment (), this, d->moreEffectsDialogLastEffect); if (dialog.exec () && !dialog.isNoOp ()) { addImageOrSelectionCommand (dialog.createCommand ()); } if (d->moreEffectsDialogLastEffect != dialog.selectedEffect ()) { d->moreEffectsDialogLastEffect = dialog.selectedEffect (); KConfigGroup cfg (KSharedConfig::openConfig (), kpSettingsGroupGeneral); cfg.writeEntry (kpSettingMoreEffectsLastEffect, d->moreEffectsDialogLastEffect); cfg.sync (); } } //-------------------------------------------------------------------------------- diff --git a/mainWindow/kpMainWindow_Tools.cpp b/mainWindow/kpMainWindow_Tools.cpp index a78ed172..904dcca8 100644 --- a/mainWindow/kpMainWindow_Tools.cpp +++ b/mainWindow/kpMainWindow_Tools.cpp @@ -1,805 +1,805 @@ /* Copyright (c) 2003-2007 Clarence Dang Copyright (c) 2011 Martin Koller All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include "mainWindow/kpMainWindow.h" #include "kpMainWindowPrivate.h" #include #include #include #include #include #include "kpLogCategories.h" #include #include "widgets/toolbars/kpColorToolBar.h" #include "commands/kpCommandHistory.h" #include "document/kpDocument.h" #include "layers/selections/image/kpImageSelectionTransparency.h" #include "tools/kpTool.h" #include "tools/kpToolAction.h" #include "tools/flow/kpToolBrush.h" #include "tools/flow/kpToolColorEraser.h" #include "tools/kpToolColorPicker.h" #include "tools/polygonal/kpToolCurve.h" #include "tools/selection/image/kpToolEllipticalSelection.h" #include "tools/rectangular/kpToolEllipse.h" #include "tools/flow/kpToolEraser.h" #include "tools/kpToolFloodFill.h" #include "tools/selection/image/kpToolFreeFormSelection.h" #include "tools/polygonal/kpToolLine.h" #include "tools/flow/kpToolPen.h" #include "tools/polygonal/kpToolPolygon.h" #include "tools/polygonal/kpToolPolyline.h" #include "tools/rectangular/kpToolRectangle.h" #include "tools/selection/image/kpToolRectSelection.h" #include "tools/rectangular/kpToolRoundedRectangle.h" #include "environments/tools/selection/kpToolSelectionEnvironment.h" #include "tools/flow/kpToolSpraycan.h" #include "tools/selection/text/kpToolText.h" #include "widgets/toolbars/kpToolToolBar.h" #include "widgets/toolbars/options/kpToolWidgetOpaqueOrTransparent.h" #include "tools/kpToolZoom.h" #include "commands/imagelib/transforms/kpTransformResizeScaleCommand.h" #include "kpViewScrollableContainer.h" #include "views/kpZoomedView.h" //--------------------------------------------------------------------- // private kpToolSelectionEnvironment *kpMainWindow::toolSelectionEnvironment () { if (!d->toolSelectionEnvironment) d->toolSelectionEnvironment = new kpToolSelectionEnvironment (this); return d->toolSelectionEnvironment; } //--------------------------------------------------------------------- // private kpToolEnvironment *kpMainWindow::toolEnvironment () { // It's fine to return a more complex environment than required. return toolSelectionEnvironment (); } //--------------------------------------------------------------------- // private void kpMainWindow::setupToolActions () { kpToolSelectionEnvironment *toolSelEnv = toolSelectionEnvironment (); kpToolEnvironment *toolEnv = toolEnvironment (); d->tools.append (d->toolFreeFormSelection = new kpToolFreeFormSelection (toolSelEnv, this)); d->tools.append (d->toolRectSelection = new kpToolRectSelection (toolSelEnv, this)); d->tools.append (d->toolEllipticalSelection = new kpToolEllipticalSelection (toolSelEnv, this)); d->tools.append (d->toolText = new kpToolText (toolSelEnv, this)); d->tools.append (d->toolLine = new kpToolLine (toolEnv, this)); d->tools.append (d->toolPen = new kpToolPen (toolEnv, this)); d->tools.append (d->toolEraser = new kpToolEraser (toolEnv, this)); d->tools.append (d->toolBrush = new kpToolBrush (toolEnv, this)); d->tools.append (d->toolFloodFill = new kpToolFloodFill (toolEnv, this)); d->tools.append (d->toolColorPicker = new kpToolColorPicker (toolEnv, this)); d->tools.append (d->toolColorEraser = new kpToolColorEraser (toolEnv, this)); d->tools.append (d->toolSpraycan = new kpToolSpraycan (toolEnv, this)); d->tools.append (d->toolRoundedRectangle = new kpToolRoundedRectangle (toolEnv, this)); d->tools.append (d->toolRectangle = new kpToolRectangle (toolEnv, this)); d->tools.append (d->toolPolygon = new kpToolPolygon (toolEnv, this)); d->tools.append (d->toolEllipse = new kpToolEllipse (toolEnv, this)); d->tools.append (d->toolPolyline = new kpToolPolyline (toolEnv, this)); d->tools.append (d->toolCurve = new kpToolCurve (toolEnv, this)); d->tools.append (d->toolZoom = new kpToolZoom (toolEnv, this)); KActionCollection *ac = actionCollection (); d->actionPrevToolOptionGroup1 = ac->addAction ("prev_tool_option_group_1"); d->actionPrevToolOptionGroup1->setText (i18n ("Previous Tool Option (Group #1)")); ac->setDefaultShortcuts (d->actionPrevToolOptionGroup1, kpTool::shortcutForKey (Qt::Key_1)); connect (d->actionPrevToolOptionGroup1, SIGNAL (triggered(bool)), SLOT (slotActionPrevToolOptionGroup1())); d->actionNextToolOptionGroup1 = ac->addAction ("next_tool_option_group_1"); d->actionNextToolOptionGroup1->setText (i18n ("Next Tool Option (Group #1)")); ac->setDefaultShortcuts (d->actionNextToolOptionGroup1, kpTool::shortcutForKey (Qt::Key_2)); connect (d->actionNextToolOptionGroup1, SIGNAL (triggered(bool)), SLOT (slotActionNextToolOptionGroup1())); d->actionPrevToolOptionGroup2 = ac->addAction ("prev_tool_option_group_2"); d->actionPrevToolOptionGroup2->setText (i18n ("Previous Tool Option (Group #2)")); ac->setDefaultShortcuts (d->actionPrevToolOptionGroup2, kpTool::shortcutForKey (Qt::Key_3)); connect (d->actionPrevToolOptionGroup2, SIGNAL (triggered(bool)), SLOT (slotActionPrevToolOptionGroup2())); d->actionNextToolOptionGroup2 = ac->addAction ("next_tool_option_group_2"); d->actionNextToolOptionGroup2->setText (i18n ("Next Tool Option (Group #2)")); ac->setDefaultShortcuts (d->actionNextToolOptionGroup2, kpTool::shortcutForKey (Qt::Key_4)); connect (d->actionNextToolOptionGroup2, SIGNAL (triggered(bool)), SLOT (slotActionNextToolOptionGroup2())); // // Implemented in this file (kpMainWindow_Tools.cpp), not // kpImageWindow_Image.cpp since they're really setting tool options. // d->actionDrawOpaque = ac->add ("image_draw_opaque"); d->actionDrawOpaque->setText (i18n ("&Draw Opaque")); connect (d->actionDrawOpaque, SIGNAL (triggered(bool)), SLOT (slotActionDrawOpaqueToggled())); d->actionDrawColorSimilarity = ac->addAction ("image_draw_color_similarity"); d->actionDrawColorSimilarity->setText (i18n ("Draw With Color Similarity...")); connect (d->actionDrawColorSimilarity, SIGNAL (triggered(bool)), SLOT (slotActionDrawColorSimilarity())); } //--------------------------------------------------------------------- // private void kpMainWindow::createToolBox () { d->toolToolBar = new kpToolToolBar(QLatin1String("Tool Box"), 2/*columns/rows*/, this); d->toolToolBar->setWindowTitle(i18n("Tool Box")); connect (d->toolToolBar, SIGNAL (sigToolSelected(kpTool*)), this, SLOT (slotToolSelected(kpTool*))); connect (d->toolToolBar, SIGNAL (toolWidgetOptionSelected()), this, SLOT (updateToolOptionPrevNextActionsEnabled())); connect (d->toolToolBar->toolWidgetOpaqueOrTransparent (), SIGNAL (isOpaqueChanged(bool)), SLOT (updateActionDrawOpaqueChecked())); updateActionDrawOpaqueChecked (); foreach (kpTool *tool, d->tools) d->toolToolBar->registerTool(tool); // (from config file) readLastTool (); } //--------------------------------------------------------------------- // private void kpMainWindow::enableToolsDocumentActions (bool enable) { #if DEBUG_KP_MAIN_WINDOW qCDebug(kpLogMainWindow) << "kpMainWindow::enableToolsDocumentsAction(" << enable << ")"; #endif d->toolActionsEnabled = enable; if (enable && !d->toolToolBar->isEnabled ()) { kpTool *previousTool = d->toolToolBar->previousTool (); // select tool for enabled Tool Box if (previousTool) d->toolToolBar->selectPreviousTool (); else { - if (d->lastToolNumber >= 0 && d->lastToolNumber < (int) d->tools.count ()) + if (d->lastToolNumber >= 0 && d->lastToolNumber < d->tools.count ()) d->toolToolBar->selectTool (d->tools.at (d->lastToolNumber)); else d->toolToolBar->selectTool (d->toolPen); } } else if (!enable && d->toolToolBar->isEnabled ()) { // don't have a disabled Tool Box with a checked Tool d->toolToolBar->selectTool (nullptr); } d->toolToolBar->setEnabled (enable); foreach (kpTool *tool, d->tools) { kpToolAction *action = tool->action(); if (!enable && action->isChecked()) action->setChecked(false); action->setEnabled(enable); } updateToolOptionPrevNextActionsEnabled (); updateActionDrawOpaqueEnabled (); } //--------------------------------------------------------------------- // private slot void kpMainWindow::updateToolOptionPrevNextActionsEnabled () { const bool enable = d->toolActionsEnabled; d->actionPrevToolOptionGroup1->setEnabled (enable && d->toolToolBar->shownToolWidget (0) && d->toolToolBar->shownToolWidget (0)->hasPreviousOption ()); d->actionNextToolOptionGroup1->setEnabled (enable && d->toolToolBar->shownToolWidget (0) && d->toolToolBar->shownToolWidget (0)->hasNextOption ()); d->actionPrevToolOptionGroup2->setEnabled (enable && d->toolToolBar->shownToolWidget (1) && d->toolToolBar->shownToolWidget (1)->hasPreviousOption ()); d->actionNextToolOptionGroup2->setEnabled (enable && d->toolToolBar->shownToolWidget (1) && d->toolToolBar->shownToolWidget (1)->hasNextOption ()); } //--------------------------------------------------------------------- // private slot void kpMainWindow::updateActionDrawOpaqueChecked () { #if DEBUG_KP_MAIN_WINDOW qCDebug(kpLogMainWindow) << "kpMainWindow::updateActionDrawOpaqueChecked()"; #endif const bool drawOpaque = (d->toolToolBar->toolWidgetOpaqueOrTransparent ()->selectedRow () == 0); #if DEBUG_KP_MAIN_WINDOW qCDebug(kpLogMainWindow) << "\tdrawOpaque=" << drawOpaque; #endif d->actionDrawOpaque->setChecked (drawOpaque); } //--------------------------------------------------------------------- // private void kpMainWindow::updateActionDrawOpaqueEnabled () { #if DEBUG_KP_MAIN_WINDOW qCDebug(kpLogMainWindow) << "kpMainWindow::updateActionDrawOpaqueEnabled()"; #endif const bool enable = d->toolActionsEnabled; #if DEBUG_KP_MAIN_WINDOW qCDebug(kpLogMainWindow) << "\tenable=" << enable << " tool=" << (tool () ? tool ()->objectName () : 0) << " (is selection=" << toolIsASelectionTool () << ")" << endl; #endif d->actionDrawOpaque->setEnabled (enable && toolIsASelectionTool ()); } //--------------------------------------------------------------------- // public QActionGroup *kpMainWindow::toolsActionGroup () { if (!d->toolsActionGroup) d->toolsActionGroup = new QActionGroup (this); return d->toolsActionGroup; } //--------------------------------------------------------------------- // public kpTool *kpMainWindow::tool () const { return d->toolToolBar ? d->toolToolBar->tool () : nullptr; } //--------------------------------------------------------------------- // public bool kpMainWindow::toolHasBegunShape () const { kpTool *currentTool = tool (); return (currentTool && currentTool->hasBegunShape ()); } //--------------------------------------------------------------------- // public bool kpMainWindow::toolIsASelectionTool (bool includingTextTool) const { kpTool *currentTool = tool (); return ((currentTool == d->toolFreeFormSelection) || (currentTool == d->toolRectSelection) || (currentTool == d->toolEllipticalSelection) || (currentTool == d->toolText && includingTextTool)); } //--------------------------------------------------------------------- // public bool kpMainWindow::toolIsTextTool () const { return (tool () == d->toolText); } //--------------------------------------------------------------------- // private void kpMainWindow::toolEndShape () { if (toolHasBegunShape ()) tool ()->endShapeInternal (); } //--------------------------------------------------------------------- // public kpImageSelectionTransparency kpMainWindow::imageSelectionTransparency () const { kpToolWidgetOpaqueOrTransparent *oot = d->toolToolBar->toolWidgetOpaqueOrTransparent (); Q_ASSERT (oot); return kpImageSelectionTransparency (oot->isOpaque (), backgroundColor (), d->colorToolBar->colorSimilarity ()); } //--------------------------------------------------------------------- // public void kpMainWindow::setImageSelectionTransparency (const kpImageSelectionTransparency &transparency, bool forceColorChange) { #if DEBUG_KP_MAIN_WINDOW && 1 qCDebug(kpLogMainWindow) << "kpMainWindow::setImageSelectionTransparency() isOpaque=" << transparency.isOpaque () << " color=" << (transparency.transparentColor ().isValid () ? (int *) transparency.transparentColor ().toQRgb () : 0) << " forceColorChange=" << forceColorChange << endl; #endif kpToolWidgetOpaqueOrTransparent *oot = d->toolToolBar->toolWidgetOpaqueOrTransparent (); Q_ASSERT (oot); d->settingImageSelectionTransparency++; oot->setOpaque (transparency.isOpaque ()); if (transparency.isTransparent () || forceColorChange) { d->colorToolBar->setColor (1, transparency.transparentColor ()); d->colorToolBar->setColorSimilarity (transparency.colorSimilarity ()); } d->settingImageSelectionTransparency--; } //--------------------------------------------------------------------- // public int kpMainWindow::settingImageSelectionTransparency () const { return d->settingImageSelectionTransparency; } //--------------------------------------------------------------------- // private slot void kpMainWindow::slotToolSelected (kpTool *tool) { #if DEBUG_KP_MAIN_WINDOW qCDebug(kpLogMainWindow) << "kpMainWindow::slotToolSelected (" << tool << ")"; #endif kpTool *previousTool = d->toolToolBar ? d->toolToolBar->previousTool () : nullptr; if (previousTool) { disconnect (previousTool, SIGNAL (movedAndAboutToDraw(QPoint,QPoint,int,bool*)), this, SLOT (slotDragScroll(QPoint,QPoint,int,bool*))); disconnect (previousTool, SIGNAL (endedDraw(QPoint)), this, SLOT (slotEndDragScroll())); disconnect (previousTool, SIGNAL (cancelledShape(QPoint)), this, SLOT (slotEndDragScroll())); disconnect (previousTool, SIGNAL (userMessageChanged(QString)), this, SLOT (recalculateStatusBarMessage())); disconnect (previousTool, SIGNAL (userShapePointsChanged(QPoint,QPoint)), this, SLOT (recalculateStatusBarShape())); disconnect (previousTool, SIGNAL (userShapeSizeChanged(QSize)), this, SLOT (recalculateStatusBarShape())); disconnect (d->colorToolBar, SIGNAL (colorsSwapped(kpColor,kpColor)), previousTool, SLOT (slotColorsSwappedInternal(kpColor,kpColor))); disconnect (d->colorToolBar, SIGNAL (foregroundColorChanged(kpColor)), previousTool, SLOT (slotForegroundColorChangedInternal(kpColor))); disconnect (d->colorToolBar, SIGNAL (backgroundColorChanged(kpColor)), previousTool, SLOT (slotBackgroundColorChangedInternal(kpColor))); disconnect (d->colorToolBar, SIGNAL (colorSimilarityChanged(double,int)), previousTool, SLOT (slotColorSimilarityChangedInternal(double,int))); } if (tool) { connect (tool, SIGNAL (movedAndAboutToDraw(QPoint,QPoint,int,bool*)), this, SLOT (slotDragScroll(QPoint,QPoint,int,bool*))); connect (tool, SIGNAL (endedDraw(QPoint)), this, SLOT (slotEndDragScroll())); connect (tool, SIGNAL (cancelledShape(QPoint)), this, SLOT (slotEndDragScroll())); connect (tool, SIGNAL (userMessageChanged(QString)), this, SLOT (recalculateStatusBarMessage())); connect (tool, SIGNAL (userShapePointsChanged(QPoint,QPoint)), this, SLOT (recalculateStatusBarShape())); connect (tool, SIGNAL (userShapeSizeChanged(QSize)), this, SLOT (recalculateStatusBarShape())); recalculateStatusBar (); connect (d->colorToolBar, SIGNAL (colorsSwapped(kpColor,kpColor)), tool, SLOT (slotColorsSwappedInternal(kpColor,kpColor))); connect (d->colorToolBar, SIGNAL (foregroundColorChanged(kpColor)), tool, SLOT (slotForegroundColorChangedInternal(kpColor))); connect (d->colorToolBar, SIGNAL (backgroundColorChanged(kpColor)), tool, SLOT (slotBackgroundColorChangedInternal(kpColor))); connect (d->colorToolBar, SIGNAL (colorSimilarityChanged(double,int)), tool, SLOT (slotColorSimilarityChangedInternal(double,int))); saveLastTool (); } updateToolOptionPrevNextActionsEnabled (); updateActionDrawOpaqueEnabled (); } //--------------------------------------------------------------------- // private void kpMainWindow::readLastTool () { KConfigGroup cfg (KSharedConfig::openConfig (), kpSettingsGroupTools); d->lastToolNumber = cfg.readEntry (kpSettingLastTool, -1); } //--------------------------------------------------------------------- // private int kpMainWindow::toolNumber () const { int number = 0; for (QList ::const_iterator it = d->tools.constBegin (); it != d->tools.constEnd (); ++it) { if (*it == tool ()) return number; number++; } return -1; } //--------------------------------------------------------------------- // private void kpMainWindow::saveLastTool () { int number = toolNumber (); - if (number < 0 || number >= (int) d->tools.count ()) + if (number < 0 || number >= d->tools.count ()) return; KConfigGroup cfg (KSharedConfig::openConfig (), kpSettingsGroupTools); cfg.writeEntry (kpSettingLastTool, number); cfg.sync (); } //--------------------------------------------------------------------- // private bool kpMainWindow::maybeDragScrollingMainView () const { return (tool () && d->mainView && tool ()->viewUnderStartPoint () == d->mainView); } //--------------------------------------------------------------------- // private slot bool kpMainWindow::slotDragScroll (const QPoint &docPoint, const QPoint &docLastPoint, int zoomLevel, bool *scrolled) { Q_UNUSED(docPoint) Q_UNUSED(docLastPoint) #if DEBUG_KP_MAIN_WINDOW qCDebug(kpLogMainWindow) << "kpMainWindow::slotDragScroll() maybeDragScrolling=" << maybeDragScrollingMainView () << endl; #endif if (maybeDragScrollingMainView ()) { return d->scrollView->beginDragScroll(zoomLevel, scrolled); } else { return false; } } //--------------------------------------------------------------------- // private slot bool kpMainWindow::slotEndDragScroll () { // (harmless if haven't started drag scroll) return d->scrollView->endDragScroll (); } //--------------------------------------------------------------------- // private slot void kpMainWindow::slotBeganDocResize () { toolEndShape (); recalculateStatusBarShape (); } //--------------------------------------------------------------------- // private slot void kpMainWindow::slotContinuedDocResize (const QSize &) { recalculateStatusBarShape (); } //--------------------------------------------------------------------- // private slot void kpMainWindow::slotCancelledDocResize () { recalculateStatusBar (); } //--------------------------------------------------------------------- // private slot void kpMainWindow::slotEndedDocResize (const QSize &size) { #define DOC_RESIZE_COMPLETED() \ { \ d->docResizeToBeCompleted = false; \ recalculateStatusBar (); \ } // Prevent statusbar updates d->docResizeToBeCompleted = true; d->docResizeWidth = (size.width () > 0 ? size.width () : 1); d->docResizeHeight = (size.height () > 0 ? size.height () : 1); if (d->docResizeWidth == d->document->width () && d->docResizeHeight == d->document->height ()) { DOC_RESIZE_COMPLETED (); return; } // Blank status to avoid confusion if dialog comes up setStatusBarMessage (); setStatusBarShapePoints (); setStatusBarShapeSize (); if (kpTool::warnIfBigImageSize (d->document->width (), d->document->height (), d->docResizeWidth, d->docResizeHeight, i18n ("

Resizing the image to" " %1x%2 may take a substantial amount of memory." " This can reduce system" " responsiveness and cause other application resource" " problems.

" "

Are you sure you want to resize the" " image?

", d->docResizeWidth, d->docResizeHeight), i18nc ("@title:window", "Resize Image?"), i18n ("R&esize Image"), this)) { d->commandHistory->addCommand ( new kpTransformResizeScaleCommand ( false/*doc, not sel*/, d->docResizeWidth, d->docResizeHeight, kpTransformResizeScaleCommand::Resize, commandEnvironment ())); saveDefaultDocSize (QSize (d->docResizeWidth, d->docResizeHeight)); } DOC_RESIZE_COMPLETED (); #undef DOC_RESIZE_COMPLETED } //--------------------------------------------------------------------- // private slot void kpMainWindow::slotDocResizeMessageChanged (const QString &string) { #if DEBUG_KP_MAIN_WINDOW qCDebug(kpLogMainWindow) << "kpMainWindow::slotDocResizeMessageChanged(" << string << ") docResizeToBeCompleted=" << d->docResizeToBeCompleted << endl; #else (void) string; #endif if (d->docResizeToBeCompleted) return; recalculateStatusBarMessage (); } //--------------------------------------------------------------------- // private slot void kpMainWindow::slotActionPrevToolOptionGroup1 () { if (!d->toolToolBar->shownToolWidget (0)) return; // We don't call toolEndShape() here because we want #23 in the file BUGS // to later work. d->toolToolBar->shownToolWidget (0)->selectPreviousOption (); updateToolOptionPrevNextActionsEnabled (); } //--------------------------------------------------------------------- // private slot void kpMainWindow::slotActionNextToolOptionGroup1 () { if (!d->toolToolBar->shownToolWidget (0)) return; // We don't call toolEndShape() here because we want #23 in the file BUGS // to later work. d->toolToolBar->shownToolWidget (0)->selectNextOption (); updateToolOptionPrevNextActionsEnabled (); } //--------------------------------------------------------------------- // private slot void kpMainWindow::slotActionPrevToolOptionGroup2 () { if (!d->toolToolBar->shownToolWidget (1)) return; // We don't call toolEndShape() here because we want #23 in the file BUGS // to later work. d->toolToolBar->shownToolWidget (1)->selectPreviousOption (); updateToolOptionPrevNextActionsEnabled (); } //--------------------------------------------------------------------- // private slot void kpMainWindow::slotActionNextToolOptionGroup2 () { if (!d->toolToolBar->shownToolWidget (1)) return; // We don't call toolEndShape() here because we want #23 in the file BUGS // to later work. d->toolToolBar->shownToolWidget (1)->selectNextOption (); updateToolOptionPrevNextActionsEnabled (); } //--------------------------------------------------------------------- // private slot void kpMainWindow::slotActionDrawOpaqueToggled () { #if DEBUG_KP_MAIN_WINDOW qCDebug(kpLogMainWindow) << "kpMainWindow::slotActionDrawOpaqueToggled()"; #endif toolEndShape (); // TODO: How does this differ to setImageSelectionTransparency()? // ("kpToolWidgetBase::" is to access one overload shadowed by the override // of the other overload) d->toolToolBar->toolWidgetOpaqueOrTransparent ()->kpToolWidgetBase::setSelected ( (d->actionDrawOpaque->isChecked () ? 0/*row 0 = opaque*/ : 1/*row 1 = transparent*/), 0/*column*/); } //--------------------------------------------------------------------- // private slot void kpMainWindow::slotActionDrawColorSimilarity () { #if DEBUG_KP_MAIN_WINDOW qCDebug(kpLogMainWindow) << "kpMainWindow::slotActionDrawColorSimilarity()"; #endif toolEndShape (); d->colorToolBar->openColorSimilarityDialog (); } //--------------------------------------------------------------------- // public slots #define SLOT_TOOL(toolName) \ void kpMainWindow::slotTool##toolName () \ { \ if (!d->toolToolBar) \ return; \ \ if (tool () == d->tool##toolName) \ return; \ \ d->toolToolBar->selectTool (d->tool##toolName); \ } SLOT_TOOL (RectSelection) SLOT_TOOL (EllipticalSelection) SLOT_TOOL (FreeFormSelection) SLOT_TOOL (Text) diff --git a/mainWindow/kpMainWindow_View_Zoom.cpp b/mainWindow/kpMainWindow_View_Zoom.cpp index 840991f9..0d2317ca 100644 --- a/mainWindow/kpMainWindow_View_Zoom.cpp +++ b/mainWindow/kpMainWindow_View_Zoom.cpp @@ -1,707 +1,707 @@ // REFACTOR: Clean up bits of this file /* Copyright (c) 2003-2007 Clarence Dang All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include "mainWindow/kpMainWindow.h" #include "kpMainWindowPrivate.h" #include "kpLogCategories.h" #include #include #include #include #include #include #include "kpDefs.h" #include "document/kpDocument.h" #include "kpThumbnail.h" #include "tools/kpTool.h" #include "widgets/toolbars/kpToolToolBar.h" #include "views/kpUnzoomedThumbnailView.h" #include "views/manager/kpViewManager.h" #include "kpViewScrollableContainer.h" #include "generic/kpWidgetMapper.h" #include "views/kpZoomedView.h" #include "views/kpZoomedThumbnailView.h" static int ZoomLevelFromString (const QString &stringIn) { #if DEBUG_KP_MAIN_WINDOW qCDebug(kpLogMainWindow) << "kpMainWindow_View.cpp:ZoomLevelFromString(" << stringIn << ")"; #endif // Remove any non-digits kdelibs sometimes adds behind our back :( e.g.: // // 1. kdelibs adds accelerators to actions' text directly // 2. ',' is automatically added to change "1000%" to "1,000%" QString string = stringIn; string.remove (QRegExp ("[^0-9]")); #if DEBUG_KP_MAIN_WINDOW qCDebug(kpLogMainWindow) << "\twithout non-digits='" << string << "'"; #endif // Convert zoom level to number. bool ok = false; int zoomLevel = string.toInt (&ok); #if DEBUG_KP_MAIN_WINDOW qCDebug(kpLogMainWindow) << "\tzoomLevel=" << zoomLevel; #endif if (!ok || zoomLevel < kpView::MinZoomLevel || zoomLevel > kpView::MaxZoomLevel) return 0; // error else return zoomLevel; } //--------------------------------------------------------------------- static QString ZoomLevelToString (int zoomLevel) { return i18n ("%1%", zoomLevel); } //--------------------------------------------------------------------- // private void kpMainWindow::setupViewMenuZoomActions () { KActionCollection *ac = actionCollection (); d->actionActualSize = KStandardAction::actualSize (this, SLOT (slotActualSize()), ac); d->actionFitToPage = KStandardAction::fitToPage (this, SLOT (slotFitToPage()), ac); d->actionFitToWidth = KStandardAction::fitToWidth (this, SLOT (slotFitToWidth()), ac); d->actionFitToHeight = KStandardAction::fitToHeight (this, SLOT (slotFitToHeight()), ac); d->actionZoomIn = KStandardAction::zoomIn (this, SLOT (slotZoomIn()), ac); d->actionZoomOut = KStandardAction::zoomOut (this, SLOT (slotZoomOut()), ac); d->actionZoom = ac->add ("view_zoom_to"); d->actionZoom->setText (i18n ("&Zoom")); connect (d->actionZoom, SIGNAL (triggered(QAction*)), SLOT (slotZoom())); d->actionZoom->setEditable (true); // create the zoom list for the 1st call to zoomTo() below d->zoomList.append (10); d->zoomList.append (25); d->zoomList.append (33); d->zoomList.append (50); d->zoomList.append (67); d->zoomList.append (75); d->zoomList.append (100); d->zoomList.append (200); d->zoomList.append (300); d->zoomList.append (400); d->zoomList.append (600); d->zoomList.append (800); d->zoomList.append (1000); d->zoomList.append (1200); d->zoomList.append (1600); } //--------------------------------------------------------------------- // private void kpMainWindow::enableViewMenuZoomDocumentActions (bool enable) { d->actionActualSize->setEnabled (enable); d->actionFitToPage->setEnabled (enable); d->actionFitToWidth->setEnabled (enable); d->actionFitToHeight->setEnabled (enable); d->actionZoomIn->setEnabled (enable); d->actionZoomOut->setEnabled (enable); d->actionZoom->setEnabled (enable); // TODO: for the time being, assume that we start at zoom 100% // with no grid // This function is only called when a new document is created // or an existing document is closed. So the following will // always be correct: zoomTo (100); } //--------------------------------------------------------------------- // private void kpMainWindow::sendZoomListToActionZoom () { QStringList items; const QList ::ConstIterator zoomListEnd (d->zoomList.end ()); for (QList ::ConstIterator it = d->zoomList.constBegin (); it != zoomListEnd; ++it) { items << ::ZoomLevelToString (*it); } // Work around a KDE bug - KSelectAction::setItems() enables the action. // David Faure said it won't be fixed because it's a feature used by // KRecentFilesAction. bool e = d->actionZoom->isEnabled (); d->actionZoom->setItems (items); if (e != d->actionZoom->isEnabled ()) d->actionZoom->setEnabled (e); } //--------------------------------------------------------------------- // private void kpMainWindow::zoomToPre (int zoomLevel) { // We're called quite early in the init process and/or when there might // not be a document or a view so we have a lot of "if (ptr)" guards. #if DEBUG_KP_MAIN_WINDOW qCDebug(kpLogMainWindow) << "kpMainWindow::zoomToPre(" << zoomLevel << ")"; #endif zoomLevel = qBound (kpView::MinZoomLevel, zoomLevel, kpView::MaxZoomLevel); // mute point since the thumbnail suffers from this too #if 0 else if (d->mainView && d->mainView->zoomLevelX () % 100 == 0 && zoomLevel % 100) { if (KMessageBox::warningContinueCancel (this, i18n ("Setting the zoom level to a value that is not a multiple of 100% " "results in imprecise editing and redraw glitches.\n" "Do you really want to set to zoom level to %1%?", zoomLevel), QString()/*caption*/, i18n ("Set Zoom Level to %1%", zoomLevel), "DoNotAskAgain_ZoomLevelNotMultipleOf100") != KMessageBox::Continue) { zoomLevel = d->mainView->zoomLevelX (); } } #endif int index = 0; QList ::Iterator it = d->zoomList.begin (); while (index < d->zoomList.count () && zoomLevel > *it) { it++; index++; } if (zoomLevel != *it) d->zoomList.insert (it, zoomLevel); // OPT: We get called twice on startup. sendZoomListToActionZoom() is very slow. sendZoomListToActionZoom (); #if DEBUG_KP_MAIN_WINDOW qCDebug(kpLogMainWindow) << "\tsetCurrentItem(" << index << ")"; #endif d->actionZoom->setCurrentItem (index); #if DEBUG_KP_MAIN_WINDOW qCDebug(kpLogMainWindow) << "\tcurrentItem=" << d->actionZoom->currentItem () << " action=" << d->actionZoom->action (d->actionZoom->currentItem ()) << " checkedAction" << d->actionZoom->selectableActionGroup ()->checkedAction () << endl;; #endif if (viewMenuDocumentActionsEnabled ()) { d->actionActualSize->setEnabled (zoomLevel != 100); - d->actionZoomIn->setEnabled (d->actionZoom->currentItem () < (int) d->zoomList.count () - 1); + d->actionZoomIn->setEnabled (d->actionZoom->currentItem () < d->zoomList.count () - 1); d->actionZoomOut->setEnabled (d->actionZoom->currentItem () > 0); } // TODO: Is this actually needed? if (d->viewManager) d->viewManager->setQueueUpdates (); if (d->scrollView) { d->scrollView->setUpdatesEnabled (false); } } //--------------------------------------------------------------------- // private void kpMainWindow::zoomToPost () { #if DEBUG_KP_MAIN_WINDOW && 1 qCDebug(kpLogMainWindow) << "kpMainWindow::zoomToPost()"; #endif if (d->mainView) { actionShowGridUpdate (); updateMainViewGrid (); // Since Zoom Level KSelectAction on ToolBar grabs focus after changing // Zoom, switch back to the Main View. // TODO: back to the last view d->mainView->setFocus (); } // The view magnified and moved beneath the cursor if (tool ()) tool ()->somethingBelowTheCursorChanged (); if (d->scrollView) { // TODO: setUpdatesEnabled() should really return to old value // - not necessarily "true" d->scrollView->setUpdatesEnabled (true); } if (d->viewManager && d->viewManager->queueUpdates ()/*just in case*/) d->viewManager->restoreQueueUpdates (); setStatusBarZoom (d->mainView ? d->mainView->zoomLevelX () : 0); #if DEBUG_KP_MAIN_WINDOW && 1 qCDebug(kpLogMainWindow) << "kpMainWindow::zoomToPost() done"; #endif } //--------------------------------------------------------------------- // private void kpMainWindow::zoomTo (int zoomLevel, bool centerUnderCursor) { zoomToPre (zoomLevel); if (d->scrollView && d->mainView) { #if DEBUG_KP_MAIN_WINDOW && 1 qCDebug(kpLogMainWindow) << "\tscrollView contentsX=" << d->scrollView->horizontalScrollBar()->value () << " contentsY=" << d->scrollView->verticalScrollBar()->value () << " contentsWidth=" << d->scrollView->widget()->width () << " contentsHeight=" << d->scrollView->widget()->height () << " visibleWidth=" << d->scrollView->viewport()->width () << " visibleHeight=" << d->scrollView->viewport()->height () << " oldZoomX=" << d->mainView->zoomLevelX () << " oldZoomY=" << d->mainView->zoomLevelY () << " newZoom=" << zoomLevel << endl; #endif // TODO: when changing from no scrollbars to scrollbars, Qt lies about // visibleWidth() & visibleHeight() (doesn't take into account the // space taken by the would-be scrollbars) until it updates the // scrollview; hence the centering is off by about 5-10 pixels. // TODO: Use visibleRect() for greater accuracy? // Or use kpAbstractScrollAreaUtils::EstimateUsableArea() // instead of ScrollView::visible{Width,Height}(), as // per zoomToRect()? int viewX, viewY; bool targetDocAvail = false; double targetDocX = -1, targetDocY = -1; if (centerUnderCursor && d->viewManager && d->viewManager->viewUnderCursor ()) { kpView *const vuc = d->viewManager->viewUnderCursor (); QPoint viewPoint = vuc->mouseViewPoint (); // vuc->transformViewToDoc() returns QPoint which only has int // accuracy so we do X and Y manually. targetDocX = vuc->transformViewToDocX (viewPoint.x ()); targetDocY = vuc->transformViewToDocY (viewPoint.y ()); targetDocAvail = true; if (vuc != d->mainView) viewPoint = vuc->transformViewToOtherView (viewPoint, d->mainView); viewX = viewPoint.x (); viewY = viewPoint.y (); } else { viewX = d->scrollView->horizontalScrollBar()->value () + qMin (d->mainView->width (), d->scrollView->viewport()->width ()) / 2; viewY = d->scrollView->verticalScrollBar()->value () + qMin (d->mainView->height (), d->scrollView->viewport()->height ()) / 2; } int newCenterX = viewX * zoomLevel / d->mainView->zoomLevelX (); int newCenterY = viewY * zoomLevel / d->mainView->zoomLevelY (); // Do the zoom. d->mainView->setZoomLevel (zoomLevel, zoomLevel); #if DEBUG_KP_MAIN_WINDOW && 1 qCDebug(kpLogMainWindow) << "\tvisibleWidth=" << d->scrollView->viewport()->width () << " visibleHeight=" << d->scrollView->viewport()->height () << endl; qCDebug(kpLogMainWindow) << "\tnewCenterX=" << newCenterX << " newCenterY=" << newCenterY << endl; #endif d->scrollView->horizontalScrollBar()->setValue(newCenterX - (d->scrollView->viewport()->width() / 2)); d->scrollView->verticalScrollBar()->setValue(newCenterY - (d->scrollView->viewport()->height() / 2)); if (centerUnderCursor && targetDocAvail && d->viewManager && d->viewManager->viewUnderCursor ()) { // Move the mouse cursor so that it is still above the same // document pixel as before the zoom. kpView *const vuc = d->viewManager->viewUnderCursor (); #if DEBUG_KP_MAIN_WINDOW qCDebug(kpLogMainWindow) << "\tcenterUnderCursor: reposition cursor; viewUnderCursor=" << vuc->objectName () << endl; #endif const double viewX = vuc->transformDocToViewX (targetDocX); const double viewY = vuc->transformDocToViewY (targetDocY); // Rounding error from zooming in and out :( // TODO: do everything in terms of tool doc points in type "double". - const QPoint viewPoint ((int) viewX, (int) viewY); + const QPoint viewPoint (static_cast (viewX), static_cast (viewY)); #if DEBUG_KP_MAIN_WINDOW qCDebug(kpLogMainWindow) << "\t\tdoc: (" << targetDocX << "," << targetDocY << ")" << " viewUnderCursor: (" << viewX << "," << viewY << ")" << endl; #endif if (vuc->visibleRegion ().contains (viewPoint)) { const QPoint globalPoint = kpWidgetMapper::toGlobal (vuc, viewPoint); #if DEBUG_KP_MAIN_WINDOW qCDebug(kpLogMainWindow) << "\t\tglobalPoint=" << globalPoint; #endif // TODO: Determine some sane cursor flashing indication - // cursor movement is convenient but not conventional. // // Major problem: if using QApplication::setOverrideCursor() // and in some stage of flash and window quits. // // Or if using kpView::setCursor() and change tool. QCursor::setPos (globalPoint); } // e.g. Zoom to 200%, scroll mainView to bottom-right. // Unzoomed Thumbnail shows top-left portion of bottom-right of // mainView. // // Aim cursor at bottom-right of thumbnail and zoom out with // CTRL+Wheel. // // If mainView is now small enough to largely not need scrollbars, // Unzoomed Thumbnail scrolls to show _top-left_ portion // _of top-left_ of mainView. // // Unzoomed Thumbnail no longer contains the point we zoomed out // on top of. else { #if DEBUG_KP_MAIN_WINDOW qCDebug(kpLogMainWindow) << "\t\twon't move cursor - would get outside view" << endl; #endif // TODO: Sane cursor flashing indication that indicates // that the normal cursor movement didn't happen. } } #if DEBUG_KP_MAIN_WINDOW && 1 qCDebug(kpLogMainWindow) << "\t\tcheck (contentsX=" << d->scrollView->horizontalScrollBar()->value () << ",contentsY=" << d->scrollView->verticalScrollBar()->value () << ")" << endl; #endif } zoomToPost (); } //--------------------------------------------------------------------- // private void kpMainWindow::zoomToRect (const QRect &normalizedDocRect, bool accountForGrips, bool careAboutWidth, bool careAboutHeight) { #if DEBUG_KP_MAIN_WINDOW qCDebug(kpLogMainWindow) << "kpMainWindow::zoomToRect(normalizedDocRect=" << normalizedDocRect << ",accountForGrips=" << accountForGrips << ",careAboutWidth=" << careAboutWidth << ",careAboutHeight=" << careAboutHeight << ")"; #endif // You can't care about nothing. Q_ASSERT (careAboutWidth || careAboutHeight); // The size of the scroll view minus the current or future scrollbars. const QSize usableScrollArea (d->scrollView->maximumViewportSize().width() - d->scrollView->verticalScrollBar()->sizeHint().width(), d->scrollView->maximumViewportSize().height() - d->scrollView->horizontalScrollBar()->sizeHint().height()); #if DEBUG_KP_MAIN_WINDOW qCDebug(kpLogMainWindow) << "size=" << d->scrollView->maximumViewportSize() << "scrollbar w=" << d->scrollView->verticalScrollBar()->sizeHint().width() << "usableSize=" << usableScrollArea; #endif // Handle rounding error, mis-estimating the scroll view size and // cosmic rays. We do this because we really don't want unnecessary // scrollbars. This seems to need to be at least 2 for slotFitToWidth() // and friends. // least 2. // TODO: I might have fixed this but check later. const int slack = 0; // The grip and slack are in view coordinates but are never zoomed. const int viewWidth = usableScrollArea.width () - (accountForGrips ? kpGrip::Size : 0) - slack; const int viewHeight = usableScrollArea.height () - (accountForGrips ? kpGrip::Size : 0) - slack; // We want the selected document rectangle to fill the scroll view. // // The integer arithmetic rounds down, rather than to the nearest zoom // level, as rounding down guarantees that the view, at the zoom level, // will fit inside x . const int zoomX = careAboutWidth ? qMax (1, viewWidth * 100 / normalizedDocRect.width ()) : INT_MAX; const int zoomY = careAboutHeight ? qMax (1, viewHeight * 100 / normalizedDocRect.height ()) : INT_MAX; // Since kpView only supports identical horizontal and vertical zooms, // choose the one that will show the greatest amount of document // content. const int zoomLevel = qMin (zoomX, zoomY); #if DEBUG_KP_MAIN_WINDOW qCDebug(kpLogMainWindow) << "\tzoomX=" << zoomX << " zoomY=" << zoomY << " -> zoomLevel=" << zoomLevel << endl; #endif zoomToPre (zoomLevel); { d->mainView->setZoomLevel (zoomLevel, zoomLevel); const QPoint viewPoint = d->mainView->transformDocToView (normalizedDocRect.topLeft ()); d->scrollView->horizontalScrollBar()->setValue(viewPoint.x()); d->scrollView->verticalScrollBar()->setValue(viewPoint.y()); } zoomToPost (); } //--------------------------------------------------------------------- // public slot void kpMainWindow::slotActualSize () { zoomTo (100); } //--------------------------------------------------------------------- // public slot void kpMainWindow::slotFitToPage () { if ( d->document ) { zoomToRect ( d->document->rect (), true/*account for grips*/, true/*care about width*/, true/*care about height*/); } } //--------------------------------------------------------------------- // public slot void kpMainWindow::slotFitToWidth () { if ( d->document ) { const QRect docRect ( 0/*x*/, - (int) d->mainView->transformViewToDocY (d->scrollView->verticalScrollBar()->value ())/*maintain y*/, - d->document->width (), - 1/*don't care about height*/); + static_cast (d->mainView->transformViewToDocY (d->scrollView->verticalScrollBar()->value ()))/*maintain y*/, + d->document->width (), + 1/*don't care about height*/); zoomToRect ( docRect, true/*account for grips*/, true/*care about width*/, false/*don't care about height*/); } } //--------------------------------------------------------------------- // public slot void kpMainWindow::slotFitToHeight () { if ( d->document ) { const QRect docRect ( - (int) d->mainView->transformViewToDocX (d->scrollView->horizontalScrollBar()->value ())/*maintain x*/, - 0/*y*/, - 1/*don't care about width*/, - d->document->height ()); + static_cast (d->mainView->transformViewToDocX (d->scrollView->horizontalScrollBar()->value ()))/*maintain x*/, + 0/*y*/, + 1/*don't care about width*/, + d->document->height ()); zoomToRect ( docRect, true/*account for grips*/, false/*don't care about width*/, true/*care about height*/); } } //--------------------------------------------------------------------- // public void kpMainWindow::zoomIn (bool centerUnderCursor) { #if DEBUG_KP_MAIN_WINDOW qCDebug(kpLogMainWindow) << "kpMainWindow::zoomIn(centerUnderCursor=" << centerUnderCursor << ") currentItem=" << d->actionZoom->currentItem () << endl; #endif const int targetItem = d->actionZoom->currentItem () + 1; - if (targetItem >= (int) d->zoomList.count ()) + if (targetItem >= static_cast (d->zoomList.count ())) return; d->actionZoom->setCurrentItem (targetItem); #if DEBUG_KP_MAIN_WINDOW qCDebug(kpLogMainWindow) << "\tnew currentItem=" << d->actionZoom->currentItem (); #endif zoomAccordingToZoomAction (centerUnderCursor); } //--------------------------------------------------------------------- // public void kpMainWindow::zoomOut (bool centerUnderCursor) { #if DEBUG_KP_MAIN_WINDOW qCDebug(kpLogMainWindow) << "kpMainWindow::zoomOut(centerUnderCursor=" << centerUnderCursor << ") currentItem=" << d->actionZoom->currentItem () << endl; #endif const int targetItem = d->actionZoom->currentItem () - 1; if (targetItem < 0) return; d->actionZoom->setCurrentItem (targetItem); #if DEBUG_KP_MAIN_WINDOW qCDebug(kpLogMainWindow) << "\tnew currentItem=" << d->actionZoom->currentItem (); #endif zoomAccordingToZoomAction (centerUnderCursor); } //--------------------------------------------------------------------- // public slot void kpMainWindow::slotZoomIn () { #if DEBUG_KP_MAIN_WINDOW qCDebug(kpLogMainWindow) << "kpMainWindow::slotZoomIn ()"; #endif zoomIn (false/*don't center under cursor*/); } //--------------------------------------------------------------------- // public slot void kpMainWindow::slotZoomOut () { #if DEBUG_KP_MAIN_WINDOW qCDebug(kpLogMainWindow) << "kpMainWindow::slotZoomOut ()"; #endif zoomOut (false/*don't center under cursor*/); } //--------------------------------------------------------------------- // public void kpMainWindow::zoomAccordingToZoomAction (bool centerUnderCursor) { #if DEBUG_KP_MAIN_WINDOW qCDebug(kpLogMainWindow) << "kpMainWindow::zoomAccordingToZoomAction(centerUnderCursor=" << centerUnderCursor << ") currentItem=" << d->actionZoom->currentItem () << " currentText=" << d->actionZoom->currentText () << endl; #endif // This might be a new zoom level the user has typed in. zoomTo (::ZoomLevelFromString (d->actionZoom->currentText ()), centerUnderCursor); } //--------------------------------------------------------------------- // private slot void kpMainWindow::slotZoom () { #if DEBUG_KP_MAIN_WINDOW qCDebug(kpLogMainWindow) << "kpMainWindow::slotZoom () index=" << d->actionZoom->currentItem () << " text='" << d->actionZoom->currentText () << "'" << endl; #endif zoomAccordingToZoomAction (false/*don't center under cursor*/); } //--------------------------------------------------------------------- diff --git a/pixmapfx/kpPixmapFX_DrawShapes.cpp b/pixmapfx/kpPixmapFX_DrawShapes.cpp index 10dfb8ae..03a6dff7 100644 --- a/pixmapfx/kpPixmapFX_DrawShapes.cpp +++ b/pixmapfx/kpPixmapFX_DrawShapes.cpp @@ -1,278 +1,278 @@ /* Copyright (c) 2003-2007 Clarence Dang 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_PIXMAP_FX 0 #include "kpPixmapFX.h" #include #include #include #include #include #include #include "kpLogCategories.h" #include "layers/selections/kpAbstractSelection.h" #include "imagelib/kpColor.h" #include "kpDefs.h" //--------------------------------------------------------------------- // Returns whether there is only 1 distinct point in . bool kpPixmapFX::Only1PixelInPointArray (const QPolygon &points) { if (points.count () == 0) return false; - for (int i = 1; i < (int) points.count (); i++) + for (int i = 1; i < static_cast (points.count ()); i++) { if (points [i] != points [0]) return false; } return true; } //--------------------------------------------------------------------- // Warp the given from 1 to 0. // This is not always done (specifically if ) because // width 0 sometimes looks worse. // // Qt lines of width 1 look like they have a width between 1-2 i.e.: // // # // ## // # // # // // compared to Qt's special "width 0" which just means a "proper" width 1: // // # // # // # // # // static int WidthToQPenWidth (int width, bool drawingEllipse = false) { if (width == 1) { // 3x10 ellipse with Qt width 0 looks like rectangle. // Therefore, do not apply this 1 -> 0 transformations for ellipses. if (!drawingEllipse) { // Closer to looking width 1, for lines at least. return 0; } } return width; } //--------------------------------------------------------------------- static void QPainterSetPenWithStipple (QPainter *p, const kpColor &fColor, int penWidth, const kpColor &fStippleColor = kpColor::Invalid, bool isEllipseLike = false) { if (!fStippleColor.isValid ()) { p->setPen ( kpPixmapFX::QPainterDrawLinePen ( fColor.toQColor(), ::WidthToQPenWidth (penWidth, isEllipseLike))); } else { QPen usePen = kpPixmapFX::QPainterDrawLinePen ( fColor.toQColor(), ::WidthToQPenWidth (penWidth, isEllipseLike)); usePen.setStyle (Qt::DashLine); p->setPen (usePen); p->setBackground (fStippleColor.toQColor()); p->setBackgroundMode (Qt::OpaqueMode); } } //--------------------------------------------------------------------- // public static QPen kpPixmapFX::QPainterDrawRectPen (const QColor &color, int qtWidth) { return QPen (color, qtWidth, Qt::SolidLine, Qt::SquareCap, Qt::MiterJoin); } //--------------------------------------------------------------------- // public static QPen kpPixmapFX::QPainterDrawLinePen (const QColor &color, int qtWidth) { return QPen (color, qtWidth, Qt::SolidLine, Qt::RoundCap, Qt::RoundJoin); } //--------------------------------------------------------------------- // // drawPolyline() / drawLine() // // public static void kpPixmapFX::drawPolyline (QImage *image, const QPolygon &points, const kpColor &color, int penWidth, const kpColor &stippleColor) { QPainter painter(image); ::QPainterSetPenWithStipple(&painter, color, penWidth, stippleColor); // Qt bug: single point doesn't show up depending on penWidth. if (Only1PixelInPointArray(points)) { #if DEBUG_KP_PIXMAP_FX qCDebug(kpLogPixmapfx) << "\tinvoking single point hack"; #endif painter.drawPoint(points[0]); return; } painter.drawPolyline(points); } //--------------------------------------------------------------------- // // drawPolygon() // // public static void kpPixmapFX::drawPolygon (QImage *image, const QPolygon &points, const kpColor &fcolor, int penWidth, const kpColor &bcolor, bool isFinal, const kpColor &fStippleColor) { QPainter p(image); ::QPainterSetPenWithStipple (&p, fcolor, penWidth, fStippleColor); if (bcolor.isValid ()) p.setBrush (QBrush (bcolor.toQColor())); // HACK: seems to be needed if set_Pen_(Qt::color0) else fills with Qt::color0. else p.setBrush (Qt::NoBrush); // Qt bug: single point doesn't show up depending on penWidth. if (Only1PixelInPointArray (points)) { #if DEBUG_KP_PIXMAP_FX qCDebug(kpLogPixmapfx) << "\tinvoking single point hack"; #endif p.drawPoint(points [0]); return; } // TODO: why aren't the ends rounded? p.drawPolygon(points, Qt::OddEvenFill); if ( isFinal ) return; if ( points.count() <= 2 ) return; p.setCompositionMode(QPainter::RasterOp_SourceXorDestination); p.setPen(QPen(Qt::white)); p.drawLine(points[0], points[points.count() - 1]); } //--------------------------------------------------------------------- // public static void kpPixmapFX::fillRect (QImage *image, int x, int y, int width, int height, const kpColor &color, const kpColor &stippleColor) { QPainter painter(image); if (!stippleColor.isValid ()) { painter.fillRect (x, y, width, height, color.toQColor()); } else { const int StippleSize = 4; painter.setClipRect (x, y, width, height); for (int dy = 0; dy < height; dy += StippleSize) { for (int dx = 0; dx < width; dx += StippleSize) { const bool parity = ((dy + dx) / StippleSize) % 2; kpColor useColor; if (!parity) useColor = color; else useColor = stippleColor; painter.fillRect (x + dx, y + dy, StippleSize, StippleSize, useColor.toQColor()); } } } } //--------------------------------------------------------------------- void kpPixmapFX::drawStippleRect(QImage *image, int x, int y, int width, int height, const kpColor &fColor, const kpColor &fStippleColor) { QPainter painter(image); painter.setPen(QPen(fColor.toQColor(), 1, Qt::DashLine)); painter.setBackground(fStippleColor.toQColor()); painter.setBackgroundMode(Qt::OpaqueMode); painter.drawRect(x, y, width - 1, height - 1); } //--------------------------------------------------------------------- diff --git a/pixmapfx/kpPixmapFX_Transforms.cpp b/pixmapfx/kpPixmapFX_Transforms.cpp index b85bb6b6..1d83e0cb 100644 --- a/pixmapfx/kpPixmapFX_Transforms.cpp +++ b/pixmapfx/kpPixmapFX_Transforms.cpp @@ -1,674 +1,674 @@ /* Copyright (c) 2003-2007 Clarence Dang 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_PIXMAP_FX 0 #include "kpPixmapFX.h" #include #include #include #include #include #include "kpLogCategories.h" #include "layers/selections/kpAbstractSelection.h" #include "imagelib/kpColor.h" #include "kpDefs.h" //--------------------------------------------------------------------- // public static void kpPixmapFX::resize (QImage *destPtr, int w, int h, const kpColor &backgroundColor) { #if DEBUG_KP_PIXMAP_FX && 1 qCDebug(kpLogPixmapfx) << "kpPixmapFX::resize()"; #endif if (!destPtr) return; const int oldWidth = destPtr->width (); const int oldHeight = destPtr->height (); if (w == oldWidth && h == oldHeight) return; QImage newImage (w, h, QImage::Format_ARGB32_Premultiplied); // Would have new undefined areas? if (w > oldWidth || h > oldHeight) newImage.fill (backgroundColor.toQRgb ()); // Copy over old pixmap. QPainter painter(&newImage); painter.setCompositionMode(QPainter::CompositionMode_Source); painter.drawImage(0, 0, *destPtr); painter.end(); // Replace pixmap with new one. *destPtr = newImage; } //--------------------------------------------------------------------- // public static QImage kpPixmapFX::resize (const QImage &image, int w, int h, const kpColor &backgroundColor) { QImage ret = image; kpPixmapFX::resize (&ret, w, h, backgroundColor); return ret; } //--------------------------------------------------------------------- // public static void kpPixmapFX::scale (QImage *destPtr, int w, int h, bool pretty) { if (!destPtr) return; *destPtr = kpPixmapFX::scale (*destPtr, w, h, pretty); } //--------------------------------------------------------------------- // public static QImage kpPixmapFX::scale (const QImage &image, int w, int h, bool pretty) { #if DEBUG_KP_PIXMAP_FX && 0 qCDebug(kpLogPixmapfx) << "kpPixmapFX::scale(oldRect=" << image.rect () << ",w=" << w << ",h=" << h << ",pretty=" << pretty << ")" << endl; #endif if (w == image.width () && h == image.height ()) return image; return image.scaled(w, h, Qt::IgnoreAspectRatio, pretty ? Qt::SmoothTransformation : Qt::FastTransformation); } //--------------------------------------------------------------------- // public static const double kpPixmapFX::AngleInDegreesEpsilon = KP_RADIANS_TO_DEGREES (atan (1.0 / 10000.0)) / (2.0/*max error allowed*/ * 2.0/*for good measure*/); static void MatrixDebug (const QString matrixName, const QMatrix &matrix, int srcPixmapWidth = -1, int srcPixmapHeight = -1) { #if DEBUG_KP_PIXMAP_FX const int w = srcPixmapWidth, h = srcPixmapHeight; qCDebug(kpLogPixmapfx) << matrixName << "=" << matrix; // Sometimes this precision lets us see unexpected rounding errors. fprintf (stderr, "m11=%.24f m12=%.24f m21=%.24f m22=%.24f dx=%.24f dy=%.24f\n", matrix.m11 (), matrix.m12 (), matrix.m21 (), matrix.m22 (), matrix.dx (), matrix.dy ()); if (w > 0 && h > 0) { qCDebug(kpLogPixmapfx) << "(0,0) ->" << matrix.map (QPoint (0, 0)); qCDebug(kpLogPixmapfx) << "(w-1,0) ->" << matrix.map (QPoint (w - 1, 0)); qCDebug(kpLogPixmapfx) << "(0,h-1) ->" << matrix.map (QPoint (0, h - 1)); qCDebug(kpLogPixmapfx) << "(w-1,h-1) ->" << matrix.map (QPoint (w - 1, h - 1)); } #if 0 QMatrix trueMatrix = QPixmap::trueMatrix (matrix, w, h); qCDebug(kpLogPixmapfx) << matrixName << "trueMatrix=" << trueMatrix; if (w > 0 && h > 0) { qCDebug(kpLogPixmapfx) << "(0,0) ->" << trueMatrix.map (QPoint (0, 0)); qCDebug(kpLogPixmapfx) << "(w-1,0) ->" << trueMatrix.map (QPoint (w - 1, 0)); qCDebug(kpLogPixmapfx) << "(0,h-1) ->" << trueMatrix.map (QPoint (0, h - 1)); qCDebug(kpLogPixmapfx) << "(w-1,h-1) ->" << trueMatrix.map (QPoint (w - 1, h - 1)); } #endif #else Q_UNUSED (matrixName); Q_UNUSED (matrix); Q_UNUSED (srcPixmapWidth); Q_UNUSED (srcPixmapHeight); #endif // DEBUG_KP_PIXMAP_FX } //--------------------------------------------------------------------- // Theoretically, this should act the same as QPixmap::trueMatrix() but // it doesn't. As an example, if you rotate tests/transforms.png by 90 // degrees clockwise, this returns the correct of 26 but // QPixmap::trueMatrix() returns 27. // // You should use the returned matrix to map points accurately (e.g. selection // borders). For QPainter::drawPixmap()/drawImage() + setWorldMatrix() // rendering accuracy, pass the returned matrix through QPixmap::trueMatrix() // and use that. // // TODO: If you put the flipMatrix() of tests/transforms.png through this, // the output is the same as QPixmap::trueMatrix(): is one off // (dy=27 instead of 26). // SYNC: I bet this is a Qt4 bug. static QMatrix MatrixWithZeroOrigin (const QMatrix &matrix, int width, int height) { #if DEBUG_KP_PIXMAP_FX qCDebug(kpLogPixmapfx) << "matrixWithZeroOrigin(w=" << width << ",h=" << height << ")"; qCDebug(kpLogPixmapfx) << "\tmatrix: m11=" << matrix.m11 () << "m12=" << matrix.m12 () << "m21=" << matrix.m21 () << "m22=" << matrix.m22 () << "dx=" << matrix.dx () << "dy=" << matrix.dy (); #endif QRect mappedRect = matrix.mapRect (QRect (0, 0, width, height)); #if DEBUG_KP_PIXMAP_FX qCDebug(kpLogPixmapfx) << "\tmappedRect=" << mappedRect; #endif QMatrix translatedMatrix ( matrix.m11 (), matrix.m12 (), matrix.m21 (), matrix.m22 (), matrix.dx () - mappedRect.left (), matrix.dy () - mappedRect.top ()); #if DEBUG_KP_PIXMAP_FX qCDebug(kpLogPixmapfx) << "\treturning" << translatedMatrix; qCDebug(kpLogPixmapfx) << "(0,0) ->" << translatedMatrix.map (QPoint (0, 0)); qCDebug(kpLogPixmapfx) << "(w-1,0) ->" << translatedMatrix.map (QPoint (width - 1, 0)); qCDebug(kpLogPixmapfx) << "(0,h-1) ->" << translatedMatrix.map (QPoint (0, height - 1)); qCDebug(kpLogPixmapfx) << "(w-1,h-1) ->" << translatedMatrix.map (QPoint (width - 1, height - 1)); #endif return translatedMatrix; } //--------------------------------------------------------------------- static double TrueMatrixEpsilon = 0.000001; // An attempt to reverse tiny rounding errors introduced by QPixmap::trueMatrix() // when skewing tests/transforms.png by 45% horizontally (with TransformPixmap() // using a QPixmap painter, prior to the 2007-10-09 change -- did not test after // the change). // Unfortunately, this does not work enough to stop the rendering errors // that follow. But it was worth a try and might still help us given the // sometimes excessive aliasing QPainter::draw{Pixmap,Image}() gives us, when // QPainter::SmoothPixmapTransform is disabled. static double TrueMatrixFixInts (double x) { if (fabs (x - qRound (x)) < TrueMatrixEpsilon) return qRound (x); else return x; } //--------------------------------------------------------------------- static QMatrix TrueMatrix (const QMatrix &matrix, int srcPixmapWidth, int srcPixmapHeight) { ::MatrixDebug ("TrueMatrix(): org", matrix); const QMatrix truMat = QPixmap::trueMatrix (matrix, srcPixmapWidth, srcPixmapHeight); ::MatrixDebug ("TrueMatrix(): passed through QPixmap::trueMatrix()", truMat); const QMatrix retMat ( ::TrueMatrixFixInts (truMat.m11 ()), ::TrueMatrixFixInts (truMat.m12 ()), ::TrueMatrixFixInts (truMat.m21 ()), ::TrueMatrixFixInts (truMat.m22 ()), ::TrueMatrixFixInts (truMat.dx ()), ::TrueMatrixFixInts (truMat.dy ())); ::MatrixDebug ("TrueMatrix(): fixed ints", retMat); return retMat; } //--------------------------------------------------------------------- // Like QPixmap::transformed() but fills new areas with // (unless is invalid) and works around internal QMatrix // floating point -> integer oddities, that would otherwise give fatally // incorrect results. If you don't believe me on this latter point, compare // QPixmap::transformed() to us using a flip matrix or a rotate-by-multiple-of-90 // matrix on tests/transforms.png -- QPixmap::transformed()'s output is 1 // pixel too high or low depending on whether the matrix is passed through // QPixmap::trueMatrix(). // // Use and to specify the intended output size // of the pixmap. -1 if don't care. static QImage TransformPixmap (const QImage &pm, const QMatrix &transformMatrix_, const kpColor &backgroundColor, int targetWidth, int targetHeight) { QMatrix transformMatrix = transformMatrix_; #if DEBUG_KP_PIXMAP_FX && 1 qCDebug(kpLogPixmapfx) << "kppixmapfx.cpp: TransformPixmap(pm.size=" << pm.size () << ",targetWidth=" << targetWidth << ",targetHeight=" << targetHeight << ")" << endl; #endif QRect newRect = transformMatrix.mapRect (pm.rect ()); #if DEBUG_KP_PIXMAP_FX && 1 qCDebug(kpLogPixmapfx) << "\tmappedRect=" << newRect; #endif QMatrix scaleMatrix; if (targetWidth > 0 && targetWidth != newRect.width ()) { #if DEBUG_KP_PIXMAP_FX && 1 qCDebug(kpLogPixmapfx) << "\tadjusting for targetWidth"; #endif scaleMatrix.scale (double (targetWidth) / double (newRect.width ()), 1); } if (targetHeight > 0 && targetHeight != newRect.height ()) { #if DEBUG_KP_PIXMAP_FX && 1 qCDebug(kpLogPixmapfx) << "\tadjusting for targetHeight"; #endif scaleMatrix.scale (1, double (targetHeight) / double (newRect.height ())); } if (!scaleMatrix.isIdentity ()) { #if DEBUG_KP_PIXMAP_FX && 1 // TODO: What is going on here??? Why isn't matrix * working properly? QMatrix wrongMatrix = transformMatrix * scaleMatrix; QMatrix oldHat = transformMatrix; if (targetWidth > 0 && targetWidth != newRect.width ()) oldHat.scale (double (targetWidth) / double (newRect.width ()), 1); if (targetHeight > 0 && targetHeight != newRect.height ()) oldHat.scale (1, double (targetHeight) / double (newRect.height ())); QMatrix altHat = transformMatrix; altHat.scale ((targetWidth > 0 && targetWidth != newRect.width ()) ? double (targetWidth) / double (newRect.width ()) : 1, (targetHeight > 0 && targetHeight != newRect.height ()) ? double (targetHeight) / double (newRect.height ()) : 1); QMatrix correctMatrix = scaleMatrix * transformMatrix; qCDebug(kpLogPixmapfx) << "\tsupposedlyWrongMatrix: m11=" << wrongMatrix.m11 () // <<<---- this is the correct matrix??? << " m12=" << wrongMatrix.m12 () << " m21=" << wrongMatrix.m21 () << " m22=" << wrongMatrix.m22 () << " dx=" << wrongMatrix.dx () << " dy=" << wrongMatrix.dy () << " rect=" << wrongMatrix.mapRect (pm.rect ()) << endl << "\ti_used_to_use_thisMatrix: m11=" << oldHat.m11 () << " m12=" << oldHat.m12 () << " m21=" << oldHat.m21 () << " m22=" << oldHat.m22 () << " dx=" << oldHat.dx () << " dy=" << oldHat.dy () << " rect=" << oldHat.mapRect (pm.rect ()) << endl << "\tabove but scaled at the same time: m11=" << altHat.m11 () << " m12=" << altHat.m12 () << " m21=" << altHat.m21 () << " m22=" << altHat.m22 () << " dx=" << altHat.dx () << " dy=" << altHat.dy () << " rect=" << altHat.mapRect (pm.rect ()) << endl << "\tsupposedlyCorrectMatrix: m11=" << correctMatrix.m11 () << " m12=" << correctMatrix.m12 () << " m21=" << correctMatrix.m21 () << " m22=" << correctMatrix.m22 () << " dx=" << correctMatrix.dx () << " dy=" << correctMatrix.dy () << " rect=" << correctMatrix.mapRect (pm.rect ()) << endl; #endif transformMatrix = transformMatrix * scaleMatrix; newRect = transformMatrix.mapRect (pm.rect ()); #if DEBUG_KP_PIXMAP_FX && 1 qCDebug(kpLogPixmapfx) << "\tnewRect after targetWidth,targetHeight adjust=" << newRect; #endif } ::MatrixDebug ("TransformPixmap(): before trueMatrix", transformMatrix, pm.width (), pm.height ()); #if DEBUG_KP_PIXMAP_FX && 1 QMatrix oldMatrix = transformMatrix; #endif // Translate the matrix to account for Qt rounding errors, // so that flipping (if it used this method) and rotating by a multiple // of 90 degrees actually work as expected (try tests/transforms.png). // // SYNC: This was not required with Qt3 so we are actually working // around a Qt4 bug/feature. // // COMPAT: Qt4's rendering with a matrix enabled is low quality anyway // but does this reduce quality even further? // // With or without it, skews by 45 degrees with the QImage // painter below look bad (with it, you get an extra transparent // line on the right; without, you get only about 1/4 of a source // line on the left). In Qt3, with TrueMatrix(), the source // image is translated 1 pixel off the destination image. // // Also, if you skew a rectangular selection, the skewed selection // border does not line up with the skewed image data. // TODO: do we need to pass through this new matrix? transformMatrix = ::TrueMatrix (transformMatrix, pm.width (), pm.height ()); #if DEBUG_KP_PIXMAP_FX && 1 qCDebug(kpLogPixmapfx) << "trueMatrix changed matrix?" << (oldMatrix == transformMatrix); #endif ::MatrixDebug ("TransformPixmap(): after trueMatrix", transformMatrix, pm.width (), pm.height ()); QImage newQImage (targetWidth > 0 ? targetWidth : newRect.width (), targetHeight > 0 ? targetHeight : newRect.height (), QImage::Format_ARGB32_Premultiplied); if ((targetWidth > 0 && targetWidth != newRect.width ()) || (targetHeight > 0 && targetHeight != newRect.height ())) { #if DEBUG_KP_PIXMAP_FX && 1 qCDebug(kpLogPixmapfx) << "kppixmapfx.cpp: TransformPixmap(pm.size=" << pm.size () << ",targetWidth=" << targetWidth << ",targetHeight=" << targetHeight << ") newRect=" << newRect << " (you are a victim of rounding error)" << endl; #endif } #if DEBUG_KP_PIXMAP_FX && 0 qCDebug(kpLogPixmapfx) << "\ttranslate top=" << painter.xForm (QPoint (0, 0)); qCDebug(kpLogPixmapfx) << "\tmatrix: m11=" << painter.worldMatrix ().m11 () << " m12=" << painter.worldMatrix ().m12 () << " m21=" << painter.worldMatrix ().m21 () << " m22=" << painter.worldMatrix ().m22 () << " dx=" << painter.worldMatrix ().dx () << " dy=" << painter.worldMatrix ().dy () << endl; #endif // Note: Do _not_ use "p.setRenderHints (QPainter::SmoothPixmapTransform);" // as the user does not want their image to get blurier every // time they e.g. rotate it (especially important for multiples // of 90 degrees but also true for every other angle). Being a // pixel-based program, we generally like to preserve RGB values // and avoid unnecessary blurs -- in the worst case, we'd rather // drop pixels, than blur. QPainter p (&newQImage); { // Make sure transparent pixels are drawn into the destination image. p.setCompositionMode (QPainter::CompositionMode_Source); // Fill the entire new image with the background color. if (backgroundColor.isValid ()) { p.fillRect (newQImage.rect (), backgroundColor.toQColor ()); } p.setMatrix (transformMatrix); p.drawImage (QPoint (0, 0), pm); } p.end (); #if DEBUG_KP_PIXMAP_FX && 1 qCDebug(kpLogPixmapfx) << "Done" << endl << endl; #endif return newQImage; } //--------------------------------------------------------------------- // public static QMatrix kpPixmapFX::skewMatrix (int width, int height, double hangle, double vangle) { if (fabs (hangle - 0) < kpPixmapFX::AngleInDegreesEpsilon && fabs (vangle - 0) < kpPixmapFX::AngleInDegreesEpsilon) { return QMatrix (); } /* Diagram for completeness :) * * |---------- w ----------| * (0,0) * _ _______________________ (w,0) * | |\~_ va | * | | \ ~_ | * | |ha\ ~__ | * | \ ~__ | dy * h | \ ~___ | * | \ ~___ | * | | \ ~___| (w,w*tan(va)=dy) * | | \ * \ * _ |________\________|_____|\ vertical shear factor * (0,h) dx ^~_ | \ | * | ~_ \________\________ General Point (x,y) V * | ~__ \ Skewed Point (x + y*tan(ha),y + x*tan(va)) * (h*tan(ha)=dx,h) ~__ \ ^ * ~___ \ | * ~___ \ horizontal shear factor * Key: ~___\ * ha = hangle (w + h*tan(ha)=w+dx,h + w*tan(va)=w+dy) * va = vangle * * Skewing really just twists a rectangle into a parallelogram. * */ //QMatrix matrix (1, tan (KP_DEGREES_TO_RADIANS (vangle)), tan (KP_DEGREES_TO_RADIANS (hangle)), 1, 0, 0); // I think this is clearer than above :) QMatrix matrix; matrix.shear (tan (KP_DEGREES_TO_RADIANS (hangle)), tan (KP_DEGREES_TO_RADIANS (vangle))); return ::MatrixWithZeroOrigin (matrix, width, height); } //--------------------------------------------------------------------- // public static QMatrix kpPixmapFX::skewMatrix (const QImage &pixmap, double hangle, double vangle) { return kpPixmapFX::skewMatrix (pixmap.width (), pixmap.height (), hangle, vangle); } //--------------------------------------------------------------------- // public static void kpPixmapFX::skew (QImage *destPtr, double hangle, double vangle, const kpColor &backgroundColor, int targetWidth, int targetHeight) { if (!destPtr) return; *destPtr = kpPixmapFX::skew (*destPtr, hangle, vangle, backgroundColor, targetWidth, targetHeight); } //--------------------------------------------------------------------- // public static QImage kpPixmapFX::skew (const QImage &pm, double hangle, double vangle, const kpColor &backgroundColor, int targetWidth, int targetHeight) { #if DEBUG_KP_PIXMAP_FX qCDebug(kpLogPixmapfx) << "kpPixmapFX::skew() pm.width=" << pm.width () << " pm.height=" << pm.height () << " hangle=" << hangle << " vangle=" << vangle << " targetWidth=" << targetWidth << " targetHeight=" << targetHeight << endl; #endif if (fabs (hangle - 0) < kpPixmapFX::AngleInDegreesEpsilon && fabs (vangle - 0) < kpPixmapFX::AngleInDegreesEpsilon && (targetWidth <= 0 && targetHeight <= 0)/*don't want to scale?*/) { return pm; } if (fabs (hangle) > 90 - kpPixmapFX::AngleInDegreesEpsilon || fabs (vangle) > 90 - kpPixmapFX::AngleInDegreesEpsilon) { qCCritical(kpLogPixmapfx) << "kpPixmapFX::skew() passed hangle and/or vangle out of range (-90 < x < 90)" << endl; return pm; } QMatrix matrix = skewMatrix (pm, hangle, vangle); return ::TransformPixmap (pm, matrix, backgroundColor, targetWidth, targetHeight); } //--------------------------------------------------------------------- // public static QMatrix kpPixmapFX::rotateMatrix (int width, int height, double angle) { if (fabs (angle - 0) < kpPixmapFX::AngleInDegreesEpsilon) { return QMatrix (); } QMatrix matrix; matrix.translate (width / 2, height / 2); matrix.rotate (angle); return ::MatrixWithZeroOrigin (matrix, width, height); } //--------------------------------------------------------------------- // public static QMatrix kpPixmapFX::rotateMatrix (const QImage &pixmap, double angle) { return kpPixmapFX::rotateMatrix (pixmap.width (), pixmap.height (), angle); } //--------------------------------------------------------------------- // public static bool kpPixmapFX::isLosslessRotation (double angle) { const double angleIn = angle; // Reflect angle into positive if negative if (angle < 0) angle = -angle; // Remove multiples of 90 to make sure 0 <= angle <= 90 - angle -= ((int) angle) / 90 * 90; + angle -= (static_cast (angle)) / 90 * 90; // "Impossible" situation? if (angle < 0 || angle > 90) { qCCritical(kpLogPixmapfx) << "kpPixmapFX::isLosslessRotation(" << angleIn << ") result=" << angle << endl; return false; // better safe than sorry } const bool ret = (angle < kpPixmapFX::AngleInDegreesEpsilon || 90 - angle < kpPixmapFX::AngleInDegreesEpsilon); #if DEBUG_KP_PIXMAP_FX qCDebug(kpLogPixmapfx) << "kpPixmapFX::isLosslessRotation(" << angleIn << ")" << " residual angle=" << angle << " returning " << ret << endl; #endif return ret; } //--------------------------------------------------------------------- // public static void kpPixmapFX::rotate (QImage *destPtr, double angle, const kpColor &backgroundColor, int targetWidth, int targetHeight) { if (!destPtr) return; *destPtr = kpPixmapFX::rotate (*destPtr, angle, backgroundColor, targetWidth, targetHeight); } //--------------------------------------------------------------------- // public static QImage kpPixmapFX::rotate (const QImage &pm, double angle, const kpColor &backgroundColor, int targetWidth, int targetHeight) { if (fabs (angle - 0) < kpPixmapFX::AngleInDegreesEpsilon && (targetWidth <= 0 && targetHeight <= 0)/*don't want to scale?*/) { return pm; } QMatrix matrix = rotateMatrix (pm, angle); return ::TransformPixmap (pm, matrix, backgroundColor, targetWidth, targetHeight); } //--------------------------------------------------------------------- diff --git a/scan/sanedialog.cpp b/scan/sanedialog.cpp index 434b8981..f79eb82f 100644 --- a/scan/sanedialog.cpp +++ b/scan/sanedialog.cpp @@ -1,118 +1,118 @@ /* ============================================================ * * Date : 2008-04-17 * Description : Sane plugin interface for KDE * * Copyright (C) 2008 by Kare Sars * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) version 3, or any * later version accepted by the membership of KDE e.V. (or its * successor approved by the membership of KDE e.V.), which shall * act as a proxy defined in Section 6 of version 3 of the license. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this program. If not, see . * * ============================================================ */ #include "sanedialog.h" #include #include "kpLogCategories.h" #include #include #include #include #include SaneDialog::SaneDialog(QWidget *parent) : KPageDialog(parent) { - setFaceType((KPageDialog::FaceType)Plain); + setFaceType(static_cast (Plain)); setWindowTitle(i18nc("@title:window", "Acquire Image")); buttonBox()->setStandardButtons(QDialogButtonBox::Close); buttonBox()->button(QDialogButtonBox::Close)->setDefault(true); m_ksanew = new KSaneIface::KSaneWidget(this); addPage(m_ksanew, QString()); connect(m_ksanew, SIGNAL(imageReady(QByteArray&,int,int,int,int)), this, SLOT(imageReady(QByteArray&,int,int,int,int))); m_openDev = QString(); } bool SaneDialog::setup() { if(!m_ksanew) { // new failed return false; } if (!m_openDev.isEmpty()) { return true; } // need to select a scanner m_openDev = m_ksanew->selectDevice(0); if (m_openDev.isEmpty()) { // either no scanner was found or then cancel was pressed. return false; } if (m_ksanew->openDevice(m_openDev) == false) { // could not open the scanner KMessageBox::sorry(0, i18n("Opening the selected scanner failed.")); m_openDev = QString(); return false; } // restore scan dialog size and all options for the selected device if available KSharedConfigPtr configPtr = KSharedConfig::openConfig("scannersettings"); KWindowConfig::restoreWindowSize(windowHandle(), KConfigGroup(configPtr, "ScanDialog")); QString groupName = m_openDev; if (configPtr->hasGroup(groupName)) { KConfigGroup group(configPtr, groupName); QStringList keys = group.keyList(); for (int i = 0; i < keys.count(); i++) m_ksanew->setOptVal(keys[i], group.readEntry(keys[i])); } return true; } SaneDialog::~SaneDialog() { if (m_ksanew && !m_openDev.isEmpty()) { // save scan dialog size and all options for the selected device if available KSharedConfigPtr configPtr = KSharedConfig::openConfig("scannersettings"); KConfigGroup group(configPtr, "ScanDialog"); KWindowConfig::saveWindowSize(windowHandle(), group, KConfigGroup::Persistent); group = configPtr->group(m_openDev); QMap opts; m_ksanew->getOptVals(opts); QMap::const_iterator i = opts.constBegin(); for (; i != opts.constEnd(); ++i) group.writeEntry(i.key(), i.value(), KConfigGroup::Persistent); } } void SaneDialog::imageReady(QByteArray &data, int w, int h, int bpl, int f) { /* copy the image data into img */ - QImage img = m_ksanew->toQImage(data, w, h, bpl, (KSaneIface::KSaneWidget::ImageFormat)f); + QImage img = m_ksanew->toQImage(data, w, h, bpl, static_cast (f)); emit finalImage(img, nextId()); } int SaneDialog::nextId() { return ++m_currentId; } diff --git a/tools/kpTool.cpp b/tools/kpTool.cpp index 92813a21..bfdfd036 100644 --- a/tools/kpTool.cpp +++ b/tools/kpTool.cpp @@ -1,262 +1,262 @@ /* Copyright (c) 2003-2007 Clarence Dang 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. */ // // Tool initialisation and basic accessors. // #define DEBUG_KP_TOOL 0 #include "kpTool.h" #include "kpToolPrivate.h" #include #include #include "kpLogCategories.h" #include #include "imagelib/kpColor.h" #include "widgets/toolbars/kpColorToolBar.h" #include "kpDefs.h" #include "tools/kpToolAction.h" #include "environments/tools/kpToolEnvironment.h" #include "widgets/toolbars/kpToolToolBar.h" #include "views/kpView.h" #include "views/manager/kpViewManager.h" #undef environ // macro on win32 //--------------------------------------------------------------------- kpTool::kpTool(const QString &text, const QString &description, int key, kpToolEnvironment *environ, QObject *parent, const QString &name) : QObject(parent), d(new kpToolPrivate()) { d->key = key; d->action = nullptr; d->ignoreColorSignals = 0; d->shiftPressed = false; d->controlPressed = false; d->altPressed = false; // set in beginInternal() d->beganDraw = false; d->text = text; d->description = description; d->began = false; d->viewUnderStartPoint = nullptr; d->userShapeStartPoint = KP_INVALID_POINT; d->userShapeEndPoint = KP_INVALID_POINT; d->userShapeSize = KP_INVALID_SIZE; d->environ = environ; setObjectName(name); initAction(); } //--------------------------------------------------------------------- kpTool::~kpTool () { // before destructing, stop using the tool if (d->began) endInternal (); delete d->action; delete d; } //--------------------------------------------------------------------- // private void kpTool::initAction () { KActionCollection *ac = d->environ->actionCollection (); Q_ASSERT (ac); d->action = new kpToolAction(text(), objectName(), shortcutForKey(d->key), this, SIGNAL(actionActivated()), ac, objectName()); // Make tools mutually exclusive by placing them in the same group. d->action->setActionGroup(d->environ->toolsActionGroup ()); d->action->setWhatsThis(d->description); connect(d->action, SIGNAL(changed()), this, SIGNAL (actionToolTipChanged())); } //--------------------------------------------------------------------- // public QString kpTool::text () const { return d->text; } //--------------------------------------------------------------------- static bool KeyIsText (int key) { // TODO: should work like !QKeyEvent::text().isEmpty() - return !(key & (Qt::KeyboardModifierMask ^ Qt::ShiftModifier)); + return !(static_cast (key) & (Qt::KeyboardModifierMask ^ Qt::ShiftModifier)); } //--------------------------------------------------------------------- // public static QString kpTool::toolTipForTextAndShortcut (const QString &text, const QList &shortcut) { foreach(const QKeySequence &seq, shortcut) { if (seq.count () == 1 && ::KeyIsText (seq [0])) return i18nc (" ()", "%1 (%2)", text, seq.toString ().toUpper ()); } return text; } //--------------------------------------------------------------------- QString kpTool::toolTip () const { return toolTipForTextAndShortcut(d->text, d->action->shortcuts()); } //--------------------------------------------------------------------- // public static QList kpTool::shortcutForKey (int key) { QList shortcut; if (key) { shortcut.append (QKeySequence (key)); // (CTRL+, ALT+, CTRL+ALT+, CTRL+SHIFT+ // all clash with global KDE shortcuts) - shortcut.append (QKeySequence (Qt::ALT + Qt::SHIFT + key)); + shortcut.append (QKeySequence (static_cast(Qt::ALT) + static_cast(Qt::SHIFT) + key)); } return shortcut; } //--------------------------------------------------------------------- // public kpToolAction *kpTool::action () const { return d->action; } //--------------------------------------------------------------------- kpDocument *kpTool::document () const { return d->environ->document (); } //--------------------------------------------------------------------- kpViewManager *kpTool::viewManager () const { return d->environ->viewManager (); } //--------------------------------------------------------------------- kpToolToolBar *kpTool::toolToolBar () const { return d->environ->toolToolBar (); } //--------------------------------------------------------------------- kpColor kpTool::color (int which) const { return d->environ->color (which); } //--------------------------------------------------------------------- kpColor kpTool::foregroundColor () const { return color (0); } //--------------------------------------------------------------------- kpColor kpTool::backgroundColor () const { return color (1); } //--------------------------------------------------------------------- // TODO: Some of these might not be common enough. // Just put in kpToolEnvironment? double kpTool::colorSimilarity () const { return d->environ->colorSimilarity (); } int kpTool::processedColorSimilarity () const { return d->environ->processedColorSimilarity (); } kpColor kpTool::oldForegroundColor () const { return d->environ->oldForegroundColor (); } kpColor kpTool::oldBackgroundColor () const { return d->environ->oldBackgroundColor (); } double kpTool::oldColorSimilarity () const { return d->environ->oldColorSimilarity (); } kpCommandHistory *kpTool::commandHistory () const { return d->environ->commandHistory (); } kpToolEnvironment *kpTool::environ () const { return d->environ; } diff --git a/tools/polygonal/kpToolPolygonalBase.cpp b/tools/polygonal/kpToolPolygonalBase.cpp index 8aa8667a..04e41fd4 100644 --- a/tools/polygonal/kpToolPolygonalBase.cpp +++ b/tools/polygonal/kpToolPolygonalBase.cpp @@ -1,495 +1,495 @@ /* Copyright (c) 2003-2007 Clarence Dang All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #define DEBUG_KP_TOOL_POLYGON 0 #include "kpToolPolygonalBase.h" #include #include #include #include #include #include #include #include "kpLogCategories.h" #include "commands/kpCommandHistory.h" #include "document/kpDocument.h" #include "kpDefs.h" #include "imagelib/kpImage.h" #include "imagelib/kpPainter.h" #include "pixmapfx/kpPixmapFX.h" #include "layers/tempImage/kpTempImage.h" #include "environments/tools/kpToolEnvironment.h" #include "commands/tools/polygonal/kpToolPolygonalCommand.h" #include "widgets/toolbars/kpToolToolBar.h" #include "widgets/toolbars/options/kpToolWidgetLineWidth.h" #include "views/manager/kpViewManager.h" struct kpToolPolygonalBasePrivate { kpToolPolygonalBasePrivate () : drawShapeFunc(nullptr), toolWidgetLineWidth(nullptr), originatingMouseButton(-1) { } kpToolPolygonalBase::DrawShapeFunc drawShapeFunc; kpToolWidgetLineWidth *toolWidgetLineWidth; int originatingMouseButton; QPolygon points; }; //--------------------------------------------------------------------- kpToolPolygonalBase::kpToolPolygonalBase ( const QString &text, const QString &description, DrawShapeFunc drawShapeFunc, int key, kpToolEnvironment *environ, QObject *parent, const QString &name) : kpTool (text, description, key, environ, parent, name), d (new kpToolPolygonalBasePrivate ()) { d->drawShapeFunc = drawShapeFunc; d->toolWidgetLineWidth = nullptr; // (hopefully cause crash if we use it before initialising it) d->originatingMouseButton = -1; } //--------------------------------------------------------------------- kpToolPolygonalBase::~kpToolPolygonalBase () { delete d; } //--------------------------------------------------------------------- // virtual void kpToolPolygonalBase::begin () { kpToolToolBar *tb = toolToolBar (); Q_ASSERT (tb); #if DEBUG_KP_TOOL_POLYGON qCDebug(kpLogTools) << "kpToolPolygonalBase::begin() tb=" << tb; #endif d->toolWidgetLineWidth = tb->toolWidgetLineWidth (); connect (d->toolWidgetLineWidth, SIGNAL (lineWidthChanged(int)), this, SLOT (updateShape())); d->toolWidgetLineWidth->show (); viewManager ()->setCursor (QCursor (Qt::ArrowCursor)); d->originatingMouseButton = -1; setUserMessage (/*virtual*/haventBegunShapeUserMessage ()); } //--------------------------------------------------------------------- // virtual void kpToolPolygonalBase::end () { // TODO: needed? endShape (); disconnect (d->toolWidgetLineWidth, SIGNAL (lineWidthChanged(int)), this, SLOT (updateShape())); d->toolWidgetLineWidth = nullptr; viewManager ()->unsetCursor (); } void kpToolPolygonalBase::beginDraw () { #if DEBUG_KP_TOOL_POLYGON qCDebug(kpLogTools) << "kpToolPolygonalBase::beginDraw() d->points=" << d->points.toList () << ", startPoint=" << startPoint () << endl; #endif bool endedShape = false; // We now need to start with dragging out the initial line? if (d->points.count () == 0) { d->originatingMouseButton = mouseButton (); // The line starts and ends at the start point of the drag. // draw() will modify the last point in d->points to reflect the // mouse drag, as the drag proceeds. d->points.append (startPoint ()); d->points.append (startPoint ()); } // Already have control points - not dragging out initial line. else { // Clicking the other mouse button? if (mouseButton () != d->originatingMouseButton) { // Finish shape. TODO: I suspect we need to call endShapeInternal instead. endShape (); endedShape = true; } // Are we dragging out an extra control point? else { // Add another control point. d->points.append (startPoint ()); } } #if DEBUG_KP_TOOL_POLYGON qCDebug(kpLogTools) << "\tafterwards, d->points=" << d->points.toList (); #endif if (!endedShape) { // We've started dragging. Print instructions on how to cancel shape. setUserMessage (cancelUserMessage ()); } } // protected void kpToolPolygonalBase::applyModifiers () { const int count = d->points.count (); QPoint &lineStartPoint = d->points [count - 2]; QPoint &lineEndPoint = d->points [count - 1]; #if DEBUG_KP_TOOL_POLYGON && 1 qCDebug(kpLogTools) << "kpToolPolygonalBase::applyModifiers() #pts=" << count << " line: startPt=" << lineStartPoint << " endPt=" << lineEndPoint << " modifiers: shift=" << shiftPressed () << " alt=" << altPressed () << " ctrl=" << controlPressed () << endl; #endif // angles if (shiftPressed () || controlPressed ()) { int diffx = lineEndPoint.x () - lineStartPoint.x (); int diffy = lineEndPoint.y () - lineStartPoint.y (); double ratio; if (diffx == 0) ratio = DBL_MAX; else ratio = fabs (double (diffy) / double (diffx)); #if DEBUG_KP_TOOL_POLYGON && 1 qCDebug(kpLogTools) << "\tdiffx=" << diffx << " diffy=" << diffy << " ratio=" << ratio << endl; #endif // Shift = 0, 45, 90 // Ctrl = 0, 30, 60, 90 // Shift + Ctrl = 0, 30, 45, 60, 90 double angles [10]; // "ought to be enough for anybody" int numAngles = 0; angles [numAngles++] = 0; if (controlPressed ()) angles [numAngles++] = KP_PI / 6; if (shiftPressed ()) angles [numAngles++] = KP_PI / 4; if (controlPressed ()) angles [numAngles++] = KP_PI / 3; angles [numAngles++] = KP_PI / 2; Q_ASSERT (numAngles <= int (sizeof (angles) / sizeof (angles [0]))); double angle = angles [numAngles - 1]; for (int i = 0; i < numAngles - 1; i++) { double acceptingRatio = tan ((angles [i] + angles [i + 1]) / 2.0); if (ratio < acceptingRatio) { angle = angles [i]; break; } } // horizontal (dist from start not maintained) if (fabs (KP_RADIANS_TO_DEGREES (angle) - 0) < kpPixmapFX::AngleInDegreesEpsilon) { lineEndPoint = QPoint (lineEndPoint.x (), lineStartPoint.y ()); } // vertical (dist from start not maintained) else if (fabs (KP_RADIANS_TO_DEGREES (angle) - 90) < kpPixmapFX::AngleInDegreesEpsilon) { lineEndPoint = QPoint (lineStartPoint.x (), lineEndPoint.y ()); } // diagonal (dist from start maintained) else { - const double dist = sqrt ((double)(diffx * diffx + diffy * diffy)); + const double dist = sqrt (static_cast (diffx * diffx + diffy * diffy)); #define sgn(a) ((a)<0?-1:1) // Round distances _before_ adding to any coordinate // (ensures consistent rounding behaviour in x & y directions) const int newdx = qRound (dist * cos (angle) * sgn (diffx)); const int newdy = qRound (dist * sin (angle) * sgn (diffy)); #undef sgn lineEndPoint = QPoint (lineStartPoint.x () + newdx, lineStartPoint.y () + newdy); #if DEBUG_KP_TOOL_POLYGON && 1 qCDebug(kpLogTools) << "\t\tdiagonal line: dist=" << dist << " angle=" << (angle * 180 / KP_PI) << " endPoint=" << lineEndPoint << endl; #endif } } // if (shiftPressed () || controlPressed ()) { // centring if (altPressed () && 0/*ALT is unreliable*/) { // start = start - diff // = start - (end - start) // = start - end + start // = 2 * start - end if (count == 2) lineStartPoint += (lineStartPoint - lineEndPoint); else lineEndPoint += (lineEndPoint - lineStartPoint); } // if (altPressed ()) { } // protected QPolygon *kpToolPolygonalBase::points () const { return &d->points; } // protected int kpToolPolygonalBase::originatingMouseButton () const { Q_ASSERT (hasBegunShape ()); return d->originatingMouseButton; } // virtual void kpToolPolygonalBase::draw (const QPoint &, const QPoint &, const QRect &) { // A click of the other mouse button (to finish shape, instead of adding // another control point) would have caused endShape() to have been // called in kpToolPolygonalBase::beginDraw(). The points list would now // be empty. We are being called by kpTool::mouseReleaseEvent(). if (d->points.count () == 0) return; #if DEBUG_KP_TOOL_POLYGON qCDebug(kpLogTools) << "kpToolPolygonalBase::draw() d->points=" << d->points.toList () << ", endPoint=" << currentPoint () << endl; #endif // Update points() so that last point reflects current mouse position. const int count = d->points.count (); d->points [count - 1] = currentPoint (); #if DEBUG_KP_TOOL_POLYGON qCDebug(kpLogTools) << "\tafterwards, d->points=" << d->points.toList (); #endif // Are we drawing a line? if (/*virtual*/drawingALine ()) { // Adjust the line (end points given by the last 2 points of points()) // in response to keyboard modifiers. applyModifiers (); // Update the preview of the shape. updateShape (); // Inform the user that we're dragging out a line with 2 control points. setUserShapePoints (d->points [count - 2], d->points [count - 1]); } // We're modifying a point. else { // Update the preview of the shape. updateShape (); // Informs the user that we're just modifying a point (perhaps, a control // point of a Bezier). setUserShapePoints (d->points [count - 1]); } } // TODO: code dup with kpToolRectangle // private kpColor kpToolPolygonalBase::drawingForegroundColor () const { return color (originatingMouseButton ()); } // protected virtual kpColor kpToolPolygonalBase::drawingBackgroundColor () const { return kpColor::Invalid; } // TODO: code dup with kpToolRectangle // protected slot void kpToolPolygonalBase::updateShape () { if (d->points.count () == 0) return; const QRect boundingRect = kpTool::neededRect ( d->points.boundingRect (), d->toolWidgetLineWidth->lineWidth ()); #if DEBUG_KP_TOOL_POLYGON qCDebug(kpLogTools) << "kpToolPolygonalBase::updateShape() boundingRect=" << boundingRect << " lineWidth=" << d->toolWidgetLineWidth->lineWidth () << endl; #endif kpImage image = document ()->getImageAt (boundingRect); QPolygon pointsTranslated = d->points; pointsTranslated.translate (-boundingRect.x (), -boundingRect.y ()); (*d->drawShapeFunc) (&image, pointsTranslated, drawingForegroundColor (), d->toolWidgetLineWidth->lineWidth (), /*virtual*/drawingBackgroundColor (), false/*not final*/); kpTempImage newTempImage (false/*always display*/, kpTempImage::SetImage/*render mode*/, boundingRect.topLeft (), image); viewManager ()->setFastUpdates (); { viewManager ()->setTempImage (newTempImage); } viewManager ()->restoreFastUpdates (); } // virtual void kpToolPolygonalBase::cancelShape () { viewManager ()->invalidateTempImage (); d->points.resize (0); setUserMessage (i18n ("Let go of all the mouse buttons.")); } void kpToolPolygonalBase::releasedAllButtons () { if (!hasBegunShape ()) setUserMessage (/*virtual*/haventBegunShapeUserMessage ()); // --- else case already handled by endDraw() --- } // public virtual [base kpTool] void kpToolPolygonalBase::endShape (const QPoint &, const QRect &) { #if DEBUG_KP_TOOL_POLYGON qCDebug(kpLogTools) << "kpToolPolygonalBase::endShape() d->points=" << d->points.toList () << endl; #endif if (!hasBegunShape ()) return; viewManager ()->invalidateTempImage (); QRect boundingRect = kpTool::neededRect ( d->points.boundingRect (), d->toolWidgetLineWidth->lineWidth ()); commandHistory ()->addCommand ( new kpToolPolygonalCommand ( text (), d->drawShapeFunc, d->points, boundingRect, drawingForegroundColor (), d->toolWidgetLineWidth->lineWidth (), /*virtual*/drawingBackgroundColor (), environ ()->commandEnvironment ())); d->points.resize (0); setUserMessage (/*virtual*/haventBegunShapeUserMessage ()); } // public virtual [base kpTool] bool kpToolPolygonalBase::hasBegunShape () const { return (d->points.count () > 0); } // virtual protected slot [base kpTool] void kpToolPolygonalBase::slotForegroundColorChanged (const kpColor &) { updateShape (); } // virtual protected slot [base kpTool] void kpToolPolygonalBase::slotBackgroundColorChanged (const kpColor &) { updateShape (); } diff --git a/tools/selection/image/kpToolFreeFormSelection.cpp b/tools/selection/image/kpToolFreeFormSelection.cpp index c61ea921..9381649e 100644 --- a/tools/selection/image/kpToolFreeFormSelection.cpp +++ b/tools/selection/image/kpToolFreeFormSelection.cpp @@ -1,141 +1,141 @@ /* Copyright (c) 2003-2007 Clarence Dang 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_FREE_FROM_SELECTION 0 #include "kpToolFreeFormSelection.h" #include "kpLogCategories.h" #include #include "document/kpDocument.h" #include "layers/selections/image/kpFreeFormImageSelection.h" #include "environments/tools/selection/kpToolSelectionEnvironment.h" //--------------------------------------------------------------------- kpToolFreeFormSelection::kpToolFreeFormSelection (kpToolSelectionEnvironment *environ, QObject *parent) : kpAbstractImageSelectionTool (i18n ("Selection (Free-Form)"), i18n ("Makes a free-form selection"), Qt::Key_M, environ, parent, "tool_free_form_selection") { } //--------------------------------------------------------------------- kpToolFreeFormSelection::~kpToolFreeFormSelection () { } //--------------------------------------------------------------------- // protected virtual [base kpAbstractSelectionTool] bool kpToolFreeFormSelection::drawCreateMoreSelectionAndUpdateStatusBar ( bool dragAccepted, const QPoint &accidentalDragAdjustedPoint, const QRect &/*normalizedRect*/) { #if DEBUG_KP_TOOL_FREE_FROM_SELECTION qCDebug(kpLogTools) << "kpToolFreeFormSelection::createMoreSelectionAndUpdateStatusBar(" << "dragAccepted=" << dragAccepted << ",accidentalDragAdjustedPoint=" << accidentalDragAdjustedPoint << ")" << endl; #endif // Prevent unintentional creation of 1-pixel selections. if (!dragAccepted && accidentalDragAdjustedPoint == startPoint ()) { #if DEBUG_KP_TOOL_FREE_FROM_SELECTION && 1 qCDebug(kpLogTools) << "\tnon-text NOP - return"; #endif setUserShapePoints (accidentalDragAdjustedPoint); return false; } Q_ASSERT (accidentalDragAdjustedPoint == currentPoint ()); - Q_ASSERT (dragAccepted == (bool) document ()->selection ()); + Q_ASSERT (dragAccepted == static_cast (document ()->selection ())); const kpFreeFormImageSelection *oldPointsSel = nullptr; if (document ()->selection ()) { kpAbstractSelection *sel = document ()->selection (); Q_ASSERT (dynamic_cast (sel)); - oldPointsSel = static_cast (sel); + oldPointsSel = dynamic_cast (sel); } QPolygon points; // First point in drag? if (!dragAccepted) { points.append (startPoint ()); } // Not first point in drag. else { if ( !oldPointsSel ) // assert above says we never reach this, but let's make coverity happy return false; // Get existing points in selection. points = oldPointsSel->cardinallyAdjacentPoints (); } #if DEBUG_KP_TOOL_FREE_FROM_SELECTION qCDebug(kpLogTools) << "\tlast old point=" << points.last (); #endif // TODO: There should be an upper limit on this before drawing the // polygon becomes too slow. points.append (accidentalDragAdjustedPoint); document ()->setSelection ( kpFreeFormImageSelection (points, environ ()->imageSelectionTransparency ())); // Prevent accidental usage of dangling pointer to old selection // (deleted by kpDocument::setSelection()). oldPointsSel = nullptr; #if DEBUG_KP_TOOL_FREE_FROM_SELECTION && 1 qCDebug(kpLogTools) << "\t\tfreeform; #points=" << document ()->selection ()->calculatePoints ().count () << endl; #endif setUserShapePoints (accidentalDragAdjustedPoint); return true; } //--------------------------------------------------------------------- diff --git a/tools/selection/text/kpToolText_CursorCalc.cpp b/tools/selection/text/kpToolText_CursorCalc.cpp index 25e81a68..dc838b79 100644 --- a/tools/selection/text/kpToolText_CursorCalc.cpp +++ b/tools/selection/text/kpToolText_CursorCalc.cpp @@ -1,212 +1,212 @@ /* Copyright (c) 2003-2007 Clarence Dang All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #define DEBUG_KP_TOOL_TEXT 0 #include "tools/selection/text/kpToolText.h" #include "kpLogCategories.h" #include "document/kpDocument.h" #include "layers/selections/text/kpTextSelection.h" #include "commands/tools/selection/text/kpToolTextBackspaceCommand.h" #include "commands/tools/selection/text/kpToolTextChangeStyleCommand.h" #include "commands/tools/selection/kpToolSelectionCreateCommand.h" #include "environments/tools/selection/kpToolSelectionEnvironment.h" #include "commands/tools/selection/text/kpToolTextDeleteCommand.h" #include "commands/tools/selection/text/kpToolTextEnterCommand.h" #include "commands/tools/selection/text/kpToolTextInsertCommand.h" #include "widgets/toolbars/options/kpToolWidgetOpaqueOrTransparent.h" #include "views/kpView.h" #include "views/manager/kpViewManager.h" #include #include // protected static bool kpToolText::CursorIsOnWordChar (const QList &textLines, int cursorRow, int cursorCol) { - return (cursorRow >= 0 && cursorRow < (int) textLines.size () && - cursorCol >= 0 && cursorCol < (int) textLines [cursorRow].length () && + return (cursorRow >= 0 && cursorRow < textLines.size () && + cursorCol >= 0 && cursorCol < textLines [cursorRow].length () && !textLines [cursorRow][cursorCol].isSpace ()); } // protected static bool kpToolText::CursorIsAtStart (const QList &, int cursorRow, int cursorCol) { return (cursorRow == 0 && cursorCol == 0); } // protected static bool kpToolText::CursorIsAtEnd (const QList &textLines, int cursorRow, int cursorCol) { if (textLines.isEmpty ()) return (cursorRow == 0 && cursorCol == 0); - return (cursorRow == (int) textLines.size () - 1 && - cursorCol == (int) textLines [cursorRow].length ()); + return (cursorRow == textLines.size () - 1 && + cursorCol == textLines [cursorRow].length ()); } // protected static void kpToolText::MoveCursorLeft (const QList &textLines, int *cursorRow, int *cursorCol) { if (textLines.isEmpty ()) return; (*cursorCol)--; if (*cursorCol < 0) { (*cursorRow)--; if (*cursorRow < 0) { *cursorRow = 0; *cursorCol = 0; } else *cursorCol = textLines [*cursorRow].length (); } } // protected static void kpToolText::MoveCursorRight (const QList &textLines, int *cursorRow, int *cursorCol) { if (textLines.isEmpty ()) return; (*cursorCol)++; - if (*cursorCol > (int) textLines [*cursorRow].length ()) + if (*cursorCol > textLines [*cursorRow].length ()) { (*cursorRow)++; - if (*cursorRow > (int) textLines.size () - 1) + if (*cursorRow > textLines.size () - 1) { *cursorRow = textLines.size () - 1; *cursorCol = textLines [*cursorRow].length (); } else *cursorCol = 0; } } #define IS_ON_SPACE_OR_EOL() !CursorIsOnWordChar (textLines, *cursorRow, *cursorCol) // protected static int kpToolText::MoveCursorToWordStart (const QList &textLines, int *cursorRow, int *cursorCol) { if (textLines.isEmpty ()) return 0; int numMoves = 0; #define IS_ON_ANCHOR() \ (CursorIsOnWordChar (textLines, *cursorRow, *cursorCol) && \ (cursorCol == 0 || \ !CursorIsOnWordChar (textLines, *cursorRow, *cursorCol - 1))) #define MOVE_CURSOR_LEFT() \ (MoveCursorLeft (textLines, cursorRow, cursorCol), ++numMoves) // (these comments will exclude the row=0,col=0 boundary case) if (IS_ON_ANCHOR ()) MOVE_CURSOR_LEFT (); // --- now we're not on an anchor point (start of word) --- // End up on a letter... while (!(*cursorRow == 0 && *cursorCol == 0) && (IS_ON_SPACE_OR_EOL ())) { MOVE_CURSOR_LEFT (); } // --- now we're on a letter --- // Find anchor point while (!(*cursorRow == 0 && *cursorCol == 0) && !IS_ON_ANCHOR ()) { MOVE_CURSOR_LEFT (); } #undef IS_ON_ANCHOR #undef MOVE_CURSOR_LEFT return numMoves; } // protected static int kpToolText::MoveCursorToNextWordStart (const QList &textLines, int *cursorRow, int *cursorCol) { if (textLines.isEmpty ()) return 0; int numMoves = 0; #define IS_AT_END() CursorIsAtEnd (textLines, *cursorRow, *cursorCol) #define MOVE_CURSOR_RIGHT() \ (MoveCursorRight (textLines, cursorRow, cursorCol), ++numMoves) // (these comments will exclude the last row,end col boundary case) // Find space while (!IS_AT_END () && !IS_ON_SPACE_OR_EOL ()) { MOVE_CURSOR_RIGHT (); } // --- now we're on a space --- // Find letter while (!IS_AT_END () && IS_ON_SPACE_OR_EOL ()) { MOVE_CURSOR_RIGHT (); } // --- now we're on a letter --- #undef IS_AT_END #undef MOVE_CURSOR_RIGHT return numMoves; } #undef IS_ON_SPACE_OR_EOL diff --git a/tools/selection/text/kpToolText_KeyboardEvents_HandleArrowKeys.cpp b/tools/selection/text/kpToolText_KeyboardEvents_HandleArrowKeys.cpp index 488da7f6..f5af7e5d 100644 --- a/tools/selection/text/kpToolText_KeyboardEvents_HandleArrowKeys.cpp +++ b/tools/selection/text/kpToolText_KeyboardEvents_HandleArrowKeys.cpp @@ -1,213 +1,213 @@ /* Copyright (c) 2003-2007 Clarence Dang All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #define DEBUG_KP_TOOL_TEXT 0 #include "tools/selection/text/kpToolText.h" #include "kpToolTextPrivate.h" #include #include #include "kpLogCategories.h" #include "commands/kpCommandHistory.h" #include "document/kpDocument.h" #include "layers/selections/text/kpTextSelection.h" #include "commands/tools/selection/text/kpToolTextBackspaceCommand.h" #include "commands/tools/selection/text/kpToolTextChangeStyleCommand.h" #include "commands/tools/selection/kpToolSelectionCreateCommand.h" #include "environments/tools/selection/kpToolSelectionEnvironment.h" #include "commands/tools/selection/text/kpToolTextDeleteCommand.h" #include "commands/tools/selection/text/kpToolTextEnterCommand.h" #include "commands/tools/selection/text/kpToolTextInsertCommand.h" #include "widgets/toolbars/options/kpToolWidgetOpaqueOrTransparent.h" #include "views/kpView.h" #include "views/manager/kpViewManager.h" // protected void kpToolText::handleUpKeyPress (QKeyEvent *e, const QList &textLines, int cursorRow, int cursorCol) { #if DEBUG_KP_TOOL_TEXT qCDebug(kpLogTools) << "\tup pressed"; #endif if (hasBegunShape ()) endShape (currentPoint (), normalizedRect ()); if (!textLines.isEmpty () && cursorRow > 0) { cursorRow--; - cursorCol = qMin (cursorCol, (int) textLines [cursorRow].length ()); + cursorCol = qMin (cursorCol, textLines [cursorRow].length ()); viewManager ()->setTextCursorPosition (cursorRow, cursorCol); } e->accept (); } // protected void kpToolText::handleDownKeyPress (QKeyEvent *e, const QList &textLines, int cursorRow, int cursorCol) { #if DEBUG_KP_TOOL_TEXT qCDebug(kpLogTools) << "\tdown pressed"; #endif if (hasBegunShape ()) endShape (currentPoint (), normalizedRect ()); - if (!textLines.isEmpty () && cursorRow < (int) textLines.size () - 1) + if (!textLines.isEmpty () && cursorRow < textLines.size () - 1) { cursorRow++; - cursorCol = qMin (cursorCol, (int) textLines [cursorRow].length ()); + cursorCol = qMin (cursorCol, textLines [cursorRow].length ()); viewManager ()->setTextCursorPosition (cursorRow, cursorCol); } e->accept (); } // protected void kpToolText::handleLeftKeyPress (QKeyEvent *e, const QList &textLines, int cursorRow, int cursorCol) { #if DEBUG_KP_TOOL_TEXT qCDebug(kpLogTools) << "\tleft pressed"; #endif if (hasBegunShape ()) endShape (currentPoint (), normalizedRect ()); if (!textLines.isEmpty ()) { if ((e->modifiers () & Qt::ControlModifier) == 0) { #if DEBUG_KP_TOOL_TEXT qCDebug(kpLogTools) << "\tmove single char"; #endif MoveCursorLeft (textLines, &cursorRow, &cursorCol); viewManager ()->setTextCursorPosition (cursorRow, cursorCol); } else { #if DEBUG_KP_TOOL_TEXT qCDebug(kpLogTools) << "\tmove to start of word"; #endif MoveCursorToWordStart (textLines, &cursorRow, &cursorCol); viewManager ()->setTextCursorPosition (cursorRow, cursorCol); } } e->accept (); } // protected void kpToolText::handleRightKeyPress (QKeyEvent *e, const QList &textLines, int cursorRow, int cursorCol) { #if DEBUG_KP_TOOL_TEXT qCDebug(kpLogTools) << "\tright pressed"; #endif if (hasBegunShape ()) endShape (currentPoint (), normalizedRect ()); if (!textLines.isEmpty ()) { if ((e->modifiers () & Qt::ControlModifier) == 0) { #if DEBUG_KP_TOOL_TEXT qCDebug(kpLogTools) << "\tmove single char"; #endif MoveCursorRight (textLines, &cursorRow, &cursorCol); viewManager ()->setTextCursorPosition (cursorRow, cursorCol); } else { #if DEBUG_KP_TOOL_TEXT qCDebug(kpLogTools) << "\tmove to start of next word"; #endif MoveCursorToNextWordStart (textLines, &cursorRow, &cursorCol); viewManager ()->setTextCursorPosition (cursorRow, cursorCol); } } e->accept (); } // protected void kpToolText::handleHomeKeyPress (QKeyEvent *e, const QList &textLines, int cursorRow, int cursorCol) { #if DEBUG_KP_TOOL_TEXT qCDebug(kpLogTools) << "\thome pressed"; #endif if (hasBegunShape ()) endShape (currentPoint (), normalizedRect ()); if (!textLines.isEmpty ()) { if (e->modifiers () & Qt::ControlModifier) cursorRow = 0; cursorCol = 0; viewManager ()->setTextCursorPosition (cursorRow, cursorCol); } e->accept (); } // protected void kpToolText::handleEndKeyPress (QKeyEvent *e, const QList &textLines, int cursorRow, int cursorCol) { #if DEBUG_KP_TOOL_TEXT qCDebug(kpLogTools) << "\tend pressed"; #endif if (hasBegunShape ()) endShape (currentPoint (), normalizedRect ()); if (!textLines.isEmpty ()) { if (e->modifiers () & Qt::ControlModifier) cursorRow = textLines.size () - 1; cursorCol = textLines [cursorRow].length (); viewManager ()->setTextCursorPosition (cursorRow, cursorCol); } e->accept (); } diff --git a/tools/selection/text/kpToolText_KeyboardEvents_HandleTypingKeys.cpp b/tools/selection/text/kpToolText_KeyboardEvents_HandleTypingKeys.cpp index 5ff6f449..622dbc83 100644 --- a/tools/selection/text/kpToolText_KeyboardEvents_HandleTypingKeys.cpp +++ b/tools/selection/text/kpToolText_KeyboardEvents_HandleTypingKeys.cpp @@ -1,193 +1,193 @@ /* Copyright (c) 2003-2007 Clarence Dang All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #define DEBUG_KP_TOOL_TEXT 0 #include "tools/selection/text/kpToolText.h" #include "kpToolTextPrivate.h" #include "kpLogCategories.h" #include "commands/kpCommandHistory.h" #include "document/kpDocument.h" #include "layers/selections/text/kpTextSelection.h" #include "commands/tools/selection/text/kpToolTextBackspaceCommand.h" #include "commands/tools/selection/text/kpToolTextChangeStyleCommand.h" #include "commands/tools/selection/kpToolSelectionCreateCommand.h" #include "environments/tools/selection/kpToolSelectionEnvironment.h" #include "commands/tools/selection/text/kpToolTextDeleteCommand.h" #include "commands/tools/selection/text/kpToolTextEnterCommand.h" #include "commands/tools/selection/text/kpToolTextInsertCommand.h" #include "widgets/toolbars/options/kpToolWidgetOpaqueOrTransparent.h" #include "views/kpView.h" #include "views/manager/kpViewManager.h" #include //--------------------------------------------------------------------- // protected void kpToolText::handleBackspaceKeyPress (QKeyEvent *e, const QList &textLines, int cursorRow, int cursorCol) { #if DEBUG_KP_TOOL_TEXT qCDebug(kpLogTools) << "\tbackspace pressed"; #endif if (!textLines.isEmpty ()) { if ((e->modifiers () & Qt::ControlModifier) == 0) { if (!d->backspaceCommand) addNewBackspaceCommand (&d->backspaceCommand); d->backspaceCommand->addBackspace (); } else { if (!d->backspaceWordCommand) addNewBackspaceCommand (&d->backspaceWordCommand); const int numMoves = MoveCursorToWordStart (textLines, &cursorRow, &cursorCol); viewManager ()->setQueueUpdates (); { for (int i = 0; i < numMoves; i++) d->backspaceWordCommand->addBackspace (); } viewManager ()->restoreQueueUpdates (); Q_ASSERT (cursorRow == viewManager ()->textCursorRow ()); Q_ASSERT (cursorCol == viewManager ()->textCursorCol ()); } } e->accept (); } //--------------------------------------------------------------------- // protected void kpToolText::handleDeleteKeyPress (QKeyEvent *e, const QList & textLines, int cursorRow, int cursorCol) { #if DEBUG_KP_TOOL_TEXT qCDebug(kpLogTools) << "\tdelete pressed"; #endif if (!textLines.isEmpty ()) { if ((e->modifiers () & Qt::ControlModifier) == 0) { if (!d->deleteCommand) addNewDeleteCommand (&d->deleteCommand); d->deleteCommand->addDelete (); } else { if (!d->deleteWordCommand) addNewDeleteCommand (&d->deleteWordCommand); // We don't want to know the cursor pos of the next word start // as delete should keep cursor in same pos. int cursorRowThrowAway = cursorRow, cursorColThrowAway = cursorCol; const int numMoves = MoveCursorToNextWordStart (textLines, &cursorRowThrowAway, &cursorColThrowAway); viewManager ()->setQueueUpdates (); { for (int i = 0; i < numMoves; i++) d->deleteWordCommand->addDelete (); } viewManager ()->restoreQueueUpdates (); // Assert unchanged as delete should keep cursor in same pos. Q_ASSERT (cursorRow == viewManager ()->textCursorRow ()); Q_ASSERT (cursorCol == viewManager ()->textCursorCol ()); } } e->accept (); } //--------------------------------------------------------------------- // protected void kpToolText::handleEnterKeyPress (QKeyEvent *e, const QList & /*textLines*/, int /*cursorRow*/, int /*cursorCol*/) { #if DEBUG_KP_TOOL_TEXT qCDebug(kpLogTools) << "\tenter pressed"; #endif // It's OK for to be empty. if (!d->enterCommand) addNewEnterCommand (&d->enterCommand); d->enterCommand->addEnter (); e->accept (); } //--------------------------------------------------------------------- // protected void kpToolText::handleTextTyped (QKeyEvent *e, const QList & /*textLines*/, int /*cursorRow*/, int /*cursorCol*/) { #if DEBUG_KP_TOOL_TEXT qCDebug(kpLogTools) << "\ttext=" << e->text(); #endif QString usableText; - for (int i = 0; i < (int) e->text ().length (); i++) + for (int i = 0; i < e->text ().length (); i++) { if (e->text ().at (i).isPrint ()) usableText += e->text ().at (i); } #if DEBUG_KP_TOOL_TEXT qCDebug(kpLogTools) << "\tusableText=" << usableText; #endif if (usableText.isEmpty ()) { // Don't end the current shape nor accept the event -- the event // wasn't for us. return; } // --- It's OK for to be empty. --- if (!d->insertCommand) addNewInsertCommand (&d->insertCommand); d->insertCommand->addText (usableText); e->accept (); } diff --git a/views/kpUnzoomedThumbnailView.cpp b/views/kpUnzoomedThumbnailView.cpp index 36fbb26b..d5e63603 100644 --- a/views/kpUnzoomedThumbnailView.cpp +++ b/views/kpUnzoomedThumbnailView.cpp @@ -1,217 +1,217 @@ /* Copyright (c) 2003-2007 Clarence Dang 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_UNZOOMED_THUMBNAIL_VIEW 0 #include "views/kpUnzoomedThumbnailView.h" #include "kpLogCategories.h" #include "document/kpDocument.h" #include "views/manager/kpViewManager.h" #include "kpViewScrollableContainer.h" #include #include //--------------------------------------------------------------------- struct kpUnzoomedThumbnailViewPrivate { }; kpUnzoomedThumbnailView::kpUnzoomedThumbnailView ( kpDocument *document, kpToolToolBar *toolToolBar, kpViewManager *viewManager, kpView *buddyView, kpViewScrollableContainer *scrollableContainer, QWidget *parent) : kpThumbnailView (document, toolToolBar, viewManager, buddyView, scrollableContainer, parent), d (new kpUnzoomedThumbnailViewPrivate ()) { if (buddyViewScrollableContainer ()) { connect (buddyViewScrollableContainer (), SIGNAL (contentsMoved()), this, SLOT (adjustToEnvironment())); } // Call to virtual function - this is why the class is sealed adjustToEnvironment (); } //--------------------------------------------------------------------- kpUnzoomedThumbnailView::~kpUnzoomedThumbnailView () { delete d; } //--------------------------------------------------------------------- // public virtual [base kpThumbnailView] QString kpUnzoomedThumbnailView::caption () const { return i18n ("Unzoomed Mode - Thumbnail"); } //--------------------------------------------------------------------- // public slot virtual [base kpView] void kpUnzoomedThumbnailView::adjustToEnvironment () { if (!buddyView () || !buddyViewScrollableContainer () || !document ()) return; const int scrollViewContentsX = buddyViewScrollableContainer()->horizontalScrollBar()->value(); const int scrollViewContentsY = buddyViewScrollableContainer ()->verticalScrollBar()->value(); #if DEBUG_KP_UNZOOMED_THUMBNAIL_VIEW qCDebug(kpLogViews) << "kpUnzoomedThumbnailView(" << name () << ")::adjustToEnvironment(" << scrollViewContentsX << "," << scrollViewContentsY << ") width=" << width () << " height=" << height () << endl; #endif #if 1 int x; if (document ()->width () > width ()) { - x = (int) buddyView ()->transformViewToDocX (scrollViewContentsX); + x = static_cast (buddyView ()->transformViewToDocX (scrollViewContentsX)); const int rightMostAllowedX = qMax (0, document ()->width () - width ()); #if DEBUG_KP_UNZOOMED_THUMBNAIL_VIEW qCDebug(kpLogViews) << "\tdocX=" << x << " docWidth=" << document ()->width () << " rightMostAllowedX=" << rightMostAllowedX << endl; #endif if (x > rightMostAllowedX) x = rightMostAllowedX; } // Thumbnail width <= doc width else { // Center X (rather than flush left to be consistent with // kpZoomedThumbnailView) x = -(width () - document ()->width ()) / 2; } int y; if (document ()->height () > height ()) { - y = (int) buddyView ()->transformViewToDocY (scrollViewContentsY); + y = static_cast (buddyView ()->transformViewToDocY (scrollViewContentsY)); const int bottomMostAllowedY = qMax (0, document ()->height () - height ()); #if DEBUG_KP_UNZOOMED_THUMBNAIL_VIEW qCDebug(kpLogViews) << "\tdocY=" << y << " docHeight=" << document ()->height () << " bottomMostAllowedY=" << bottomMostAllowedY << endl; #endif if (y > bottomMostAllowedY) y = bottomMostAllowedY; } // Thumbnail height <= doc height else { // Center Y (rather than flush top to be consistent with // kpZoomedThumbnailView) y = -(height () - document ()->height ()) / 2; } // Prefer to keep visible area centred in thumbnail instead of flushed left. // Gives more editing context to the left and top. // But feels awkward for left-to-right users. So disabled for now. // Not totally tested. #else if (!buddyViewScrollableContainer ()) return; QRect docRect = buddyView ()->transformViewToDoc ( QRect (buddyViewScrollableContainer ()->horizontalScrollBar()->value(), buddyViewScrollableContainer ()->verticalScrollBar()->value(), qMin (buddyView ()->width (), buddyViewScrollableContainer ()->viewport()->width ()), qMin (buddyView ()->height (), buddyViewScrollableContainer ()->viewport()->height ()))); x = docRect.x () - (width () - docRect.width ()) / 2; qCDebug(kpLogViews) << "\tnew suggest x=" << x; const int rightMostAllowedX = qMax (0, document ()->width () - width ()); if (x < 0) x = 0; if (x > rightMostAllowedX) x = rightMostAllowedX; y = docRect.y () - (height () - docRect.height ()) / 2; qCDebug(kpLogViews) << "\tnew suggest y=" << y; const int bottomMostAllowedY = qMax (0, document ()->height () - height ()); if (y < 0) y = 0; if (y > bottomMostAllowedY) y = bottomMostAllowedY; #endif if (viewManager ()) { viewManager ()->setFastUpdates (); viewManager ()->setQueueUpdates (); } { // OPT: scrollView impl would be much, much faster setOrigin (QPoint (-x, -y)); setMaskToCoverDocument (); // Above might be a NOP even if e.g. doc size changed so force // update if (viewManager ()) viewManager ()->updateView (this); } if (viewManager ()) { viewManager ()->restoreQueueUpdates (); viewManager ()->restoreFastUpdates (); } } diff --git a/views/kpView.cpp b/views/kpView.cpp index 454c620f..1c1af05f 100644 --- a/views/kpView.cpp +++ b/views/kpView.cpp @@ -1,672 +1,672 @@ /* Copyright (c) 2003-2007 Clarence Dang Copyright (c) 2005 Kazuki Ohta Copyright (c) 2010 Tasuku Suzuki 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_VIEW 0 #define DEBUG_KP_VIEW_RENDERER ((DEBUG_KP_VIEW && 1) || 0) #include "kpView.h" #include "kpViewPrivate.h" #include #include #include #include #include #include #include #include "kpLogCategories.h" #include "kpDefs.h" #include "document/kpDocument.h" #include "layers/selections/text/kpTextSelection.h" #include "tools/kpTool.h" #include "widgets/toolbars/kpToolToolBar.h" #include "views/manager/kpViewManager.h" #include "kpViewScrollableContainer.h" //--------------------------------------------------------------------- // public static const int kpView::MinZoomLevel = 1; const int kpView::MaxZoomLevel = 3200; //--------------------------------------------------------------------- kpView::kpView (kpDocument *document, kpToolToolBar *toolToolBar, kpViewManager *viewManager, kpView *buddyView, kpViewScrollableContainer *scrollableContainer, QWidget *parent) : QWidget (parent), d (new kpViewPrivate ()) { d->document = document; d->toolToolBar = toolToolBar; d->viewManager = viewManager; d->buddyView = buddyView; d->scrollableContainer = scrollableContainer; d->hzoom = 100; d->vzoom = 100; d->origin = QPoint (0, 0); d->showGrid = false; d->isBuddyViewScrollableContainerRectangleShown = false; // Don't waste CPU drawing default background since its overridden by // our fully opaque drawing. In reality, this seems to make no // difference in performance. setAttribute(Qt::WA_OpaquePaintEvent, true); setFocusPolicy (Qt::WheelFocus); setMouseTracking (true); // mouseMoveEvent's even when no mousebtn down setAttribute (Qt::WA_KeyCompression, true); } //--------------------------------------------------------------------- kpView::~kpView () { setHasMouse (false); delete d; } //--------------------------------------------------------------------- // public kpDocument *kpView::document () const { return d->document; } //--------------------------------------------------------------------- // protected kpAbstractSelection *kpView::selection () const { return document () ? document ()->selection () : nullptr; } //--------------------------------------------------------------------- // protected kpTextSelection *kpView::textSelection () const { return document () ? document ()->textSelection () : nullptr; } //--------------------------------------------------------------------- // public kpToolToolBar *kpView::toolToolBar () const { return d->toolToolBar; } // protected kpTool *kpView::tool () const { return toolToolBar () ? toolToolBar ()->tool () : nullptr; } // public kpViewManager *kpView::viewManager () const { return d->viewManager; } // public kpView *kpView::buddyView () const { return d->buddyView; } // public kpViewScrollableContainer *kpView::buddyViewScrollableContainer () const { return (buddyView () ? buddyView ()->scrollableContainer () : nullptr); } // public kpViewScrollableContainer *kpView::scrollableContainer () const { return d->scrollableContainer; } // public int kpView::zoomLevelX (void) const { return d->hzoom; } // public int kpView::zoomLevelY (void) const { return d->vzoom; } // public virtual void kpView::setZoomLevel (int hzoom, int vzoom) { hzoom = qBound (MinZoomLevel, hzoom, MaxZoomLevel); vzoom = qBound (MinZoomLevel, vzoom, MaxZoomLevel); if (hzoom == d->hzoom && vzoom == d->vzoom) return; d->hzoom = hzoom; d->vzoom = vzoom; if (viewManager ()) viewManager ()->updateView (this); emit zoomLevelChanged (hzoom, vzoom); } // public QPoint kpView::origin () const { return d->origin; } // public virtual void kpView::setOrigin (const QPoint &origin) { #if DEBUG_KP_VIEW qCDebug(kpLogViews) << "kpView(" << objectName () << ")::setOrigin" << origin; #endif if (origin == d->origin) { #if DEBUG_KP_VIEW qCDebug(kpLogViews) << "\tNOP"; #endif return; } d->origin = origin; if (viewManager ()) viewManager ()->updateView (this); emit originChanged (origin); } // public bool kpView::canShowGrid () const { // (minimum zoom level < 400% would probably be reported as a bug by // users who thought that the grid was a part of the image!) return ((zoomLevelX () >= 400 && zoomLevelX () % 100 == 0) && (zoomLevelY () >= 400 && zoomLevelY () % 100 == 0)); } // public bool kpView::isGridShown () const { return d->showGrid; } // public void kpView::showGrid (bool yes) { if (d->showGrid == yes) return; if (yes && !canShowGrid ()) return; d->showGrid = yes; if (viewManager ()) viewManager ()->updateView (this); } // public bool kpView::isBuddyViewScrollableContainerRectangleShown () const { return d->isBuddyViewScrollableContainerRectangleShown; } // public void kpView::showBuddyViewScrollableContainerRectangle (bool yes) { if (yes == d->isBuddyViewScrollableContainerRectangleShown) return; d->isBuddyViewScrollableContainerRectangleShown = yes; if (d->isBuddyViewScrollableContainerRectangleShown) { // Got these connect statements by analysing deps of // updateBuddyViewScrollableContainerRectangle() rect update code. connect (this, SIGNAL (zoomLevelChanged(int,int)), this, SLOT (updateBuddyViewScrollableContainerRectangle())); connect (this, SIGNAL (originChanged(QPoint)), this, SLOT (updateBuddyViewScrollableContainerRectangle())); if (buddyViewScrollableContainer ()) { connect (buddyViewScrollableContainer (), SIGNAL (contentsMoved()), this, SLOT (updateBuddyViewScrollableContainerRectangle())); connect (buddyViewScrollableContainer (), SIGNAL (resized()), this, SLOT (updateBuddyViewScrollableContainerRectangle())); } if (buddyView ()) { connect (buddyView (), SIGNAL (zoomLevelChanged(int,int)), this, SLOT (updateBuddyViewScrollableContainerRectangle())); connect (buddyView (), SIGNAL (originChanged(QPoint)), this, SLOT (updateBuddyViewScrollableContainerRectangle())); connect (buddyView (), SIGNAL (sizeChanged(int,int)), this, SLOT (updateBuddyViewScrollableContainerRectangle())); } } else { disconnect (this, SIGNAL (zoomLevelChanged(int,int)), this, SLOT (updateBuddyViewScrollableContainerRectangle())); disconnect (this, SIGNAL (originChanged(QPoint)), this, SLOT (updateBuddyViewScrollableContainerRectangle())); if (buddyViewScrollableContainer ()) { disconnect (buddyViewScrollableContainer (), SIGNAL (contentsMoved()), this, SLOT (updateBuddyViewScrollableContainerRectangle())); disconnect (buddyViewScrollableContainer (), SIGNAL (resized()), this, SLOT (updateBuddyViewScrollableContainerRectangle())); } if (buddyView ()) { disconnect (buddyView (), SIGNAL (zoomLevelChanged(int,int)), this, SLOT (updateBuddyViewScrollableContainerRectangle())); disconnect (buddyView (), SIGNAL (originChanged(QPoint)), this, SLOT (updateBuddyViewScrollableContainerRectangle())); disconnect (buddyView (), SIGNAL (sizeChanged(int,int)), this, SLOT (updateBuddyViewScrollableContainerRectangle())); } } updateBuddyViewScrollableContainerRectangle (); } // protected QRect kpView::buddyViewScrollableContainerRectangle () const { return d->buddyViewScrollableContainerRectangle; } // protected slot void kpView::updateBuddyViewScrollableContainerRectangle () { if (viewManager ()) viewManager ()->setQueueUpdates (); { if (d->buddyViewScrollableContainerRectangle.isValid ()) { if (viewManager ()) { // Erase last viewManager ()->updateViewRectangleEdges (this, d->buddyViewScrollableContainerRectangle); } } QRect newRect; if (isBuddyViewScrollableContainerRectangleShown () && buddyViewScrollableContainer () && buddyView ()) { QRect docRect = buddyView ()->transformViewToDoc ( QRect (buddyViewScrollableContainer ()->horizontalScrollBar()->value(), buddyViewScrollableContainer ()->verticalScrollBar()->value(), qMin (buddyView ()->width (), buddyViewScrollableContainer ()->viewport()->width ()), qMin (buddyView ()->height (), buddyViewScrollableContainer ()->viewport()->height ()))); QRect viewRect = this->transformDocToView (docRect); // (Surround the area of interest by moving outwards by 1 pixel in each // direction - don't overlap area) newRect = QRect (viewRect.x () - 1, viewRect.y () - 1, viewRect.width () + 2, viewRect.height () + 2); } else { newRect = QRect (); } if (newRect != d->buddyViewScrollableContainerRectangle) { // (must set before updateView() for paintEvent() to see new // rect) d->buddyViewScrollableContainerRectangle = newRect; if (newRect.isValid ()) { if (viewManager ()) { viewManager ()->updateViewRectangleEdges (this, d->buddyViewScrollableContainerRectangle); } } } } if (viewManager ()) viewManager ()->restoreQueueUpdates (); } //--------------------------------------------------------------------- // public double kpView::transformViewToDocX (double viewX) const { return (viewX - origin ().x ()) * 100.0 / zoomLevelX (); } //--------------------------------------------------------------------- // public double kpView::transformViewToDocY (double viewY) const { return (viewY - origin ().y ()) * 100.0 / zoomLevelY (); } //--------------------------------------------------------------------- // public QPoint kpView::transformViewToDoc (const QPoint &viewPoint) const { - return QPoint ((int) transformViewToDocX (viewPoint.x ()), - (int) transformViewToDocY (viewPoint.y ())); + return QPoint (static_cast (transformViewToDocX (viewPoint.x ())), + static_cast (transformViewToDocY (viewPoint.y ()))); } //--------------------------------------------------------------------- // public QRect kpView::transformViewToDoc (const QRect &viewRect) const { if (zoomLevelX () == 100 && zoomLevelY () == 100) { return QRect (viewRect.x () - origin ().x (), viewRect.y () - origin ().y (), viewRect.width (), viewRect.height ()); } else { const QPoint docTopLeft = transformViewToDoc (viewRect.topLeft ()); // (don't call transformViewToDoc[XY]() - need to round up dimensions) const int docWidth = qRound (double (viewRect.width ()) * 100.0 / double (zoomLevelX ())); const int docHeight = qRound (double (viewRect.height ()) * 100.0 / double (zoomLevelY ())); // (like QWMatrix::Areas) return QRect (docTopLeft.x (), docTopLeft.y (), docWidth, docHeight); } } //--------------------------------------------------------------------- // public double kpView::transformDocToViewX (double docX) const { return (docX * zoomLevelX () / 100.0) + origin ().x (); } // public double kpView::transformDocToViewY (double docY) const { return (docY * zoomLevelY () / 100.0) + origin ().y (); } // public QPoint kpView::transformDocToView (const QPoint &docPoint) const { - return QPoint ((int) transformDocToViewX (docPoint.x ()), - (int) transformDocToViewY (docPoint.y ())); + return QPoint (static_cast (transformDocToViewX (docPoint.x ())), + static_cast (transformDocToViewY (docPoint.y ()))); } // public QRect kpView::transformDocToView (const QRect &docRect) const { if (zoomLevelX () == 100 && zoomLevelY () == 100) { return QRect (docRect.x () + origin ().x (), docRect.y () + origin ().y (), docRect.width (), docRect.height ()); } else { const QPoint viewTopLeft = transformDocToView (docRect.topLeft ()); // (don't call transformDocToView[XY]() - need to round up dimensions) const int viewWidth = qRound (double (docRect.width ()) * double (zoomLevelX ()) / 100.0); const int viewHeight = qRound (double (docRect.height ()) * double (zoomLevelY ()) / 100.0); // (like QWMatrix::Areas) return QRect (viewTopLeft.x (), viewTopLeft.y (), viewWidth, viewHeight); } } // public QPoint kpView::transformViewToOtherView (const QPoint &viewPoint, const kpView *otherView) { if (this == otherView) return viewPoint; const double docX = transformViewToDocX (viewPoint.x ()); const double docY = transformViewToDocY (viewPoint.y ()); const double otherViewX = otherView->transformDocToViewX (docX); const double otherViewY = otherView->transformDocToViewY (docY); - return QPoint ((int) otherViewX, (int) otherViewY); + return QPoint (static_cast (otherViewX), static_cast (otherViewY)); } // public int kpView::zoomedDocWidth () const { return document () ? document ()->width () * zoomLevelX () / 100 : 0; } // public int kpView::zoomedDocHeight () const { return document () ? document ()->height () * zoomLevelY () / 100 : 0; } // public void kpView::setHasMouse (bool yes) { kpViewManager *vm = viewManager (); if (!vm) return; #if DEBUG_KP_VIEW && 0 qCDebug(kpLogViews) << "kpView(" << objectName () << ")::setHasMouse(" << yes << ") existing viewUnderCursor=" << (vm->viewUnderCursor () ? vm->viewUnderCursor ()->objectName () : "(none)") << endl; #endif if (yes && vm->viewUnderCursor () != this) vm->setViewUnderCursor (this); else if (!yes && vm->viewUnderCursor () == this) vm->setViewUnderCursor (nullptr); } //--------------------------------------------------------------------- // public void kpView::addToQueuedArea (const QRegion ®ion) { #if DEBUG_KP_VIEW && 0 qCDebug(kpLogViews) << "kpView(" << objectName () << ")::addToQueuedArea() already=" << d->queuedUpdateArea << " - plus - " << region << endl; #endif d->queuedUpdateArea += region; } //--------------------------------------------------------------------- // public void kpView::addToQueuedArea (const QRect &rect) { #if DEBUG_KP_VIEW && 0 qCDebug(kpLogViews) << "kpView(" << objectName () << ")::addToQueuedArea() already=" << d->queuedUpdateArea << " - plus - " << rect << endl; #endif d->queuedUpdateArea += rect; } //--------------------------------------------------------------------- // public void kpView::invalidateQueuedArea () { #if DEBUG_KP_VIEW && 0 qCDebug(kpLogViews) << "kpView::invalidateQueuedArea()"; #endif d->queuedUpdateArea = QRegion (); } //--------------------------------------------------------------------- // public void kpView::updateQueuedArea () { kpViewManager *vm = viewManager (); #if DEBUG_KP_VIEW && 0 qCDebug(kpLogViews) << "kpView(" << objectName () << ")::updateQueuedArea() vm=" << (bool) vm << " queueUpdates=" << (vm && vm->queueUpdates ()) << " fastUpdates=" << (vm && vm->fastUpdates ()) << " area=" << d->queuedUpdateArea << endl; #endif if (!vm) return; if (vm->queueUpdates ()) return; if (!d->queuedUpdateArea.isEmpty ()) vm->updateView (this, d->queuedUpdateArea); invalidateQueuedArea (); } //--------------------------------------------------------------------- // public QPoint kpView::mouseViewPoint (const QPoint &returnViewPoint) const { if (returnViewPoint != KP_INVALID_POINT) return returnViewPoint; else { // TODO: I don't think this is right for the main view since that's // inside the scrollview (which can scroll). return mapFromGlobal (QCursor::pos ()); } } //--------------------------------------------------------------------- // public virtual QVariant kpView::inputMethodQuery (Qt::InputMethodQuery query) const { #if DEBUG_KP_VIEW && 1 qCDebug(kpLogViews) << "kpView(" << objectName () << ")::inputMethodQuery()"; #endif QVariant ret; switch (query) { case Qt::ImMicroFocus: { QRect r = d->viewManager->textCursorRect (); r.setTopLeft (r.topLeft () + origin ()); r.setHeight (r.height() + 2); r = transformDocToView (r); ret = r; break; } case Qt::ImFont: { if (textSelection ()) { ret = textSelection ()->textStyle ().font (); } break; } default: break; } return ret; } //--------------------------------------------------------------------- diff --git a/views/kpZoomedView.cpp b/views/kpZoomedView.cpp index c41422c4..1227095d 100644 --- a/views/kpZoomedView.cpp +++ b/views/kpZoomedView.cpp @@ -1,102 +1,102 @@ /* Copyright (c) 2003-2007 Clarence Dang 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_ZOOMED_VIEW 0 #include "views/kpZoomedView.h" #include "kpLogCategories.h" #include "document/kpDocument.h" #include "views/kpView.h" #include "views/manager/kpViewManager.h" kpZoomedView::kpZoomedView (kpDocument *document, kpToolToolBar *toolToolBar, kpViewManager *viewManager, kpView *buddyView, kpViewScrollableContainer *scrollableContainer, QWidget *parent) : kpView (document, toolToolBar, viewManager, buddyView, scrollableContainer, parent) { // Call to virtual function - this is why the class is sealed adjustToEnvironment (); } kpZoomedView::~kpZoomedView () { } // public virtual [base kpView] void kpZoomedView::setZoomLevel (int hzoom, int vzoom) { #if DEBUG_KP_ZOOMED_VIEW qCDebug(kpLogViews) << "kpZoomedView(" << name () << ")::setZoomLevel(" << hzoom << "," << vzoom << ")" << endl; #endif if (viewManager ()) viewManager ()->setQueueUpdates (); { kpView::setZoomLevel (hzoom, vzoom); adjustToEnvironment (); } if (viewManager ()) viewManager ()->restoreQueueUpdates (); } // public slot virtual [base kpView] void kpZoomedView::adjustToEnvironment () { #if DEBUG_KP_ZOOMED_VIEW qCDebug(kpLogViews) << "kpZoomedView(" << name () << ")::adjustToEnvironment()" << " doc: width=" << document ()->width () << " height=" << document ()->height () << endl; #endif if (document ()) { // TODO: use zoomedDocWidth() & zoomedDocHeight()? - resize ((int) transformDocToViewX (document ()->width ()), - (int) transformDocToViewY (document ()->height ())); + resize (static_cast (transformDocToViewX (document ()->width ())), + static_cast (transformDocToViewY (document ()->height ()))); } } diff --git a/views/manager/kpViewManager_TextCursor.cpp b/views/manager/kpViewManager_TextCursor.cpp index c7eea0ea..99d5e661 100644 --- a/views/manager/kpViewManager_TextCursor.cpp +++ b/views/manager/kpViewManager_TextCursor.cpp @@ -1,240 +1,240 @@ // TODO: This is bad design as it's easy to get out of sync with the selection. // e.g. You could have textCursorEnabled() but no text selection or // vice versa. And the cursor could be outside of the selection. // // In fact, our text commands momentarily violate these "invariants": // // 1. A text box with content must have the cursor somewhere on an // existing text line, possibly 1 position after the last character // on a line. // // 2. Special case: A content-less text box (i.e. no text lines) must // have the cursor at (0,0). // // We don't assert-check them at the moment. We should when we fix // the design so that the invariants are always maintained. /* Copyright (c) 2003-2007 Clarence Dang Copyright (c) 2005 Kazuki Ohta Copyright (c) 2010 Tasuku Suzuki 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_VIEW_MANAGER 0 #include "kpViewManager.h" #include "kpViewManagerPrivate.h" #include #include #include //#include #include "kpLogCategories.h" #include "kpDefs.h" #include "document/kpDocument.h" #include "mainWindow/kpMainWindow.h" #include "layers/tempImage/kpTempImage.h" #include "layers/selections/text/kpTextSelection.h" #include "tools/kpTool.h" #include "views/kpView.h" // public bool kpViewManager::textCursorEnabled () const { - return (bool) d->textCursorBlinkTimer; + return static_cast (d->textCursorBlinkTimer); } // public void kpViewManager::setTextCursorEnabled (bool yes) { #if DEBUG_KP_VIEW_MANAGER && 1 qCDebug(kpLogViews) << "kpViewManager::setTextCursorEnabled(" << yes << ")"; #endif if (yes == textCursorEnabled ()) return; delete d->textCursorBlinkTimer; d->textCursorBlinkTimer = nullptr; setFastUpdates (); setQueueUpdates (); { if (yes) { d->textCursorBlinkTimer = new QTimer (this); d->textCursorBlinkTimer->setSingleShot (true); connect (d->textCursorBlinkTimer, SIGNAL (timeout()), this, SLOT (slotTextCursorBlink())); d->textCursorBlinkState = true; slotTextCursorBlink (); } else { d->textCursorBlinkState = false; updateTextCursor (); } } restoreQueueUpdates (); restoreFastUpdates (); } // public bool kpViewManager::textCursorBlinkState () const { return d->textCursorBlinkState; } // public void kpViewManager::setTextCursorBlinkState (bool on) { if (on == d->textCursorBlinkState) return; d->textCursorBlinkState = on; updateTextCursor (); } // public int kpViewManager::textCursorRow () const { return d->textCursorRow; } // public int kpViewManager::textCursorCol () const { return d->textCursorCol; } // public void kpViewManager::setTextCursorPosition (int row, int col) { if (row == d->textCursorRow && col == d->textCursorCol) return; setFastUpdates (); setQueueUpdates (); { // Clear the old cursor. d->textCursorBlinkState = false; updateTextCursor (); d->textCursorRow = row; d->textCursorCol = col; // Render the new cursor. d->textCursorBlinkState = true; updateTextCursor (); } restoreQueueUpdates (); restoreFastUpdates (); #if 0 // TODO port to Qt5? if (d->viewUnderCursor) { QInputContext *inputContext = d->viewUnderCursor->inputContext (); if (inputContext) { inputContext->update (); } } #endif } // public QRect kpViewManager::textCursorRect () const { kpTextSelection *textSel = document ()->textSelection (); if (!textSel) return QRect (); QPoint topLeft = textSel->pointForTextRowCol (d->textCursorRow, d->textCursorCol); if (topLeft == KP_INVALID_POINT) { // Text cursor row/col hasn't been specified yet? if (textSel->hasContent ()) return QRect (); // Empty text box should still display a cursor so that the user // knows where typed text will go. topLeft = textSel->textAreaRect ().topLeft (); } Q_ASSERT (topLeft != KP_INVALID_POINT); return QRect (topLeft.x (), topLeft.y (), 1, textSel->textStyle ().fontMetrics ().height ()); } // protected void kpViewManager::updateTextCursor () { #if DEBUG_KP_VIEW_MANAGER && 0 qCDebug(kpLogViews) << "kpViewManager::updateTextCursor()"; #endif const QRect r = textCursorRect (); if (!r.isValid ()) return; setFastUpdates (); { // If !textCursorEnabled(), this will clear. updateViews (r); } restoreFastUpdates (); } // protected slot void kpViewManager::slotTextCursorBlink () { #if DEBUG_KP_VIEW_MANAGER && 0 qCDebug(kpLogViews) << "kpViewManager::slotTextCursorBlink() cursorBlinkState=" << d->textCursorBlinkState << endl; #endif if (d->textCursorBlinkTimer) { // (single shot) d->textCursorBlinkTimer->start (QApplication::cursorFlashTime () / 2); } updateTextCursor (); // TODO: Shouldn't this be done _before_ updating the text cursor // because textCursorBlinkState() is supposed to reflect what // updateTextCursor() just rendered, until the next timer tick? d->textCursorBlinkState = !d->textCursorBlinkState; } diff --git a/widgets/colorSimilarity/kpColorSimilarityHolder.cpp b/widgets/colorSimilarity/kpColorSimilarityHolder.cpp index 02def57c..d02e5474 100644 --- a/widgets/colorSimilarity/kpColorSimilarityHolder.cpp +++ b/widgets/colorSimilarity/kpColorSimilarityHolder.cpp @@ -1,189 +1,189 @@ /* Copyright (c) 2003-2007 Clarence Dang 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_COLOR_SIMILARITY_CUBE 0 #include "kpColorSimilarityHolder.h" #include "kpColorSimilarityCubeRenderer.h" #include "imagelib/kpColor.h" #include "kpDefs.h" #include #include #include #include #include "kpLogCategories.h" #include // public static const double kpColorSimilarityHolder::ColorCubeDiagonalDistance = - sqrt ((double)255 * 255 * 3); + sqrt (255.0 * 255 * 3); // public static const double kpColorSimilarityHolder::MaxColorSimilarity = .30; kpColorSimilarityHolder::kpColorSimilarityHolder () : m_colorSimilarity (0) { } kpColorSimilarityHolder::~kpColorSimilarityHolder () { } // Don't cause the translators grief by appending strings etc. // - duplicate text with 2 cases // public static QString kpColorSimilarityHolder::WhatsThisWithClickInstructions () { return i18n ("" "

Color Similarity is how similar the colors of different pixels" " must be, for operations to consider them to be the same.

" "

If you set it to something other than Exact Match," " you can work more effectively with dithered" " images and photos, in a comparable manner to the \"Magic Wand\"" " feature of other paint programs.

" "

This feature applies to:

" "
    " "
  • Selections: In Transparent mode, any color in the" " selection that is similar to the background color will" " be made transparent.
  • " "
  • Flood Fill: For regions with similar - but not" " identical - colored pixels, a higher setting is likely to" " fill more pixels.
  • " "
  • Color Eraser: Any pixel whose color is similar" " to the foreground color will be replaced with the background" " color.
  • " "
  • Autocrop and Remove Internal Border: For" " borders with similar - but not identical - colored pixels," " a higher setting is more likely to crop the whole border.
  • " "
" "

Higher settings mean that operations consider an increased range" " of colors to be sufficiently similar so as to be the same. Therefore," " you should increase the setting if the above operations are not" " affecting pixels whose colors you consider to be similar enough.

" "

However, if they are having too much of an effect and are changing" " pixels whose colors you do not consider to be similar" " (e.g. if Flood Fill is changing too many pixels), you" " should decrease this setting.

" // sync: Compared to the other string below, we've added this line. "

To configure it, click on the cube.

" "
"); } // public static QString kpColorSimilarityHolder::WhatsThis () { return i18n ("" "

Color Similarity is how similar the colors of different pixels" " must be, for operations to consider them to be the same.

" "

If you set it to something other than Exact Match," " you can work more effectively with dithered" " images and photos, in a comparable manner to the \"Magic Wand\"" " feature of other paint programs.

" "

This feature applies to:

" "
    " "
  • Selections: In Transparent mode, any color in the" " selection that is similar to the background color will" " be made transparent.
  • " "
  • Flood Fill: For regions with similar - but not" " identical - colored pixels, a higher setting is likely to" " fill more pixels.
  • " "
  • Color Eraser: Any pixel whose color is similar" " to the foreground color will be replaced with the background" " color.
  • " "
  • Autocrop and Remove Internal Border: For" " borders with similar - but not identical - colored pixels," " a higher setting is more likely to crop the whole border.
  • " "
" "

Higher settings mean that operations consider an increased range" " of colors to be sufficiently similar so as to be the same. Therefore," " you should increase the setting if the above operations are not" " affecting pixels whose colors you consider to be similar enough.

" "

However, if they are having too much of an effect and are changing" " pixels whose colors you do not consider to be similar" " (e.g. if Flood Fill is changing too many pixels), you" " should decrease this setting.

" "
"); } // public double kpColorSimilarityHolder::colorSimilarity () const { return m_colorSimilarity; } // public virtual void kpColorSimilarityHolder::setColorSimilarity (double similarity) { #if DEBUG_KP_COLOR_SIMILARITY_CUBE qCDebug(kpLogWidgets) << "kpColorSimilarityHolder::setColorSimilarity(" << similarity << ")"; #endif if (m_colorSimilarity == similarity) return; if (similarity < 0) similarity = 0; else if (similarity > MaxColorSimilarity) similarity = MaxColorSimilarity; m_colorSimilarity = similarity; } diff --git a/widgets/kpDefaultColorCollection.cpp b/widgets/kpDefaultColorCollection.cpp index 66612e13..6eed4b61 100644 --- a/widgets/kpDefaultColorCollection.cpp +++ b/widgets/kpDefaultColorCollection.cpp @@ -1,71 +1,71 @@ /* Copyright (c) 2003-2007 Clarence Dang All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include "kpDefaultColorCollection.h" #include "imagelib/kpColor.h" kpDefaultColorCollection::kpDefaultColorCollection () { kpColor colors [] = { kpColor::Black, kpColor::Gray, kpColor::Red, kpColor::Orange, kpColor::Yellow, kpColor::Green, kpColor::Aqua, kpColor::Blue, kpColor::Purple, kpColor::Pink, kpColor::LightGreen, kpColor::White, kpColor::LightGray, kpColor::DarkRed, kpColor::DarkOrange, kpColor::DarkYellow, kpColor::DarkGreen, kpColor::DarkAqua, kpColor::DarkBlue, kpColor::DarkPurple, kpColor::LightBlue, kpColor::Tan }; - for (int i = 0; i < (int) (sizeof (colors) / sizeof (colors [0])); i++) + for (int i = 0; i < static_cast (sizeof (colors) / sizeof (colors [0])); i++) { addColor (colors [i].toQColor ()); } } kpDefaultColorCollection::~kpDefaultColorCollection () { } diff --git a/widgets/toolbars/options/kpToolWidgetBase.cpp b/widgets/toolbars/options/kpToolWidgetBase.cpp index d1ba0c86..5d61f76b 100644 --- a/widgets/toolbars/options/kpToolWidgetBase.cpp +++ b/widgets/toolbars/options/kpToolWidgetBase.cpp @@ -1,722 +1,722 @@ /* Copyright (c) 2003-2007 Clarence Dang 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_WIDGET_BASE 0 #include "kpToolWidgetBase.h" #include "kpDefs.h" #include #include #include #include "kpLogCategories.h" #include #include #include #include #include #include #include #include //--------------------------------------------------------------------- kpToolWidgetBase::kpToolWidgetBase (QWidget *parent, const QString &name) : QFrame(parent), m_baseWidget(nullptr), m_selectedRow(-1), m_selectedCol(-1) { setObjectName (name); setFrameStyle (QFrame::Panel | QFrame::Sunken); setFixedSize (44, 66); setSizePolicy (QSizePolicy::Minimum, QSizePolicy::Minimum); } //--------------------------------------------------------------------- kpToolWidgetBase::~kpToolWidgetBase () { } //--------------------------------------------------------------------- // public void kpToolWidgetBase::addOption (const QPixmap &pixmap, const QString &toolTip) { if (m_pixmaps.isEmpty ()) startNewOptionRow (); m_pixmaps.last ().append (pixmap); m_pixmapRects.last ().append (QRect ()); m_toolTips.last ().append (toolTip); } //--------------------------------------------------------------------- // public void kpToolWidgetBase::startNewOptionRow () { m_pixmaps.append (QList ()); m_pixmapRects.append (QList ()); m_toolTips.append (QList ()); } //--------------------------------------------------------------------- // public void kpToolWidgetBase::finishConstruction (int fallBackRow, int fallBackCol) { #if DEBUG_KP_TOOL_WIDGET_BASE qCDebug(kpLogWidgets) << "kpToolWidgetBase(" << objectName () << ")::kpToolWidgetBase(fallBack:row=" << fallBackRow << ",col=" << fallBackCol << ")" << endl; #endif relayoutOptions (); // HACK: Undo the maximum half of setFixedSize() in the ctor to avoid // bizarre redraw errors when tool widgets are hidden and others // are shown. // // The reason why we didn't just use setMinimumSize() in the ctor is // because all tool widgets construct pixmaps whose sizes are dependent // on the size() in the ctor, so we needed to get the correct size // in there. This is bad design because it means that tool widgets // can't really be resized. setMaximumSize (QWIDGETSIZE_MAX, QWIDGETSIZE_MAX); const QPair rowColPair = defaultSelectedRowAndCol (); if (!setSelected (rowColPair.first, rowColPair.second, false/*don't save*/)) { if (!setSelected (fallBackRow, fallBackCol)) { if (!setSelected (0, 0)) { qCCritical(kpLogWidgets) << "kpToolWidgetBase::finishConstruction() " "can't even fall back to setSelected(row=0,col=0)" << endl; } } } } //--------------------------------------------------------------------- // private QList kpToolWidgetBase::spreadOutElements (const QList &sizes, int max) { if (sizes.count () == 0) return QList (); else if (sizes.count () == 1) { QList ret; ret.append (sizes.first () > max ? 0 : 1/*margin*/); return ret; } QList retOffsets; for (int i = 0; i < sizes.count (); i++) retOffsets.append (0); int totalSize = 0; - for (int i = 0; i < (int) sizes.count (); i++) + for (int i = 0; i < sizes.count (); i++) totalSize += sizes [i]; int margin = 1; // if don't fit with margin, then just return elements // packed right next to each other if (totalSize + margin * 2 > max) { retOffsets [0] = 0; - for (int i = 1; i < (int) sizes.count (); i++) + for (int i = 1; i < sizes.count (); i++) retOffsets [i] = retOffsets [i - 1] + sizes [i - 1]; return retOffsets; } int maxLeftOver = max - (totalSize + margin * 2 * sizes.count()); int startCompensating = -1; int numCompensate = 0; int spacing = 0; spacing = maxLeftOver / (sizes.count () - 1); if (spacing * int (sizes.count () - 1) < maxLeftOver) { numCompensate = maxLeftOver - spacing * (sizes.count () - 1); startCompensating = ((sizes.count () - 1) - numCompensate) / 2; } retOffsets [0] = margin; - for (int i = 1; i < (int) sizes.count (); i++) + for (int i = 1; i < sizes.count (); i++) { retOffsets [i] += retOffsets [i - 1] + sizes [i - 1] + spacing + ((numCompensate && i >= startCompensating && i < startCompensating + numCompensate) ? 1 : 0); } return retOffsets; } //--------------------------------------------------------------------- // public QPair kpToolWidgetBase::defaultSelectedRowAndCol () const { int row = -1, col = -1; if (!objectName ().isEmpty ()) { KConfigGroup cfg (KSharedConfig::openConfig (), kpSettingsGroupTools); row = cfg.readEntry (objectName () + QLatin1String (" Row"), -1); col = cfg.readEntry (objectName () + QLatin1String (" Col"), -1); } #if DEBUG_KP_TOOL_WIDGET_BASE qCDebug(kpLogWidgets) << "kpToolWidgetBase(" << objectName () << ")::defaultSelectedRowAndCol() returning row=" << row << " col=" << col << endl; #endif return qMakePair (row, col); } //--------------------------------------------------------------------- // public int kpToolWidgetBase::defaultSelectedRow () const { return defaultSelectedRowAndCol ().first; } //--------------------------------------------------------------------- // public int kpToolWidgetBase::defaultSelectedCol () const { return defaultSelectedRowAndCol ().second; } //--------------------------------------------------------------------- // public void kpToolWidgetBase::saveSelectedAsDefault () const { #if DEBUG_KP_TOOL_WIDGET_BASE qCDebug(kpLogWidgets) << "kpToolWidgetBase(" << objectName () << ")::saveSelectedAsDefault() row=" << m_selectedRow << " col=" << m_selectedCol << endl; #endif if (objectName ().isEmpty ()) return; KConfigGroup cfg (KSharedConfig::openConfig (), kpSettingsGroupTools); cfg.writeEntry (objectName () + QLatin1String (" Row"), m_selectedRow); cfg.writeEntry (objectName () + QLatin1String (" Col"), m_selectedCol); cfg.sync (); } //--------------------------------------------------------------------- // public void kpToolWidgetBase::relayoutOptions () { #if DEBUG_KP_TOOL_WIDGET_BASE qCDebug(kpLogWidgets) << "kpToolWidgetBase::relayoutOptions() size=" << size (); #endif while (!m_pixmaps.isEmpty () && m_pixmaps.last ().count () == 0) { #if DEBUG_KP_TOOL_WIDGET_BASE qCDebug(kpLogWidgets) << "\tkilling #" << m_pixmaps.count () - 1; #endif m_pixmaps.removeLast (); m_pixmapRects.removeLast (); m_toolTips.removeLast (); } if (m_pixmaps.isEmpty ()) return; #if DEBUG_KP_TOOL_WIDGET_BASE qCDebug(kpLogWidgets) << "\tsurvived killing of empty rows"; qCDebug(kpLogWidgets) << "\tfinding heights of rows:"; #endif QList maxHeightOfRow; for (int r = 0; r < m_pixmaps.count (); r++) maxHeightOfRow.append (0); - for (int r = 0; r < (int) m_pixmaps.count (); r++) + for (int r = 0; r < m_pixmaps.count (); r++) { - for (int c = 0; c < (int) m_pixmaps [r].count (); c++) + for (int c = 0; c < m_pixmaps [r].count (); c++) { if (c == 0 || m_pixmaps [r][c].height () > maxHeightOfRow [r]) maxHeightOfRow [r] = m_pixmaps [r][c].height (); } #if DEBUG_KP_TOOL_WIDGET_BASE qCDebug(kpLogWidgets) << "\t\t" << r << ": " << maxHeightOfRow [r]; #endif } QList rowYOffset = spreadOutElements (maxHeightOfRow, height ()); #if DEBUG_KP_TOOL_WIDGET_BASE qCDebug(kpLogWidgets) << "\tspread out offsets of rows:"; for (int r = 0; r < (int) rowYOffset.count (); r++) qCDebug(kpLogWidgets) << "\t\t" << r << ": " << rowYOffset [r]; #endif - for (int r = 0; r < (int) m_pixmaps.count (); r++) + for (int r = 0; r < m_pixmaps.count (); r++) { #if DEBUG_KP_TOOL_WIDGET_BASE qCDebug(kpLogWidgets) << "\tlaying out row " << r << ":"; #endif QList widths; - for (int c = 0; c < (int) m_pixmaps [r].count (); c++) + for (int c = 0; c < m_pixmaps [r].count (); c++) widths.append (m_pixmaps [r][c].width ()); #if DEBUG_KP_TOOL_WIDGET_BASE qCDebug(kpLogWidgets) << "\t\twidths of cols:"; - for (int c = 0; c < (int) m_pixmaps [r].count (); c++) + for (int c = 0; c < m_pixmaps [r].count (); c++) qCDebug(kpLogWidgets) << "\t\t\t" << c << ": " << widths [c]; #endif QList colXOffset = spreadOutElements (widths, width ()); #if DEBUG_KP_TOOL_WIDGET_BASE qCDebug(kpLogWidgets) << "\t\tspread out offsets of cols:"; - for (int c = 0; c < (int) colXOffset.count (); c++) + for (int c = 0; c < colXOffset.count (); c++) qCDebug(kpLogWidgets) << "\t\t\t" << c << ": " << colXOffset [c]; #endif - for (int c = 0; c < (int) colXOffset.count (); c++) + for (int c = 0; c < colXOffset.count (); c++) { int x = colXOffset [c]; int y = rowYOffset [r]; int w, h; - if (c == (int) colXOffset.count () - 1) + if (c == colXOffset.count () - 1) { if (x + m_pixmaps [r][c].width () >= width ()) w = m_pixmaps [r][c].width (); else w = width () - 1 - x; } else w = colXOffset [c + 1] - x; - if (r == (int) m_pixmaps.count () - 1) + if (r == m_pixmaps.count () - 1) { if (y + m_pixmaps [r][c].height () >= height ()) h = m_pixmaps [r][c].height (); else h = height () - 1 - y; } else h = rowYOffset [r + 1] - y; m_pixmapRects [r][c] = QRect (x, y, w, h); } } update (); } //--------------------------------------------------------------------- // public int kpToolWidgetBase::selectedRow () const { return m_selectedRow; } //--------------------------------------------------------------------- // public int kpToolWidgetBase::selectedCol () const { return m_selectedCol; } //--------------------------------------------------------------------- // public int kpToolWidgetBase::selected () const { if (m_selectedRow < 0 || - m_selectedRow >= (int) m_pixmaps.count () || + m_selectedRow >= m_pixmaps.count () || m_selectedCol < 0) { return -1; } int upto = 0; for (int y = 0; y < m_selectedRow; y++) upto += m_pixmaps [y].count (); - if (m_selectedCol >= (int) m_pixmaps [m_selectedRow].count ()) + if (m_selectedCol >= m_pixmaps [m_selectedRow].count ()) return -1; upto += m_selectedCol; return upto; } //--------------------------------------------------------------------- // public bool kpToolWidgetBase::hasPreviousOption (int *row, int *col) const { #if DEBUG_KP_TOOL_WIDGET_BASE qCDebug(kpLogWidgets) << "kpToolWidgetBase(" << objectName () << ")::hasPreviousOption() current row=" << m_selectedRow << " col=" << m_selectedCol << endl; #endif if (row) *row = -1; if (col) *col = -1; if (m_selectedRow < 0 || m_selectedCol < 0) return false; int newRow = m_selectedRow, newCol = m_selectedCol; newCol--; if (newCol < 0) { newRow--; if (newRow < 0) return false; newCol = m_pixmaps [newRow].count () - 1; if (newCol < 0) return false; } if (row) *row = newRow; if (col) *col = newCol; return true; } //--------------------------------------------------------------------- // public bool kpToolWidgetBase::hasNextOption (int *row, int *col) const { #if DEBUG_KP_TOOL_WIDGET_BASE qCDebug(kpLogWidgets) << "kpToolWidgetBase(" << objectName () << ")::hasNextOption() current row=" << m_selectedRow << " col=" << m_selectedCol << endl; #endif if (row) *row = -1; if (col) *col = -1; if (m_selectedRow < 0 || m_selectedCol < 0) return false; int newRow = m_selectedRow, newCol = m_selectedCol; newCol++; - if (newCol >= (int) m_pixmaps [newRow].count ()) + if (newCol >= m_pixmaps [newRow].count ()) { newRow++; - if (newRow >= (int) m_pixmaps.count ()) + if (newRow >= m_pixmaps.count ()) return false; newCol = 0; - if (newCol >= (int) m_pixmaps [newRow].count ()) + if (newCol >= m_pixmaps [newRow].count ()) return false; } if (row) *row = newRow; if (col) *col = newCol; return true; } //--------------------------------------------------------------------- // public slot virtual bool kpToolWidgetBase::setSelected (int row, int col, bool saveAsDefault) { #if DEBUG_KP_TOOL_WIDGET_BASE qCDebug(kpLogWidgets) << "kpToolWidgetBase::setSelected(row=" << row << ",col=" << col << ",saveAsDefault=" << saveAsDefault << ")" << endl; #endif if (row < 0 || col < 0 || - row >= (int) m_pixmapRects.count () || col >= (int) m_pixmapRects [row].count ()) + row >= m_pixmapRects.count () || col >= m_pixmapRects [row].count ()) { #if DEBUG_KP_TOOL_WIDGET_BASE qCDebug(kpLogWidgets) << "\tout of range"; #endif return false; } if (row == m_selectedRow && col == m_selectedCol) { #if DEBUG_KP_TOOL_WIDGET_BASE qCDebug(kpLogWidgets) << "\tNOP"; #endif if (saveAsDefault) saveSelectedAsDefault (); return true; } const int wasSelectedRow = m_selectedRow; const int wasSelectedCol = m_selectedCol; m_selectedRow = row; m_selectedCol = col; if (wasSelectedRow >= 0 && wasSelectedCol >= 0) { // unhighlight old option update (m_pixmapRects [wasSelectedRow][wasSelectedCol]); } // highlight new option update (m_pixmapRects [row][col]); #if DEBUG_KP_TOOL_WIDGET_BASE qCDebug(kpLogWidgets) << "\tOK"; #endif if (saveAsDefault) saveSelectedAsDefault (); emit optionSelected (row, col); return true; } //--------------------------------------------------------------------- // public slot bool kpToolWidgetBase::setSelected (int row, int col) { return setSelected (row, col, true/*set as default*/); } //--------------------------------------------------------------------- // public slot bool kpToolWidgetBase::selectPreviousOption () { int newRow, newCol; if (!hasPreviousOption (&newRow, &newCol)) return false; return setSelected (newRow, newCol); } //--------------------------------------------------------------------- // public slot bool kpToolWidgetBase::selectNextOption () { int newRow, newCol; if (!hasNextOption (&newRow, &newCol)) return false; return setSelected (newRow, newCol); } //--------------------------------------------------------------------- // protected virtual [base QWidget] bool kpToolWidgetBase::event (QEvent *e) { // TODO: It's unclear when we should call the base, call accept() and // return true or false. Look at other event() handlers. The // kpToolText one is wrong since after calling accept(), it calls // its base which calls ignore() :) if (e->type () == QEvent::ToolTip) { - QHelpEvent *he = (QHelpEvent *) e; + QHelpEvent *he = dynamic_cast (e); #if DEBUG_KP_TOOL_WIDGET_BASE qCDebug(kpLogWidgets) << "kpToolWidgetBase::event() QHelpEvent pos=" << he->pos (); #endif bool showedText = false; - for (int r = 0; r < (int) m_pixmapRects.count (); r++) + for (int r = 0; r < m_pixmapRects.count (); r++) { - for (int c = 0; c < (int) m_pixmapRects [r].count (); c++) + for (int c = 0; c < m_pixmapRects [r].count (); c++) { if (m_pixmapRects [r][c].contains (he->pos ())) { const QString tip = m_toolTips [r][c]; #if DEBUG_KP_TOOL_WIDGET_BASE qCDebug(kpLogWidgets) << "\tin option: r=" << r << "c=" << c << "tip='" << tip << "'" << endl; #endif if (!tip.isEmpty ()) { QToolTip::showText (he->globalPos (), tip, this); showedText = true; } e->accept (); goto exit_loops; } } } exit_loops: if (!showedText) { #if DEBUG_KP_TOOL_WIDGET_BASE qCDebug(kpLogWidgets) << "\thiding text"; #endif QToolTip::hideText (); } return true; } else return QWidget::event (e); } //--------------------------------------------------------------------- // protected virtual [base QWidget] void kpToolWidgetBase::mousePressEvent (QMouseEvent *e) { e->ignore (); if (e->button () != Qt::LeftButton) return; - for (int i = 0; i < (int) m_pixmapRects.count (); i++) + for (int i = 0; i < m_pixmapRects.count (); i++) { - for (int j = 0; j < (int) m_pixmapRects [i].count (); j++) + for (int j = 0; j < m_pixmapRects [i].count (); j++) { if (m_pixmapRects [i][j].contains (e->pos ())) { setSelected (i, j); e->accept (); return; } } } } //--------------------------------------------------------------------- // protected virtual [base QWidget] void kpToolWidgetBase::paintEvent (QPaintEvent *e) { #if DEBUG_KP_TOOL_WIDGET_BASE && 1 qCDebug(kpLogWidgets) << "kpToolWidgetBase::paintEvent(): rect=" << contentsRect (); #endif // Draw frame first. QFrame::paintEvent (e); QPainter painter (this); - for (int i = 0; i < (int) m_pixmaps.count (); i++) + for (int i = 0; i < m_pixmaps.count (); i++) { #if DEBUG_KP_TOOL_WIDGET_BASE && 1 qCDebug(kpLogWidgets) << "\tRow: " << i; #endif - for (int j = 0; j < (int) m_pixmaps [i].count (); j++) + for (int j = 0; j < m_pixmaps [i].count (); j++) { QRect rect = m_pixmapRects [i][j]; QPixmap pixmap = m_pixmaps [i][j]; #if DEBUG_KP_TOOL_WIDGET_BASE && 1 qCDebug(kpLogWidgets) << "\t\tCol: " << j << " rect=" << rect; #endif if (i == m_selectedRow && j == m_selectedCol) { painter.fillRect(rect, palette().color(QPalette::Highlight).rgb()); } #if DEBUG_KP_TOOL_WIDGET_BASE && 1 qCDebug(kpLogWidgets) << "\t\t\tdraw pixmap @ x=" << rect.x () + (rect.width () - pixmap.width ()) / 2 << " y=" << rect.y () + (rect.height () - pixmap.height ()) / 2 << endl; #endif painter.drawPixmap(QPoint(rect.x () + (rect.width () - pixmap.width ()) / 2, rect.y () + (rect.height () - pixmap.height ()) / 2), pixmap); } } } //--------------------------------------------------------------------- diff --git a/widgets/toolbars/options/kpToolWidgetFillStyle.cpp b/widgets/toolbars/options/kpToolWidgetFillStyle.cpp index 90048831..7ed44f72 100644 --- a/widgets/toolbars/options/kpToolWidgetFillStyle.cpp +++ b/widgets/toolbars/options/kpToolWidgetFillStyle.cpp @@ -1,181 +1,181 @@ /* Copyright (c) 2003-2007 Clarence Dang 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_WIDGET_FILL_STYLE 0 #include "kpToolWidgetFillStyle.h" #include "imagelib/kpColor.h" #include "kpDefs.h" #include "pixmapfx/kpPixmapFX.h" #include "tools/kpTool.h" #include "kpLogCategories.h" #include #include #include //--------------------------------------------------------------------- kpToolWidgetFillStyle::kpToolWidgetFillStyle (QWidget *parent, const QString &name) : kpToolWidgetBase (parent, name) { - for (int i = 0; i < (int) FillStyleNum; i++) + for (int i = 0; i < FillStyleNum; i++) { QPixmap pixmap; - pixmap = fillStylePixmap ((FillStyle) i, + pixmap = fillStylePixmap (static_cast (i), (width () - 2/*margin*/) * 3 / 4, (height () - 2/*margin*/ - 2/*spacing*/) * 3 / (3 * 4)); - addOption (pixmap, fillStyleName ((FillStyle) i)/*tooltip*/); + addOption (pixmap, fillStyleName (static_cast (i))/*tooltip*/); startNewOptionRow (); } finishConstruction (0, 0); } //--------------------------------------------------------------------- kpToolWidgetFillStyle::~kpToolWidgetFillStyle () { } //--------------------------------------------------------------------- // private QPixmap kpToolWidgetFillStyle::fillStylePixmap (FillStyle fs, int w, int h) { QPixmap pixmap ((w <= 0 ? width () : w), (h <= 0 ? height () : h)); pixmap.fill(palette().color(QPalette::Window)); const int penWidth = 2; const QRect rectRect(1, 1, w - 2, h - 2); QPainter painter(&pixmap); painter.setPen(kpPixmapFX::QPainterDrawRectPen(Qt::black, penWidth)); switch ( fs ) { case NoFill: { painter.setBrush(Qt::NoBrush); break; } case FillWithBackground: { painter.setBrush(Qt::gray); break; } case FillWithForeground: { painter.setBrush(Qt::black); break; } default: ; } painter.drawRect(rectRect); painter.end(); return pixmap; } //--------------------------------------------------------------------- // private QString kpToolWidgetFillStyle::fillStyleName (FillStyle fs) const { // do not complain about the "useless" breaks // as the return statements might not be return statements one day switch (fs) { case NoFill: return i18n ("No Fill"); break; case FillWithBackground: return i18n ("Fill with Background Color"); break; case FillWithForeground: return i18n ("Fill with Foreground Color"); break; default: return QString(); break; } } //--------------------------------------------------------------------- // public kpToolWidgetFillStyle::FillStyle kpToolWidgetFillStyle::fillStyle () const { #if DEBUG_KP_TOOL_WIDGET_FILL_STYLE qCDebug(kpLogWidgets) << "kpToolWidgetFillStyle::fillStyle() selected=" << selectedRow () << endl; #endif - return (FillStyle) selectedRow (); + return static_cast (selectedRow ()); } //--------------------------------------------------------------------- kpColor kpToolWidgetFillStyle::drawingBackgroundColor ( const kpColor &foregroundColor, const kpColor &backgroundColor) const { switch (fillStyle ()) { default: case NoFill: return kpColor::Invalid; case FillWithBackground: return backgroundColor; case FillWithForeground: return foregroundColor; } } //--------------------------------------------------------------------- // virtual protected slot [base kpToolWidgetBase] bool kpToolWidgetFillStyle::setSelected (int row, int col, bool saveAsDefault) { const bool ret = kpToolWidgetBase::setSelected (row, col, saveAsDefault); if (ret) emit fillStyleChanged (fillStyle ()); return ret; } //---------------------------------------------------------------------