diff --git a/commands/kpCommandHistoryBase.cpp b/commands/kpCommandHistoryBase.cpp index 19dc47f7..c5492993 100644 --- a/commands/kpCommandHistoryBase.cpp +++ b/commands/kpCommandHistoryBase.cpp @@ -1,730 +1,730 @@ /* 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); + m_actionUndo = new KToolBarPopupAction(KDE::icon(QStringLiteral("edit-undo")), undoActionText (), this); ac->addAction (KStandardAction::name (KStandardAction::Undo), m_actionUndo); ac->setDefaultShortcuts (m_actionUndo, KStandardShortcut::shortcut (KStandardShortcut::Undo)); connect (m_actionUndo, &KToolBarPopupAction::triggered, this, &kpCommandHistoryBase::undo); - m_actionRedo = new KToolBarPopupAction(KDE::icon("edit-redo"), redoActionText (), this); + m_actionRedo = new KToolBarPopupAction(KDE::icon(QStringLiteral("edit-redo")), redoActionText (), this); ac->addAction (KStandardAction::name (KStandardAction::Redo), m_actionRedo); ac->setDefaultShortcuts (m_actionRedo, KStandardShortcut::shortcut (KStandardShortcut::Redo)); connect (m_actionRedo, &KToolBarPopupAction::triggered, this, &kpCommandHistoryBase::redo ); m_actionUndo->setEnabled (false); m_actionRedo->setEnabled (false); connect (m_actionUndo->menu(), &QMenu::triggered, this, &kpCommandHistoryBase::undoUpToNumber); connect (m_actionRedo->menu(), &QMenu::triggered, this, &kpCommandHistoryBase::redoUpToNumber); 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 << ")"; #endif if (limit < 1 || limit > 5000/*"ought to be enough for anybody"*/) { qCCritical(kpLogCommands) << "kpCommandHistoryBase::setUndoMinLimit(" << limit << ")"; 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 << ")"; #endif if (limit < 1 || limit > 5000/*"ought to be enough for anybody"*/) { qCCritical(kpLogCommands) << "kpCommandHistoryBase::setUndoMaxLimit(" << limit << ")"; 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 << ")"; #endif if (sizeLimit < 0 || sizeLimit > (500 * 1048576)/*"ought to be enough for anybody"*/) { qCCritical(kpLogCommands) << "kpCommandHistoryBase::setUndoMaxLimitSizeLimit(" << sizeLimit << ")"; 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 << ")" #endif if (execute) { command->execute (); } m_undoCommandList.push_front (command); ::ClearPointerList (&m_redoCommandList); #if DEBUG_KP_COMMAND_HISTORY qCDebug(kpLogCommands) << "\tdocumentRestoredPosition=" << m_documentRestoredPosition; #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; #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; #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; #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; #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; #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 (); return (undoCommand) ? i18n ("&Undo: %1", undoCommand->name ()) : i18n ("&Undo"); } // protected QString kpCommandHistoryBase::redoActionText () const { kpCommand *redoCommand = nextRedoCommand (); return (redoCommand) ? i18n ("&Redo: %1", redoCommand->name ()) : i18n ("&Redo"); } // protected QString kpCommandHistoryBase::undoActionToolTip () const { kpCommand *undoCommand = nextUndoCommand (); return (undoCommand) ? i18n ("Undo: %1", undoCommand->name ()) : i18n ("Undo"); } // protected QString kpCommandHistoryBase::redoActionToolTip () const { kpCommand *redoCommand = nextRedoCommand (); return (redoCommand) ? i18n ("Redo: %1", redoCommand->name ()) : 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"; return; } #if DEBUG_KP_COMMAND_HISTORY qCDebug(kpLogCommands) << "\tsize=" << commandList->size () << " undoMinLimit=" << m_undoMinLimit << " undoMaxLimit=" << m_undoMaxLimit << " undoMaxLimitSizeLimit=" << m_undoMaxLimitSizeLimit; #endif 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; #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 #endif if (m_documentRestoredPosition != INT_MAX) { #if DEBUG_KP_COMMAND_HISTORY qCDebug(kpLogCommands) << "\t\tundoCmdList.size=" << m_undoCommandList.size () << " redoCmdList.size=" << m_redoCommandList.size (); #endif 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 (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"; #endif 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"; #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 << ")"; #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/dialogs/imagelib/transforms/kpTransformPreviewDialog.cpp b/dialogs/imagelib/transforms/kpTransformPreviewDialog.cpp index 606ac7da..9833f989 100644 --- a/dialogs/imagelib/transforms/kpTransformPreviewDialog.cpp +++ b/dialogs/imagelib/transforms/kpTransformPreviewDialog.cpp @@ -1,468 +1,468 @@ /* 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_TRANSFORM_PREVIEW_DIALOG 0 #include "dialogs/imagelib/transforms/kpTransformPreviewDialog.h" #include #include #include #include #include #include #include #include #include #include "kpLogCategories.h" #include #include "layers/selections/image/kpAbstractImageSelection.h" #include "imagelib/kpColor.h" #include "document/kpDocument.h" #include "pixmapfx/kpPixmapFX.h" #include "generic/widgets/kpResizeSignallingLabel.h" #include "environments/dialogs/imagelib/transforms/kpTransformDialogEnvironment.h" kpTransformPreviewDialog::kpTransformPreviewDialog (Features features, bool reserveTopRow, const QString &caption, const QString &afterActionText, bool actOnSelection, kpTransformDialogEnvironment *_env, QWidget *parent) : QDialog (parent), m_afterActionText (afterActionText), m_actOnSelection (actOnSelection), m_dimensionsGroupBox (nullptr), m_afterTransformDimensionsLabel (nullptr), m_previewGroupBox (nullptr), m_previewPixmapLabel (nullptr), m_gridLayout (nullptr), m_environ (_env) { setWindowTitle (caption); QDialogButtonBox *buttons = new QDialogButtonBox (QDialogButtonBox::Ok | QDialogButtonBox::Cancel, this); connect (buttons, &QDialogButtonBox::accepted, this, &kpTransformPreviewDialog::accept); connect (buttons, &QDialogButtonBox::rejected, this, &kpTransformPreviewDialog::reject); QWidget *baseWidget = new QWidget (this); m_mainWidget = baseWidget; auto *dialogLayout = new QVBoxLayout (this); dialogLayout->addWidget (baseWidget); dialogLayout->addWidget (buttons); if (document ()) { m_oldWidth = document ()->width (actOnSelection); m_oldHeight = document ()->height (actOnSelection); } else { m_oldWidth = m_oldHeight = 1; } if (features & Dimensions) { createDimensionsGroupBox (); } if (features & Preview) { createPreviewGroupBox (); } m_gridLayout = new QGridLayout (baseWidget ); m_gridLayout->setContentsMargins(0, 0, 0, 0); m_gridNumRows = reserveTopRow ? 1 : 0; if (m_dimensionsGroupBox || m_previewGroupBox) { if (m_dimensionsGroupBox && m_previewGroupBox) { m_gridLayout->addWidget (m_dimensionsGroupBox, m_gridNumRows, 0); m_gridLayout->addWidget (m_previewGroupBox, m_gridNumRows, 1); m_gridLayout->setColumnStretch (1, 1); } else if (m_dimensionsGroupBox) { m_gridLayout->addWidget (m_dimensionsGroupBox, m_gridNumRows, 0, 1, 2); } else if (m_previewGroupBox) { m_gridLayout->addWidget (m_previewGroupBox, m_gridNumRows, 0, 1, 2); } m_gridLayout->setRowStretch (m_gridNumRows, 1); m_gridNumRows++; } } kpTransformPreviewDialog::~kpTransformPreviewDialog () = default; // private void kpTransformPreviewDialog::createDimensionsGroupBox () { m_dimensionsGroupBox = new QGroupBox (i18n ("Dimensions"), mainWidget ()); auto *originalLabel = new QLabel (i18n ("Original:"), m_dimensionsGroupBox); QString originalDimensions; if (document ()) { originalDimensions = i18n ("%1 x %2", m_oldWidth, m_oldHeight); // Stop the Dimensions Group Box from resizing so often - const QString minimumLengthString ("100000 x 100000"); + const QString minimumLengthString (QStringLiteral("100000 x 100000")); const int padLength = minimumLengthString.length (); for (int i = originalDimensions.length (); i < padLength; i++) { originalDimensions += ' '; } } auto *originalDimensionsLabel = new QLabel (originalDimensions, m_dimensionsGroupBox); auto *afterTransformLabel = new QLabel (m_afterActionText, m_dimensionsGroupBox); m_afterTransformDimensionsLabel = new QLabel (m_dimensionsGroupBox); auto *dimensionsLayout = new QGridLayout (m_dimensionsGroupBox ); dimensionsLayout->addWidget (originalLabel, 0, 0, Qt::AlignBottom); dimensionsLayout->addWidget (originalDimensionsLabel, 0, 1, Qt::AlignBottom); dimensionsLayout->addWidget (afterTransformLabel, 1, 0, Qt::AlignTop); dimensionsLayout->addWidget (m_afterTransformDimensionsLabel, 1, 1, Qt::AlignTop); } // private void kpTransformPreviewDialog::createPreviewGroupBox () { m_previewGroupBox = new QGroupBox (i18n ("Preview"), mainWidget ()); m_previewPixmapLabel = new kpResizeSignallingLabel (m_previewGroupBox); m_previewPixmapLabel->setMinimumSize (150, 110); connect (m_previewPixmapLabel, &kpResizeSignallingLabel::resized, this, &kpTransformPreviewDialog::updatePreview); QPushButton *updatePushButton = new QPushButton (i18n ("&Update"), m_previewGroupBox); connect (updatePushButton, &QPushButton::clicked, this, &kpTransformPreviewDialog::slotUpdateWithWaitCursor); auto *previewLayout = new QVBoxLayout (m_previewGroupBox); previewLayout->addWidget (m_previewPixmapLabel, 1/*stretch*/); previewLayout->addWidget (updatePushButton, 0/*stretch*/, Qt::AlignHCenter); } // protected kpDocument *kpTransformPreviewDialog::document () const { return m_environ->document (); } // protected QWidget *kpTransformPreviewDialog::mainWidget () const { return m_mainWidget; } // protected void kpTransformPreviewDialog::addCustomWidgetToFront (QWidget *w) { m_gridLayout->addWidget (w, 0, 0, 1, 2); } // protected void kpTransformPreviewDialog::addCustomWidget (QWidget *w) { m_gridLayout->addWidget (w, m_gridNumRows, 0, 1, 2); m_gridNumRows++; } // public override [base QWidget] void kpTransformPreviewDialog::setUpdatesEnabled (bool enable) { QDialog::setUpdatesEnabled (enable); if (enable) { slotUpdateWithWaitCursor (); } } // private void kpTransformPreviewDialog::updateDimensions () { if (!m_dimensionsGroupBox) { return; } kpDocument *doc = document (); if (!doc) { return; } if (!updatesEnabled ()) { #if DEBUG_KP_TRANSFORM_PREVIEW_DIALOG qCDebug(kpLogDialogs) << "updates not enabled - aborting"; #endif return; } QSize newDim = newDimensions (); #if DEBUG_KP_TRANSFORM_PREVIEW_DIALOG qCDebug(kpLogDialogs) << "kpTransformPreviewDialog::updateDimensions(): newDim=" << newDim; #endif QString newDimString = i18n ("%1 x %2", newDim.width (), newDim.height ()); m_afterTransformDimensionsLabel->setText (newDimString); } // public static double kpTransformPreviewDialog::aspectScale (int newWidth, int newHeight, int oldWidth, int oldHeight) { double widthScale = double (newWidth) / double (oldWidth); double heightScale = double (newHeight) / double (oldHeight); // Keeps aspect ratio return qMin (widthScale, heightScale); } // public static int kpTransformPreviewDialog::scaleDimension (int dimension, double scale, int min, int max) { return qMax (min, qMin (max, qRound (dimension * scale))); } // private void kpTransformPreviewDialog::updateShrunkenDocumentPixmap () { #if DEBUG_KP_TRANSFORM_PREVIEW_DIALOG qCDebug(kpLogDialogs) << "kpTransformPreviewDialog::updateShrunkenDocumentPixmap()" << " shrunkenDocPixmap.size=" << m_shrunkenDocumentPixmap.size () << " previewPixmapLabelSizeWhenUpdatedPixmap=" << m_previewPixmapLabelSizeWhenUpdatedPixmap << " previewPixmapLabel.size=" << m_previewPixmapLabel->size () << endl; #endif if (!m_previewGroupBox) { return; } kpDocument *doc = document (); Q_ASSERT (doc && !doc->image ().isNull ()); if (m_shrunkenDocumentPixmap.isNull () || m_previewPixmapLabel->size () != m_previewPixmapLabelSizeWhenUpdatedPixmap) { #if DEBUG_KP_TRANSFORM_PREVIEW_DIALOG qCDebug(kpLogDialogs) << "\tupdating shrunkenDocPixmap"; #endif // TODO: Why the need to keep aspect ratio here? // Isn't scaling the skewed result maintaining aspect enough? double keepsAspectScale = aspectScale (m_previewPixmapLabel->width (), m_previewPixmapLabel->height (), m_oldWidth, m_oldHeight); kpImage image; if (m_actOnSelection) { kpAbstractImageSelection *sel = doc->imageSelection ()->clone (); if (!sel->hasContent ()) { sel->setBaseImage (doc->getSelectedBaseImage ()); } image = sel->transparentImage (); delete sel; } else { image = doc->image (); } m_shrunkenDocumentPixmap = kpPixmapFX::scale ( image, scaleDimension (m_oldWidth, keepsAspectScale, 1, m_previewPixmapLabel->width ()), scaleDimension (m_oldHeight, keepsAspectScale, 1, m_previewPixmapLabel->height ())); m_previewPixmapLabelSizeWhenUpdatedPixmap = m_previewPixmapLabel->size (); } } // private void kpTransformPreviewDialog::updatePreview () { #if DEBUG_KP_TRANSFORM_PREVIEW_DIALOG qCDebug(kpLogDialogs) << "kpTransformPreviewDialog::updatePreview()"; #endif if (!m_previewGroupBox) { return; } kpDocument *doc = document (); if (!doc) { return; } if (!updatesEnabled ()) { #if DEBUG_KP_TRANSFORM_PREVIEW_DIALOG qCDebug(kpLogDialogs) << "updates not enabled - aborting"; #endif return; } updateShrunkenDocumentPixmap (); if (!m_shrunkenDocumentPixmap.isNull ()) { QSize newDim = newDimensions (); double keepsAspectScale = aspectScale (m_previewPixmapLabel->width (), m_previewPixmapLabel->height (), newDim.width (), newDim.height ()); int targetWidth = scaleDimension (newDim.width (), keepsAspectScale, 1, // min m_previewPixmapLabel->width ()); // max int targetHeight = scaleDimension (newDim.height (), keepsAspectScale, 1, // min m_previewPixmapLabel->height ()); // max // TODO: Some effects work directly on QImage; so could cache the // QImage so that transformPixmap() is faster QImage transformedShrunkenDocumentPixmap = transformPixmap (m_shrunkenDocumentPixmap, targetWidth, targetHeight); QImage previewPixmap (m_previewPixmapLabel->width (), m_previewPixmapLabel->height (), QImage::Format_ARGB32_Premultiplied); previewPixmap.fill(QColor(Qt::transparent).rgba()); kpPixmapFX::setPixmapAt (&previewPixmap, (previewPixmap.width () - transformedShrunkenDocumentPixmap.width ()) / 2, (previewPixmap.height () - transformedShrunkenDocumentPixmap.height ()) / 2, transformedShrunkenDocumentPixmap); #if DEBUG_KP_TRANSFORM_PREVIEW_DIALOG qCDebug(kpLogDialogs) << "kpTransformPreviewDialog::updatePreview ():" << " shrunkenDocumentPixmap: w=" << m_shrunkenDocumentPixmap.width () << " h=" << m_shrunkenDocumentPixmap.height () << " previewPixmapLabel: w=" << m_previewPixmapLabel->width () << " h=" << m_previewPixmapLabel->height () << " transformedShrunkenDocumentPixmap: w=" << transformedShrunkenDocumentPixmap.width () << " h=" << transformedShrunkenDocumentPixmap.height () << " previewPixmap: w=" << previewPixmap.width () << " h=" << previewPixmap.height () << endl; #endif m_previewPixmapLabel->setPixmap (QPixmap::fromImage(previewPixmap)); // immediate update esp. for expensive previews m_previewPixmapLabel->repaint (); #if DEBUG_KP_TRANSFORM_PREVIEW_DIALOG qCDebug(kpLogDialogs) << "\tafter QLabel::setPixmap() previewPixmapLabel: w=" << m_previewPixmapLabel->width () << " h=" << m_previewPixmapLabel->height () << endl; #endif } } // protected slot virtual void kpTransformPreviewDialog::slotUpdate () { #if DEBUG_KP_TRANSFORM_PREVIEW_DIALOG qCDebug(kpLogDialogs) << "kpTransformPreviewDialog::slotUpdate()"; #endif updateDimensions (); updatePreview (); } // protected slot virtual void kpTransformPreviewDialog::slotUpdateWithWaitCursor () { #if DEBUG_KP_TRANSFORM_PREVIEW_DIALOG qCDebug(kpLogDialogs) << "kpTransformPreviewDialog::slotUpdateWithWaitCursor()"; #endif QApplication::setOverrideCursor (Qt::WaitCursor); slotUpdate (); QApplication::restoreOverrideCursor (); } diff --git a/dialogs/imagelib/transforms/kpTransformResizeScaleDialog.cpp b/dialogs/imagelib/transforms/kpTransformResizeScaleDialog.cpp index 44cbe222..d431e64c 100644 --- a/dialogs/imagelib/transforms/kpTransformResizeScaleDialog.cpp +++ b/dialogs/imagelib/transforms/kpTransformResizeScaleDialog.cpp @@ -1,837 +1,837 @@ /* 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 "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, &QDialogButtonBox::accepted, this, &kpTransformResizeScaleDialog::accept); connect (buttons, &QDialogButtonBox::rejected, this, &kpTransformResizeScaleDialog::reject); QWidget *baseWidget = new QWidget (this); auto *dialogLayout = new QVBoxLayout (this); dialogLayout->addWidget (baseWidget); dialogLayout->addWidget (buttons); QWidget *actOnBox = createActOnBox(baseWidget); QGroupBox *operationGroupBox = createOperationGroupBox(baseWidget); QGroupBox *dimensionsGroupBox = createDimensionsGroupBox(baseWidget); auto *baseLayout = new QVBoxLayout (baseWidget); baseLayout->setContentsMargins(0, 0, 0, 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); auto *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); } auto *lay = new QHBoxLayout (actOnBox); lay->setContentsMargins(0, 0, 0, 0); lay->addWidget (actOnLabel); lay->addWidget (m_actOnCombo, 1); connect (m_actOnCombo, static_cast(&QComboBox::activated), this, &kpTransformResizeScaleDialog::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"), + QStringLiteral ("resize"), i18n ("&Resize")); m_scaleButton = new QToolButton (operationGroupBox); toolButtonSetLook (m_scaleButton, - QLatin1String ("scale"), + QStringLiteral ("scale"), i18n ("&Scale")); m_smoothScaleButton = new QToolButton (operationGroupBox); toolButtonSetLook (m_smoothScaleButton, - QLatin1String ("smooth_scale"), + QStringLiteral ("smooth_scale"), i18n ("S&mooth Scale")); auto *resizeScaleButtonGroup = new QButtonGroup (baseWidget); resizeScaleButtonGroup->addButton (m_resizeButton); resizeScaleButtonGroup->addButton (m_scaleButton); resizeScaleButtonGroup->addButton (m_smoothScaleButton); auto *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, &QToolButton::toggled, this, &kpTransformResizeScaleDialog::slotTypeChanged); connect (m_scaleButton, &QToolButton::toggled, this, &kpTransformResizeScaleDialog::slotTypeChanged); connect (m_smoothScaleButton, &QToolButton::toggled, this, &kpTransformResizeScaleDialog::slotTypeChanged); return operationGroupBox; } //--------------------------------------------------------------------- // private QGroupBox *kpTransformResizeScaleDialog::createDimensionsGroupBox(QWidget *baseWidget) { QGroupBox *dimensionsGroupBox = new QGroupBox (i18n ("Dimensions"), baseWidget); auto *widthLabel = new QLabel (i18n ("Width:"), dimensionsGroupBox); widthLabel->setAlignment (widthLabel->alignment () | Qt::AlignHCenter); auto *heightLabel = new QLabel (i18n ("Height:"), dimensionsGroupBox); heightLabel->setAlignment (heightLabel->alignment () | Qt::AlignHCenter); auto *originalLabel = new QLabel (i18n ("Original:"), dimensionsGroupBox); m_originalWidthInput = new QSpinBox; m_originalWidthInput->setRange(1, INT_MAX); m_originalWidthInput->setValue(document()->width(static_cast (selection()))); auto *xLabel0 = new QLabel (i18n ("x"), dimensionsGroupBox); m_originalHeightInput = new QSpinBox; m_originalHeightInput->setRange(1, INT_MAX); m_originalHeightInput->setValue(document()->height(static_cast (selection()))); auto *newLabel = new QLabel (i18n ("&New:"), dimensionsGroupBox); m_newWidthInput = new QSpinBox; m_newWidthInput->setRange(1, INT_MAX); auto *xLabel1 = new QLabel (i18n ("x"), dimensionsGroupBox); m_newHeightInput = new QSpinBox; m_newHeightInput->setRange(1, INT_MAX); auto *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("%")); auto *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); auto *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, static_cast(&QSpinBox::valueChanged), this, &kpTransformResizeScaleDialog::slotWidthChanged); connect (m_newHeightInput, static_cast(&QSpinBox::valueChanged), this, &kpTransformResizeScaleDialog::slotHeightChanged); // 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, static_cast(&QDoubleSpinBox::valueChanged), this, &kpTransformResizeScaleDialog::slotPercentWidthChanged); connect (m_percentHeightInput, static_cast(&QDoubleSpinBox::valueChanged), this, &kpTransformResizeScaleDialog::slotPercentHeightChanged); connect (m_keepAspectRatioCheckBox, &QCheckBox::toggled, this, &kpTransformResizeScaleDialog::setKeepAspectRatio); 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 << ")"; #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 << ")"; #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 << ")"; #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; } if (m_scaleButton->isChecked ()) { return kpTransformResizeScaleCommand::Scale; } 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/imagelib/transforms/kpTransformRotateDialog.cpp b/dialogs/imagelib/transforms/kpTransformRotateDialog.cpp index 0b5e87a0..ef92d867 100644 --- a/dialogs/imagelib/transforms/kpTransformRotateDialog.cpp +++ b/dialogs/imagelib/transforms/kpTransformRotateDialog.cpp @@ -1,322 +1,322 @@ /* 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_ROTATE 0 #include "kpTransformRotateDialog.h" #include "kpDefs.h" #include "document/kpDocument.h" #include "pixmapfx/kpPixmapFX.h" #include "tools/kpTool.h" #include "environments/dialogs/imagelib/transforms/kpTransformDialogEnvironment.h" #include "views/manager/kpViewManager.h" #include "kpLogCategories.h" #include #include #include #include #include #include #include #include #include #include #include #include // private static int kpTransformRotateDialog::s_lastWidth = -1, kpTransformRotateDialog::s_lastHeight = -1; // private static bool kpTransformRotateDialog::s_lastIsClockwise = true; int kpTransformRotateDialog::s_lastAngleCustom = 0; kpTransformRotateDialog::kpTransformRotateDialog (bool actOnSelection, kpTransformDialogEnvironment *_env, QWidget *parent) : kpTransformPreviewDialog (kpTransformPreviewDialog::AllFeatures, false/*don't reserve top row*/, actOnSelection ? i18nc ("@title:window", "Rotate Selection") : i18nc ("@title:window", "Rotate Image"), i18n ("After rotate:"), actOnSelection, _env, parent) { s_lastAngleCustom = 0; createDirectionGroupBox (); createAngleGroupBox (); if (s_lastWidth > 0 && s_lastHeight > 0) { resize (s_lastWidth, s_lastHeight); } slotAngleCustomRadioButtonToggled (m_angleCustomRadioButton->isChecked ()); slotUpdate (); } kpTransformRotateDialog::~kpTransformRotateDialog () { s_lastWidth = width (); s_lastHeight = height (); } // private void kpTransformRotateDialog::createDirectionGroupBox () { auto *directionGroupBox = new QGroupBox (i18n ("Direction"), mainWidget ()); addCustomWidget (directionGroupBox); auto *antiClockwisePixmapLabel = new QLabel (directionGroupBox); - antiClockwisePixmapLabel->setPixmap (UserIcon ("image_rotate_anticlockwise")); + antiClockwisePixmapLabel->setPixmap (UserIcon (QStringLiteral("image_rotate_anticlockwise"))); auto *clockwisePixmapLabel = new QLabel (directionGroupBox); - clockwisePixmapLabel->setPixmap (UserIcon ("image_rotate_clockwise")); + clockwisePixmapLabel->setPixmap (UserIcon (QStringLiteral("image_rotate_clockwise"))); m_antiClockwiseRadioButton = new QRadioButton (i18n ("Cou&nterclockwise"), directionGroupBox); m_clockwiseRadioButton = new QRadioButton (i18n ("C&lockwise"), directionGroupBox); m_antiClockwiseRadioButton->setChecked (!s_lastIsClockwise); m_clockwiseRadioButton->setChecked (s_lastIsClockwise); auto *directionLayout = new QGridLayout (directionGroupBox ); directionLayout->addWidget (antiClockwisePixmapLabel, 0, 0, Qt::AlignCenter); directionLayout->addWidget (clockwisePixmapLabel, 0, 1, Qt::AlignCenter); directionLayout->addWidget (m_antiClockwiseRadioButton, 1, 0, Qt::AlignCenter); directionLayout->addWidget (m_clockwiseRadioButton, 1, 1, Qt::AlignCenter); connect (m_antiClockwiseRadioButton, &QRadioButton::toggled, this, &kpTransformRotateDialog::slotUpdate); connect (m_clockwiseRadioButton, &QRadioButton::toggled, this, &kpTransformRotateDialog::slotUpdate); } // private void kpTransformRotateDialog::createAngleGroupBox () { auto *angleGroupBox = new QGroupBox (i18n ("Angle"), mainWidget ()); addCustomWidget (angleGroupBox); m_angle90RadioButton = new QRadioButton (i18n ("90 °rees"), angleGroupBox); m_angle180RadioButton = new QRadioButton (i18n ("180 d&egrees"), angleGroupBox); m_angle270RadioButton = new QRadioButton (i18n ("270 de&grees"), angleGroupBox); m_angleCustomRadioButton = new QRadioButton (i18n ("C&ustom:"), angleGroupBox); m_angleCustomInput = new QSpinBox; m_angleCustomInput->setMinimum(-359); m_angleCustomInput->setMaximum(+359); m_angleCustomInput->setValue(s_lastAngleCustom); auto *degreesLabel = new QLabel (i18n ("degrees"), angleGroupBox); m_angleCustomRadioButton->setChecked (true); auto *angleLayout = new QGridLayout (angleGroupBox ); angleLayout->addWidget (m_angle90RadioButton, 0, 0, 1, 3); angleLayout->addWidget (m_angle180RadioButton, 1, 0, 1, 3); angleLayout->addWidget (m_angle270RadioButton, 2, 0, 1, 3); angleLayout->addWidget (m_angleCustomRadioButton, 3, 0); angleLayout->addWidget (m_angleCustomInput, 3, 1); angleLayout->addWidget (degreesLabel, 3, 2); angleLayout->setColumnStretch (1, 2); // Stretch Custom Angle Input connect (m_angle90RadioButton, &QRadioButton::toggled, this, &kpTransformRotateDialog::slotUpdate); connect (m_angle180RadioButton, &QRadioButton::toggled, this, &kpTransformRotateDialog::slotUpdate); connect (m_angle270RadioButton, &QRadioButton::toggled, this, &kpTransformRotateDialog::slotUpdate); connect (m_angleCustomRadioButton, &QRadioButton::toggled, this, &kpTransformRotateDialog::slotAngleCustomRadioButtonToggled); connect (m_angleCustomRadioButton, &QRadioButton::toggled, this, &kpTransformRotateDialog::slotUpdate); connect (m_angleCustomInput, static_cast(&QSpinBox::valueChanged), this, &kpTransformRotateDialog::slotUpdate); } // public virtual [base kpTransformPreviewDialog] bool kpTransformRotateDialog::isNoOp () const { return (angle () == 0); } // public int kpTransformRotateDialog::angle () const { int retAngle; if (m_angle90RadioButton->isChecked ()) { retAngle = 90; } else if (m_angle180RadioButton->isChecked ()) { retAngle = 180; } else if (m_angle270RadioButton->isChecked ()) { retAngle = 270; } else { // if (m_angleCustomRadioButton->isChecked ()) retAngle = m_angleCustomInput->value (); } if (m_antiClockwiseRadioButton->isChecked ()) { retAngle *= -1; } if (retAngle < 0) { retAngle += ((0 - retAngle) / 360 + 1) * 360; } if (retAngle >= 360) { retAngle -= ((retAngle - 360) / 360 + 1) * 360; } return retAngle; } // private virtual [base kpTransformPreviewDialog] QSize kpTransformRotateDialog::newDimensions () const { QTransform matrix = kpPixmapFX::rotateMatrix (m_oldWidth, m_oldHeight, angle ()); QRect rect = matrix.mapRect (QRect (0, 0, m_oldWidth, m_oldHeight)); return rect.size (); } // private virtual [base kpTransformPreviewDialog] QImage kpTransformRotateDialog::transformPixmap (const QImage &image, int targetWidth, int targetHeight) const { return kpPixmapFX::rotate (image, angle (), m_environ->backgroundColor (m_actOnSelection), targetWidth, targetHeight); } // private slot void kpTransformRotateDialog::slotAngleCustomRadioButtonToggled (bool isChecked) { m_angleCustomInput->setEnabled (isChecked); if (isChecked) { m_angleCustomInput->setFocus(); } } // private slot virtual [base kpTransformPreviewDialog] void kpTransformRotateDialog::slotUpdate () { s_lastIsClockwise = m_clockwiseRadioButton->isChecked (); s_lastAngleCustom = m_angleCustomInput->value (); kpTransformPreviewDialog::slotUpdate (); } // private slot virtual [base QDialog] void kpTransformRotateDialog::accept () { KLocalizedString message; QString caption, continueButtonText; if (document ()->selection ()) { if (!document ()->textSelection ()) { message = ki18n ("

Rotating 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 rotate the selection?

"); caption = i18nc ("@title:window", "Rotate Selection?"); continueButtonText = i18n ("Rotat&e Selection"); } } else { message = ki18n ("

Rotating 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 rotate the image?

"); caption = i18nc ("@title:window", "Rotate Image?"); continueButtonText = i18n ("Rotat&e Image"); } const int newWidth = newDimensions ().width (); const int newHeight = newDimensions ().height (); if (kpTool::warnIfBigImageSize (m_oldWidth, m_oldHeight, newWidth, newHeight, message.subs (newWidth).subs (newHeight).toString (), caption, continueButtonText, this)) { QDialog::accept (); } } diff --git a/dialogs/imagelib/transforms/kpTransformSkewDialog.cpp b/dialogs/imagelib/transforms/kpTransformSkewDialog.cpp index 29a983bd..26896f5f 100644 --- a/dialogs/imagelib/transforms/kpTransformSkewDialog.cpp +++ b/dialogs/imagelib/transforms/kpTransformSkewDialog.cpp @@ -1,298 +1,298 @@ /* 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_SKEW 0 #define DEBUG_KP_TOOL_SKEW_DIALOG 0 #include "dialogs/imagelib/transforms/kpTransformSkewDialog.h" #include #include #include #include #include #include #include #include #include #include "kpLogCategories.h" #include #include #include "kpDefs.h" #include "document/kpDocument.h" #include "pixmapfx/kpPixmapFX.h" #include "tools/kpTool.h" #include "environments/dialogs/imagelib/transforms/kpTransformDialogEnvironment.h" // private static int kpTransformSkewDialog::s_lastWidth = -1, kpTransformSkewDialog::s_lastHeight = -1; // private static int kpTransformSkewDialog::s_lastHorizontalAngle = 0, kpTransformSkewDialog::s_lastVerticalAngle = 0; kpTransformSkewDialog::kpTransformSkewDialog (bool actOnSelection, kpTransformDialogEnvironment *_env, QWidget *parent) : kpTransformPreviewDialog (kpTransformPreviewDialog::AllFeatures, false/*don't reserve top row*/, actOnSelection ? i18nc ("@title:window", "Skew Selection") : i18nc ("@title:window", "Skew Image"), i18n ("After skew:"), actOnSelection, _env, parent) { // Too confusing - disable for now s_lastHorizontalAngle = s_lastVerticalAngle = 0; createAngleGroupBox (); if (s_lastWidth > 0 && s_lastHeight > 0) { resize (s_lastWidth, s_lastHeight); } slotUpdate (); m_horizontalSkewInput->setFocus (); } kpTransformSkewDialog::~kpTransformSkewDialog () { s_lastWidth = width (); s_lastHeight = height (); } // private void kpTransformSkewDialog::createAngleGroupBox () { auto *angleGroupBox = new QGroupBox (i18n ("Angle"), mainWidget ()); addCustomWidget (angleGroupBox); auto *horizontalSkewPixmapLabel = new QLabel (angleGroupBox); - horizontalSkewPixmapLabel->setPixmap (UserIcon ("image_skew_horizontal")); + horizontalSkewPixmapLabel->setPixmap (UserIcon (QStringLiteral("image_skew_horizontal"))); auto *horizontalSkewLabel = new QLabel (i18n ("&Horizontal:"), angleGroupBox); m_horizontalSkewInput = new QSpinBox; m_horizontalSkewInput->setValue(s_lastHorizontalAngle); m_horizontalSkewInput->setMinimum(-89); m_horizontalSkewInput->setMaximum(+89); auto *horizontalSkewDegreesLabel = new QLabel (i18n ("degrees"), angleGroupBox); auto *verticalSkewPixmapLabel = new QLabel (angleGroupBox); - verticalSkewPixmapLabel->setPixmap (UserIcon ("image_skew_vertical")); + verticalSkewPixmapLabel->setPixmap (UserIcon (QStringLiteral("image_skew_vertical"))); auto *verticalSkewLabel = new QLabel (i18n ("&Vertical:"), angleGroupBox); m_verticalSkewInput = new QSpinBox; m_verticalSkewInput->setValue(s_lastVerticalAngle); m_verticalSkewInput->setMinimum(-89); m_verticalSkewInput->setMaximum(+89); auto *verticalSkewDegreesLabel = new QLabel (i18n ("degrees"), angleGroupBox); horizontalSkewLabel->setBuddy (m_horizontalSkewInput); verticalSkewLabel->setBuddy (m_verticalSkewInput); auto *angleLayout = new QGridLayout (angleGroupBox); angleLayout->addWidget (horizontalSkewPixmapLabel, 0, 0); angleLayout->addWidget (horizontalSkewLabel, 0, 1); angleLayout->addWidget (m_horizontalSkewInput, 0, 2, Qt::AlignVCenter); angleLayout->addWidget (horizontalSkewDegreesLabel, 0, 3); angleLayout->addWidget (verticalSkewPixmapLabel, 1, 0); angleLayout->addWidget (verticalSkewLabel, 1, 1); angleLayout->addWidget (m_verticalSkewInput, 1, 2, Qt::AlignVCenter); angleLayout->addWidget (verticalSkewDegreesLabel, 1, 3); connect (m_horizontalSkewInput, static_cast(&QSpinBox::valueChanged), this, &kpTransformSkewDialog::slotUpdate); connect (m_verticalSkewInput, static_cast(&QSpinBox::valueChanged), this, &kpTransformSkewDialog::slotUpdate); } // private virtual [base kpTransformPreviewDialog] QSize kpTransformSkewDialog::newDimensions () const { kpDocument *doc = document (); Q_ASSERT (doc); auto skewMatrix = kpPixmapFX::skewMatrix (doc->image (), horizontalAngleForPixmapFX (), verticalAngleForPixmapFX ()); auto skewRect = skewMatrix.mapRect (doc->rect (m_actOnSelection)); return {skewRect.width (), skewRect.height ()}; } // private virtual [base kpTransformPreviewDialog] QImage kpTransformSkewDialog::transformPixmap (const QImage &image, int targetWidth, int targetHeight) const { return kpPixmapFX::skew (image, horizontalAngleForPixmapFX (), verticalAngleForPixmapFX (), m_environ->backgroundColor (m_actOnSelection), targetWidth, targetHeight); } // private void kpTransformSkewDialog::updateLastAngles () { s_lastHorizontalAngle = horizontalAngle (); s_lastVerticalAngle = verticalAngle (); } // private slot virtual [base kpTransformPreviewDialog] void kpTransformSkewDialog::slotUpdate () { updateLastAngles (); kpTransformPreviewDialog::slotUpdate (); } // public int kpTransformSkewDialog::horizontalAngle () const { return m_horizontalSkewInput->value (); } // public int kpTransformSkewDialog::verticalAngle () const { return m_verticalSkewInput->value (); } // public static int kpTransformSkewDialog::horizontalAngleForPixmapFX (int hangle) { return -hangle; } // public static int kpTransformSkewDialog::verticalAngleForPixmapFX (int vangle) { return -vangle; } // public int kpTransformSkewDialog::horizontalAngleForPixmapFX () const { return kpTransformSkewDialog::horizontalAngleForPixmapFX (horizontalAngle ()); } // public int kpTransformSkewDialog::verticalAngleForPixmapFX () const { return kpTransformSkewDialog::verticalAngleForPixmapFX (verticalAngle ()); } // public virtual [base kpTransformPreviewDialog] bool kpTransformSkewDialog::isNoOp () const { return (horizontalAngle () == 0) && (verticalAngle () == 0); } // private slot virtual [base QDialog] void kpTransformSkewDialog::accept () { KLocalizedString message; QString caption, continueButtonText; if (document ()->selection ()) { if (!document ()->textSelection ()) { message = ki18n ("

Skewing 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 skew the selection?

"); caption = i18nc ("@title:window", "Skew Selection?"); continueButtonText = i18n ("Sk&ew Selection"); } } else { message = ki18n ("

Skewing 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 skew the image?

"); caption = i18nc ("@title:window", "Skew Image?"); continueButtonText = i18n ("Sk&ew Image"); } const int newWidth = newDimensions ().width (); const int newHeight = newDimensions ().height (); if (kpTool::warnIfBigImageSize (m_oldWidth, m_oldHeight, newWidth, newHeight, message.subs (newWidth).subs (newHeight).toString (), caption, continueButtonText, this)) { QDialog::accept (); } } diff --git a/document/kpDocumentSaveOptions.cpp b/document/kpDocumentSaveOptions.cpp index da4e3c07..587e7a37 100644 --- a/document/kpDocumentSaveOptions.cpp +++ b/document/kpDocumentSaveOptions.cpp @@ -1,622 +1,622 @@ /* 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 0 #include "kpDocumentSaveOptions.h" #include "kpDefs.h" #include "pixmapfx/kpPixmapFX.h" #include #include "kpLogCategories.h" #include #include #include #include //--------------------------------------------------------------------- class kpDocumentSaveOptionsPrivate { public: QString m_mimeType; int m_colorDepth{}; bool m_dither{}; int m_quality{}; }; //--------------------------------------------------------------------- kpDocumentSaveOptions::kpDocumentSaveOptions () : d (new kpDocumentSaveOptionsPrivate ()) { d->m_mimeType = invalidMimeType (); d->m_colorDepth = invalidColorDepth (); d->m_dither = initialDither (); d->m_quality = invalidQuality (); } //--------------------------------------------------------------------- kpDocumentSaveOptions::kpDocumentSaveOptions (const kpDocumentSaveOptions &rhs) : d (new kpDocumentSaveOptionsPrivate ()) { d->m_mimeType = rhs.mimeType (); d->m_colorDepth = rhs.colorDepth (); d->m_dither = rhs.dither (); d->m_quality = rhs.quality (); } //--------------------------------------------------------------------- -kpDocumentSaveOptions::kpDocumentSaveOptions (QString mimeType, int colorDepth, bool dither, int quality) +kpDocumentSaveOptions::kpDocumentSaveOptions (const QString &mimeType, int colorDepth, bool dither, int quality) : d (new kpDocumentSaveOptionsPrivate ()) { d->m_mimeType = mimeType; d->m_colorDepth = colorDepth; d->m_dither = dither; d->m_quality = quality; } //--------------------------------------------------------------------- kpDocumentSaveOptions::~kpDocumentSaveOptions () { delete d; } //--------------------------------------------------------------------- // public bool kpDocumentSaveOptions::operator== (const kpDocumentSaveOptions &rhs) const { return (mimeType () == rhs.mimeType () && colorDepth () == rhs.colorDepth () && dither () == rhs.dither () && quality () == rhs.quality ()); } //--------------------------------------------------------------------- // public bool kpDocumentSaveOptions::operator!= (const kpDocumentSaveOptions &rhs) const { return !(*this == rhs); } //--------------------------------------------------------------------- // public kpDocumentSaveOptions &kpDocumentSaveOptions::operator= (const kpDocumentSaveOptions &rhs) { setMimeType (rhs.mimeType ()); setColorDepth (rhs.colorDepth ()); setDither (rhs.dither ()); setQuality (rhs.quality ()); return *this; } //--------------------------------------------------------------------- // public void kpDocumentSaveOptions::printDebug (const QString &prefix) const { const QString usedPrefix = !prefix.isEmpty () ? prefix + QLatin1String (": ") : QString(); qCDebug(kpLogDocument) << usedPrefix << "mimeType=" << mimeType () << " colorDepth=" << colorDepth () << " dither=" << dither () << " quality=" << quality (); } //--------------------------------------------------------------------- // public QString kpDocumentSaveOptions::mimeType () const { return d->m_mimeType; } //--------------------------------------------------------------------- // public void kpDocumentSaveOptions::setMimeType (const QString &mimeType) { d->m_mimeType = mimeType; } //--------------------------------------------------------------------- // public static QString kpDocumentSaveOptions::invalidMimeType () { return QString(); } //--------------------------------------------------------------------- // public static bool kpDocumentSaveOptions::mimeTypeIsInvalid (const QString &mimeType) { return (mimeType == invalidMimeType ()); } //--------------------------------------------------------------------- // public bool kpDocumentSaveOptions::mimeTypeIsInvalid () const { return mimeTypeIsInvalid (mimeType ()); } //--------------------------------------------------------------------- // public int kpDocumentSaveOptions::colorDepth () const { return d->m_colorDepth; } // public void kpDocumentSaveOptions::setColorDepth (int depth) { d->m_colorDepth = depth; } // public static int kpDocumentSaveOptions::invalidColorDepth () { return -1; } // public static bool kpDocumentSaveOptions::colorDepthIsInvalid (int colorDepth) { return (colorDepth != 1 && colorDepth != 8 && colorDepth != 32); } // public bool kpDocumentSaveOptions::colorDepthIsInvalid () const { return colorDepthIsInvalid (colorDepth ()); } // public bool kpDocumentSaveOptions::dither () const { return d->m_dither; } // public void kpDocumentSaveOptions::setDither (bool dither) { d->m_dither = dither; } // public static int kpDocumentSaveOptions::initialDither () { return false; // to avoid accidental double dithering } // public int kpDocumentSaveOptions::quality () const { return d->m_quality; } // public void kpDocumentSaveOptions::setQuality (int quality) { d->m_quality = quality; } // public static int kpDocumentSaveOptions::invalidQuality () { return -2; } // public static bool kpDocumentSaveOptions::qualityIsInvalid (int quality) { return (quality < -1 || quality > 100); } // public bool kpDocumentSaveOptions::qualityIsInvalid () const { return qualityIsInvalid (quality ()); } // public static QString kpDocumentSaveOptions::defaultMimeType (const KConfigGroup &config) { return config.readEntry (kpSettingForcedMimeType, - QString::fromLatin1 ("image/png")); + QStringLiteral ("image/png")); } // public static void kpDocumentSaveOptions::saveDefaultMimeType (KConfigGroup &config, const QString &mimeType) { config.writeEntry (kpSettingForcedMimeType, mimeType); } // public static int kpDocumentSaveOptions::defaultColorDepth (const KConfigGroup &config) { int colorDepth = config.readEntry (kpSettingForcedColorDepth, -1); if (colorDepthIsInvalid (colorDepth)) { // (not screen depth, in case of transparency) colorDepth = 32; } return colorDepth; } //--------------------------------------------------------------------- // public static void kpDocumentSaveOptions::saveDefaultColorDepth (KConfigGroup &config, int colorDepth) { config.writeEntry (kpSettingForcedColorDepth, colorDepth); } //--------------------------------------------------------------------- // public static int kpDocumentSaveOptions::defaultDither (const KConfigGroup &config) { return config.readEntry (kpSettingForcedDither, initialDither ()); } //--------------------------------------------------------------------- // public static void kpDocumentSaveOptions::saveDefaultDither (KConfigGroup &config, bool dither) { config.writeEntry (kpSettingForcedDither, dither); } //--------------------------------------------------------------------- // public static int kpDocumentSaveOptions::defaultQuality (const KConfigGroup &config) { int val = config.readEntry (kpSettingForcedQuality, -1); return qualityIsInvalid (val) ? -1 : val; } //--------------------------------------------------------------------- // public static void kpDocumentSaveOptions::saveDefaultQuality (KConfigGroup &config, int quality) { config.writeEntry (kpSettingForcedQuality, quality); } //--------------------------------------------------------------------- // public static kpDocumentSaveOptions kpDocumentSaveOptions::defaultDocumentSaveOptions (const KConfigGroup &config) { kpDocumentSaveOptions saveOptions; saveOptions.setMimeType (defaultMimeType (config)); saveOptions.setColorDepth (defaultColorDepth (config)); saveOptions.setDither (defaultDither (config)); saveOptions.setQuality (defaultQuality (config)); #if DEBUG_KP_DOCUMENT_SAVE_OPTIONS saveOptions.printDebug ("kpDocumentSaveOptions::defaultDocumentSaveOptions()"); #endif return saveOptions; } //--------------------------------------------------------------------- // public static bool kpDocumentSaveOptions::saveDefaultDifferences (KConfigGroup &config, const kpDocumentSaveOptions &oldDocInfo, const kpDocumentSaveOptions &newDocInfo) { bool savedSomething = false; #if DEBUG_KP_DOCUMENT_SAVE_OPTIONS qCDebug(kpLogDocument) << "kpDocumentSaveOptions::saveDefaultDifferences()"; oldDocInfo.printDebug ("\told"); newDocInfo.printDebug ("\tnew"); #endif if (newDocInfo.mimeType () != oldDocInfo.mimeType ()) { saveDefaultMimeType (config, newDocInfo.mimeType ()); savedSomething = true; } if (newDocInfo.colorDepth () != oldDocInfo.colorDepth ()) { saveDefaultColorDepth (config, newDocInfo.colorDepth ()); savedSomething = true; } if (newDocInfo.dither () != oldDocInfo.dither ()) { saveDefaultDither (config, newDocInfo.dither ()); savedSomething = true; } if (newDocInfo.quality () != oldDocInfo.quality ()) { saveDefaultQuality (config, newDocInfo.quality ()); savedSomething = true; } return savedSomething; } //--------------------------------------------------------------------- static QStringList mimeTypesSupportingProperty (const QString &property, const QStringList &defaultMimeTypesWithPropertyList) { QStringList mimeTypeList; KConfigGroup cfg (KSharedConfig::openConfig (), kpSettingsGroupMimeTypeProperties); if (cfg.hasKey (property)) { mimeTypeList = cfg.readEntry (property, QStringList ()); } else { mimeTypeList = defaultMimeTypesWithPropertyList; cfg.writeEntry (property, mimeTypeList); cfg.sync (); } return mimeTypeList; } //--------------------------------------------------------------------- static bool mimeTypeSupportsProperty (const QString &mimeType, const QString &property, const QStringList &defaultMimeTypesWithPropertyList) { const auto mimeTypeList = mimeTypesSupportingProperty ( property, defaultMimeTypesWithPropertyList); return mimeTypeList.contains (mimeType); } //--------------------------------------------------------------------- // SYNC: update mime info // // Only care about writable mimetypes. // // Run: // // branches/kolourpaint/control/scripts/gen_mimetype_line.sh Write | // branches/kolourpaint/control/scripts/split_mimetype_line.pl // // in the version of kdelibs/kimgio/ (e.g. KDE 4.0) KolourPaint is shipped with, // to check for any new mimetypes to add info for. In the methods below, // you can specify this info (maximum color depth, whether it's lossy etc.). // // Update the below list and if you do change any of that info, bump up // "kpSettingsGroupMimeTypeProperties" in kpDefs.h. // // Currently, Depth and Quality settings are mutually exclusive with // Depth overriding Quality. I've currently favoured Quality with the // below mimetypes (i.e. all lossy mimetypes are only given Quality settings, // no Depth settings). // // Mimetypes done: // image/bmp // image/jpeg // image/jp2 // image/png // image/tiff // image/x-eps // image/x-pcx // image/x-portable-bitmap // image/x-portable-graymap // image/x-portable-pixmap // image/x-rgb // image/x-tga // image/x-xbitmap // image/x-xpixmap // video/x-mng [COULD NOT TEST] // // To test whether depth is configurable, write an image in the new // mimetype with all depths and read each one back. See what // kpDocument thinks the depth is when it gets QImage to read it. // public static int kpDocumentSaveOptions::mimeTypeMaximumColorDepth (const QString &mimeType) { QStringList defaultList; // SYNC: update mime info here // Grayscale actually (unenforced since depth not set to configurable) - defaultList << QLatin1String ("image/x-eps:32"); + defaultList << QStringLiteral ("image/x-eps:32"); - defaultList << QLatin1String ("image/x-portable-bitmap:1"); + defaultList << QStringLiteral ("image/x-portable-bitmap:1"); // Grayscale actually (unenforced since depth not set to configurable) - defaultList << QLatin1String ("image/x-portable-graymap:8"); + defaultList << QStringLiteral ("image/x-portable-graymap:8"); - defaultList << QLatin1String ("image/x-xbitmap:1"); + defaultList << QStringLiteral ("image/x-xbitmap:1"); const auto mimeTypeList = mimeTypesSupportingProperty ( kpSettingMimeTypeMaximumColorDepth, defaultList); const QString mimeTypeColon = mimeType + QLatin1String (":"); for (const auto & it : mimeTypeList) { if (it.startsWith (mimeTypeColon)) { - int number = it.mid (mimeTypeColon.length ()).toInt (); + int number = it.midRef (mimeTypeColon.length ()).toInt (); if (!colorDepthIsInvalid (number)) { return number; } } } return 32; } //--------------------------------------------------------------------- // public int kpDocumentSaveOptions::mimeTypeMaximumColorDepth () const { return mimeTypeMaximumColorDepth (mimeType ()); } //--------------------------------------------------------------------- // public static bool kpDocumentSaveOptions::mimeTypeHasConfigurableColorDepth (const QString &mimeType) { QStringList defaultMimeTypes; // SYNC: update mime info here - defaultMimeTypes << QLatin1String ("image/png"); - defaultMimeTypes << QLatin1String ("image/bmp"); - defaultMimeTypes << QLatin1String ("image/x-pcx"); + defaultMimeTypes << QStringLiteral ("image/png"); + defaultMimeTypes << QStringLiteral ("image/bmp"); + defaultMimeTypes << QStringLiteral ("image/x-pcx"); // TODO: Only 1, 24 not 8; Qt only sees 32 but "file" cmd realizes // it's either 1 or 24. - defaultMimeTypes << QLatin1String ("image/x-rgb"); + defaultMimeTypes << QStringLiteral ("image/x-rgb"); // TODO: Only 8 and 24 - no 1. - defaultMimeTypes << QLatin1String ("image/x-xpixmap"); + defaultMimeTypes << QStringLiteral ("image/x-xpixmap"); return mimeTypeSupportsProperty (mimeType, kpSettingMimeTypeHasConfigurableColorDepth, defaultMimeTypes); } //--------------------------------------------------------------------- // public bool kpDocumentSaveOptions::mimeTypeHasConfigurableColorDepth () const { return mimeTypeHasConfigurableColorDepth (mimeType ()); } //--------------------------------------------------------------------- // public static bool kpDocumentSaveOptions::mimeTypeHasConfigurableQuality (const QString &mimeType) { QStringList defaultMimeTypes; // SYNC: update mime info here - defaultMimeTypes << QLatin1String ("image/jp2"); - defaultMimeTypes << QLatin1String ("image/jpeg"); - defaultMimeTypes << QLatin1String ("image/x-webp"); + defaultMimeTypes << QStringLiteral ("image/jp2"); + defaultMimeTypes << QStringLiteral ("image/jpeg"); + defaultMimeTypes << QStringLiteral ("image/x-webp"); return mimeTypeSupportsProperty (mimeType, kpSettingMimeTypeHasConfigurableQuality, defaultMimeTypes); } //--------------------------------------------------------------------- // public bool kpDocumentSaveOptions::mimeTypeHasConfigurableQuality () const { return mimeTypeHasConfigurableQuality (mimeType ()); } //--------------------------------------------------------------------- // public int kpDocumentSaveOptions::isLossyForSaving (const QImage &image) const { auto ret = 0; if (mimeTypeMaximumColorDepth () < image.depth ()) { ret |= MimeTypeMaximumColorDepthLow; } if (mimeTypeHasConfigurableColorDepth () && !colorDepthIsInvalid () /*REFACTOR: guarantee it is valid*/ && ((colorDepth () < image.depth ()) || (colorDepth () < 32 && image.hasAlphaChannel()))) { ret |= ColorDepthLow; } if (mimeTypeHasConfigurableQuality () && !qualityIsInvalid ()) { ret |= Quality; } return ret; } //--------------------------------------------------------------------- diff --git a/document/kpDocumentSaveOptions.h b/document/kpDocumentSaveOptions.h index ef3d7999..a28e14aa 100644 --- a/document/kpDocumentSaveOptions.h +++ b/document/kpDocumentSaveOptions.h @@ -1,150 +1,150 @@ /* 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. */ #ifndef KP_DOCUMENT_SAVE_OPTIONS_H #define KP_DOCUMENT_SAVE_OPTIONS_H class QImage; class QString; class KConfigGroup; class kpDocumentSaveOptions { public: kpDocumentSaveOptions (); kpDocumentSaveOptions (const kpDocumentSaveOptions &rhs); - kpDocumentSaveOptions (QString mimeType, int colorDepth, bool dither, int quality); + kpDocumentSaveOptions (const QString &mimeType, int colorDepth, bool dither, int quality); virtual ~kpDocumentSaveOptions (); bool operator== (const kpDocumentSaveOptions &rhs) const; bool operator!= (const kpDocumentSaveOptions &rhs) const; kpDocumentSaveOptions &operator= (const kpDocumentSaveOptions &rhs); void printDebug (const QString &prefix) const; QString mimeType () const; void setMimeType (const QString &mimeType); static QString invalidMimeType (); static bool mimeTypeIsInvalid (const QString &mimeType); bool mimeTypeIsInvalid () const; int colorDepth () const; void setColorDepth (int depth); static int invalidColorDepth (); static bool colorDepthIsInvalid (int colorDepth); bool colorDepthIsInvalid () const; bool dither () const; void setDither (bool dither); static int initialDither (); int quality () const; void setQuality (int quality); static int invalidQuality (); static bool qualityIsInvalid (int quality); bool qualityIsInvalid () const; // (All assume that 's group has been set) // (None of them call KConfigBase::reparseConfig() nor KConfigBase::sync()) static QString defaultMimeType (const KConfigGroup &config); static void saveDefaultMimeType (KConfigGroup &config, const QString &mimeType); static int defaultColorDepth (const KConfigGroup &config); static void saveDefaultColorDepth (KConfigGroup &config, int colorDepth); static int defaultDither (const KConfigGroup &config); static void saveDefaultDither (KConfigGroup &config, bool dither); static int defaultQuality (const KConfigGroup &config); static void saveDefaultQuality (KConfigGroup &config, int quality); static kpDocumentSaveOptions defaultDocumentSaveOptions (const KConfigGroup &config); // (returns true if it encountered a difference (and saved it to )) static bool saveDefaultDifferences (KConfigGroup &config, const kpDocumentSaveOptions &oldDocInfo, const kpDocumentSaveOptions &newDocInfo); public: // (purely for informational purposes - not enforced by this class) static int mimeTypeMaximumColorDepth (const QString &mimeType); int mimeTypeMaximumColorDepth () const; static bool mimeTypeHasConfigurableColorDepth (const QString &mimeType); bool mimeTypeHasConfigurableColorDepth () const; static bool mimeTypeHasConfigurableQuality (const QString &mimeType); bool mimeTypeHasConfigurableQuality () const; // TODO: checking for mask loss due to format e.g. BMP enum LossyType { LossLess = 0, // mimeTypeMaximumColorDepth() < .depth() MimeTypeMaximumColorDepthLow = 1, // i.e. colorDepth() < .depth() || // colorDepth() < 32 && .mask() ColorDepthLow = 2, // i.e. mimeTypeHasConfigurableQuality() Quality = 4 }; // Returns whether saving with these options will result in // loss of information. Returned value is the bitwise OR of // LossType enum possiblities. int isLossyForSaving (const QImage &image) const; private: // There is no need to maintain binary compatibility at this stage. // The d-pointer is just so that you can experiment without recompiling // the kitchen sink. class kpDocumentSaveOptionsPrivate *d; }; #endif // KP_DOCUMENT_SAVE_OPTIONS_H diff --git a/imagelib/transforms/kpTransformAutoCrop.cpp b/imagelib/transforms/kpTransformAutoCrop.cpp index c0315043..0a91e986 100644 --- a/imagelib/transforms/kpTransformAutoCrop.cpp +++ b/imagelib/transforms/kpTransformAutoCrop.cpp @@ -1,756 +1,756 @@ /* 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; if (m_processedColorSimilarity == 0) return m_referenceColor; 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"); } return i18n ("Remove Internal Border"); } if (options & kpTransformAutoCropCommand::ShowAccel) return i18n ("Autocr&op"); 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 (); #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 */; #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 {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"); + QStringLiteral("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"); + QStringLiteral("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 (); #endif ::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 () : nullptr) << " avgCol=" << (leftBorder.exists () ? (int *) leftBorder.averageColor ().toQRgb () : nullptr); qCDebug(kpLogImagelib) << "\t\tright=" << rightBorder.rect () << " refCol=" << (rightBorder.exists () ? (int *) rightBorder.referenceColor ().toQRgb () : nullptr) << " avgCol=" << (rightBorder.exists () ? (int *) rightBorder.averageColor ().toQRgb () : nullptr); qCDebug(kpLogImagelib) << "\t\ttop=" << topBorder.rect () << " refCol=" << (topBorder.exists () ? (int *) topBorder.referenceColor ().toQRgb () : nullptr) << " avgCol=" << (topBorder.exists () ? (int *) topBorder.averageColor ().toQRgb () : nullptr); qCDebug(kpLogImagelib) << "\t\tbot=" << botBorder.rect () << " refCol=" << (botBorder.exists () ? (int *) botBorder.referenceColor ().toQRgb () : nullptr) << " avgCol=" << (botBorder.exists () ? (int *) botBorder.averageColor ().toQRgb () : nullptr); #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 (static_cast (doc->selection ()), leftBorder, rightBorder, topBorder, botBorder, mainWindow->commandEnvironment ())); return true; } diff --git a/kolourpaint.cpp b/kolourpaint.cpp index 0aaf6749..3843d2a4 100644 --- a/kolourpaint.cpp +++ b/kolourpaint.cpp @@ -1,124 +1,124 @@ /* Copyright (c) 2003-2007 Clarence Dang Copyright (c) 2015,2016 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 #include "kpVersion.h" #include "mainWindow/kpMainWindow.h" #include #include #include #include #include int main(int argc, char *argv []) { QApplication app(argc, argv); QApplication::setAttribute(Qt::AA_UseHighDpiPixmaps); KLocalizedString::setApplicationDomain("kolourpaint"); KAboutData aboutData ( - "kolourpaint", + QStringLiteral("kolourpaint"), i18n("KolourPaint"), QStringLiteral(KOLOURPAINT_VERSION_STRING), i18n("Paint Program by KDE"), KAboutLicense::Custom, QString(), // copyright statement - see license instead QString(), // other text - QLatin1String("http://www.kolourpaint.org/") // home page + QStringLiteral("http://www.kolourpaint.org/") // home page ); // (this is _not_ the same as KAboutLicense::BSD) aboutData.setLicenseText(i18n(kpLicenseText)); aboutData.setDesktopFileName(QStringLiteral("org.kde.kolourpaint")); // Please add yourself here if you feel you're missing. // SYNC: with AUTHORS - aboutData.addAuthor(i18n("Clarence Dang"), i18n("Project Founder"), QLatin1String("dang@kde.org")); + aboutData.addAuthor(i18n("Clarence Dang"), i18n("Project Founder"), QStringLiteral("dang@kde.org")); aboutData.addAuthor(i18n("Thurston Dang"), i18n("Chief Investigator"), - QLatin1String("thurston_dang@users.sourceforge.net")); + QStringLiteral("thurston_dang@users.sourceforge.net")); aboutData.addAuthor(i18n("Martin Koller"), i18n("Scanning Support, Alpha Support, Current Maintainer"), - QLatin1String("kollix@aon.at")); + QStringLiteral("kollix@aon.at")); - aboutData.addAuthor(i18n("Kristof Borrey"), i18n("Icons"), QLatin1String("borrey@kde.org")); - aboutData.addAuthor(i18n("Tasuku Suzuki"), i18n("InputMethod Support"), QLatin1String("stasuku@gmail.com")); - aboutData.addAuthor(i18n("Kazuki Ohta"), i18n("InputMethod Support"), QLatin1String("mover@hct.zaq.ne.jp")); - aboutData.addAuthor(i18n("Nuno Pinheiro"), i18n("Icons"), QLatin1String("nf.pinheiro@gmail.com")); - aboutData.addAuthor(i18n("Danny Allen"), i18n("Icons"), QLatin1String("dannya40uk@yahoo.co.uk")); - aboutData.addAuthor(i18n("Mike Gashler"), i18n("Image Effects"), QLatin1String("gashlerm@yahoo.com")); + aboutData.addAuthor(i18n("Kristof Borrey"), i18n("Icons"), QStringLiteral("borrey@kde.org")); + aboutData.addAuthor(i18n("Tasuku Suzuki"), i18n("InputMethod Support"), QStringLiteral("stasuku@gmail.com")); + aboutData.addAuthor(i18n("Kazuki Ohta"), i18n("InputMethod Support"), QStringLiteral("mover@hct.zaq.ne.jp")); + aboutData.addAuthor(i18n("Nuno Pinheiro"), i18n("Icons"), QStringLiteral("nf.pinheiro@gmail.com")); + aboutData.addAuthor(i18n("Danny Allen"), i18n("Icons"), QStringLiteral("dannya40uk@yahoo.co.uk")); + aboutData.addAuthor(i18n("Mike Gashler"), i18n("Image Effects"), QStringLiteral("gashlerm@yahoo.com")); - aboutData.addAuthor(i18n("Laurent Montel"), i18n("KDE 4 Porting"), QLatin1String("montel@kde.org")); - aboutData.addAuthor(i18n("Christoph Feck"), i18n("KF 5 Porting"), QLatin1String("cfeck@kde.org")); + aboutData.addAuthor(i18n("Laurent Montel"), i18n("KDE 4 Porting"), QStringLiteral("montel@kde.org")); + aboutData.addAuthor(i18n("Christoph Feck"), i18n("KF 5 Porting"), QStringLiteral("cfeck@kde.org")); aboutData.addCredit(i18n("Thanks to the many others who have helped to make this program possible.")); QCommandLineParser cmdLine; KAboutData::setApplicationData(aboutData); QApplication::setWindowIcon(QIcon::fromTheme(QStringLiteral("kolourpaint"), app.windowIcon())); cmdLine.addVersionOption(); cmdLine.addHelpOption(); - cmdLine.addPositionalArgument("files", i18n("Image files to open, optionally"), "[files...]"); + cmdLine.addPositionalArgument(QStringLiteral("files"), i18n("Image files to open, optionally"), QStringLiteral("[files...]")); aboutData.setupCommandLine(&cmdLine); cmdLine.process(app); aboutData.processCommandLine(&cmdLine); if ( app.isSessionRestored() ) { // Creates a kpMainWindow using the default constructor and then // calls kpMainWindow::readProperties(). RESTORE(kpMainWindow) } else { kpMainWindow *mainWindow; QStringList args = cmdLine.positionalArguments(); if ( args.count() >= 1 ) { for (int i = 0; i < args.count(); i++) { mainWindow = new kpMainWindow(QUrl::fromUserInput(args[i], QDir::currentPath(), QUrl::AssumeLocalFile)); mainWindow->show(); } } else { mainWindow = new kpMainWindow(); mainWindow->show(); } } return app.exec(); } diff --git a/kpViewScrollableContainer.cpp b/kpViewScrollableContainer.cpp index 6ec7698f..77a69148 100644 --- a/kpViewScrollableContainer.cpp +++ b/kpViewScrollableContainer.cpp @@ -1,1208 +1,1208 @@ /* 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; case kpGrip::Right: return Qt::SizeHorCursor; case kpGrip::BottomRight: return Qt::SizeFDiagCursor; } 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 {(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 (); #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 (); #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; #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; #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->setObjectName(QStringLiteral("Bottom Grip")); + m_rightGrip->setObjectName(QStringLiteral("Right Grip")); + m_bottomRightGrip->setObjectName(QStringLiteral("BottomRight Grip")); m_bottomGrip->hide (); connectGripSignals (m_bottomGrip); m_rightGrip->hide (); connectGripSignals (m_rightGrip); m_bottomRightGrip->hide (); connectGripSignals (m_bottomRightGrip); connect (horizontalScrollBar(), &QScrollBar::valueChanged, this, &kpViewScrollableContainer::slotContentsMoved); connect (verticalScrollBar(), &QScrollBar::valueChanged, this, &kpViewScrollableContainer::slotContentsMoved); connect (m_dragScrollTimer, &QTimer::timeout, this, [this]{slotDragScroll();}); m_overlay->hide(); } //--------------------------------------------------------------------- // protected void kpViewScrollableContainer::connectGripSignals (kpGrip *grip) { connect (grip, &kpGrip::beganDraw, this, &kpViewScrollableContainer::slotGripBeganDraw); connect (grip, &kpGrip::continuedDraw, this, &kpViewScrollableContainer::slotGripContinuedDraw); connect (grip, &kpGrip::cancelledDraw, this, &kpViewScrollableContainer::slotGripCancelledDraw); connect (grip, &kpGrip::endedDraw, this, &kpViewScrollableContainer::slotGripEndedDraw); connect (grip, &kpGrip::statusMessageChanged, this, &kpViewScrollableContainer::slotGripStatusMessageChanged); connect (grip, &kpGrip::releasedAllButtons, this, &kpViewScrollableContainer::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 {}; } if (!docResizingGrip ()) { return {}; } 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 {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); } 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); } return 1; } //--------------------------------------------------------------------- // protected QRect kpViewScrollableContainer::bottomResizeLineRect () const { if (m_resizeRoundedLastViewX < 0 || m_resizeRoundedLastViewY < 0) { return {}; } 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 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 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 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; #endif if (viewX >= 0 && viewY >= 0) { 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; #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; #endif } m_haveMovedFromOriginalDocSize = true; 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); #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())); #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, static_cast(&kpView::sizeChanged), this, &kpViewScrollableContainer::updateGrips); disconnect (m_view, &kpView::destroyed, this, &kpViewScrollableContainer::slotViewDestroyed); } //--------------------------------------------------------------------- // protected void kpViewScrollableContainer::connectViewSignals () { connect (m_view, static_cast(&kpView::sizeChanged), this, &kpViewScrollableContainer::updateGrips); connect (m_view, &kpView::destroyed, this, &kpViewScrollableContainer::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; } return false; } //--------------------------------------------------------------------- static int distanceFromRectToMultiplier (int dist) { if (dist < 0) { return 0; } if (dist < DragDistanceFromRectMaxFor1stMultiplier) { return 1; } if (dist < DragDistanceFromRectMaxFor2ndMultiplier) { return 2; } 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 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 {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.cpp b/layers/selections/text/kpTextSelection.cpp index 167967ee..e6157edf 100644 --- a/layers/selections/text/kpTextSelection.cpp +++ b/layers/selections/text/kpTextSelection.cpp @@ -1,347 +1,347 @@ /* 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 "kpLogCategories.h" #include #include // public kpTextSelection::kpTextSelection (const QRect &rect, const kpTextStyle &textStyle) : kpAbstractSelection (rect), d (new kpTextSelectionPrivate ()) { d->textStyle = textStyle; } // public kpTextSelection::kpTextSelection (const QRect &rect, const QList &textLines, const kpTextStyle &textStyle) : kpAbstractSelection (rect), d (new kpTextSelectionPrivate ()) { d->textLines = textLines; d->textStyle = textStyle; } // public kpTextSelection::kpTextSelection (const kpTextSelection &rhs) : kpAbstractSelection (), d (new kpTextSelectionPrivate ()) { *this = rhs; } // public kpTextSelection &kpTextSelection::operator= (const kpTextSelection &rhs) { kpAbstractSelection::operator= (rhs); d->textLines = rhs.d->textLines; d->textStyle = rhs.d->textStyle; d->preeditText = rhs.d->preeditText; return *this; } // public virtual [base kpAbstractSelection] kpTextSelection *kpTextSelection::clone () const { kpTextSelection *sel = new kpTextSelection (); *sel = *this; return sel; } // public kpTextSelection *kpTextSelection::resized (int newWidth, int newHeight) const { return new kpTextSelection (QRect (x (), y (), newWidth, newHeight), d->textLines, d->textStyle); } // public kpTextSelection::~kpTextSelection () { delete d; } // public virtual [kpAbstractSelection] int kpTextSelection::serialID () const { Q_ASSERT (!"Marshalling not supported"); return -1; } // public virtual [base kpAbstractSelection] bool kpTextSelection::readFromStream (QDataStream &stream) { (void) stream; Q_ASSERT (!"Marshalling not supported"); return false; } // public virtual [base kpAbstractSelection] void kpTextSelection::writeToStream (QDataStream &stream) const { (void) stream; Q_ASSERT (!"Marshalling not supported"); } // public virtual [kpAbstractSelection] QString kpTextSelection::name () const { return i18n ("Text"); } // public virtual [base kpAbstractSelection] kpCommandSize::SizeType kpTextSelection::size () const { return kpAbstractSelection::size () + kpCommandSize::StringSize (text ()); } // public virtual [kpAbstractSelection] bool kpTextSelection::isRectangular () const { return true; } // public static int kpTextSelection::MinimumWidthForTextStyle (const kpTextStyle &) { return (kpTextSelection::TextBorderSize () * 2 + 5); } // public static int kpTextSelection::MinimumHeightForTextStyle (const kpTextStyle &) { return (kpTextSelection::TextBorderSize () * 2 + 5); } // public static QSize kpTextSelection::MinimumSizeForTextStyle (const kpTextStyle &textStyle) { return {kpTextSelection::MinimumWidthForTextStyle (textStyle), kpTextSelection::MinimumHeightForTextStyle (textStyle)}; } // public virtual [kpAbstractSelection] int kpTextSelection::minimumWidth () const { return kpTextSelection::MinimumWidthForTextStyle (textStyle ()); } // public virtual [kpAbstractSelection] int kpTextSelection::minimumHeight () const { return kpTextSelection::MinimumHeightForTextStyle (textStyle ()); } // public static int kpTextSelection::PreferredMinimumWidthForTextStyle (const kpTextStyle &textStyle) { const int about15CharsWidth = textStyle.fontMetrics ().width ( - QLatin1String ("1234567890abcde")); + QStringLiteral ("1234567890abcde")); const int preferredMinWidth = qMax (150, kpTextSelection::TextBorderSize () * 2 + about15CharsWidth); return qMax (kpTextSelection::MinimumWidthForTextStyle (textStyle), qMin (250, preferredMinWidth)); } // public static int kpTextSelection::PreferredMinimumHeightForTextStyle (const kpTextStyle &textStyle) { const int preferredMinHeight = kpTextSelection::TextBorderSize () * 2 + textStyle.fontMetrics ().height (); return qMax (kpTextSelection::MinimumHeightForTextStyle (textStyle), qMin (150, preferredMinHeight)); } // public static QSize kpTextSelection::PreferredMinimumSizeForTextStyle (const kpTextStyle &textStyle) { return {kpTextSelection::PreferredMinimumWidthForTextStyle (textStyle), kpTextSelection::PreferredMinimumHeightForTextStyle (textStyle)}; } // public static int kpTextSelection::TextBorderSize () { return 1; } // public QRect kpTextSelection::textAreaRect () const { return {x () + kpTextSelection::TextBorderSize (), y () + kpTextSelection::TextBorderSize (), width () - kpTextSelection::TextBorderSize () * 2, height () - kpTextSelection::TextBorderSize () * 2}; } // public virtual [kpAbstractSelection] QPolygon kpTextSelection::calculatePoints () const { return kpAbstractSelection::CalculatePointsForRectangle (boundingRect ()); } // public virtual [kpAbstractSelection] bool kpTextSelection::contains (const QPoint &point) const { return boundingRect ().contains (point); } // public bool kpTextSelection::pointIsInTextBorderArea (const QPoint &point) const { return (boundingRect ().contains (point) && !pointIsInTextArea (point)); } // public bool kpTextSelection::pointIsInTextArea (const QPoint &point) const { return textAreaRect ().contains (point); } // public virtual [kpAbstractSelection] bool kpTextSelection::hasContent () const { return !d->textLines.isEmpty (); } // public virtual [kpAbstractSelection] void kpTextSelection::deleteContent () { if (!hasContent ()) { return; } setTextLines (QList ()); } // public QList kpTextSelection::textLines () const { return d->textLines; } // public void kpTextSelection::setTextLines (const QList &textLines_) { d->textLines = textLines_; emit changed (boundingRect ()); } // public static QString kpTextSelection::TextForTextLines (const QList &textLines) { if (textLines.isEmpty ()) { return {}; } QString bigString = textLines [0]; for (QList ::const_iterator it = textLines.begin () + 1; it != textLines.end (); ++it) { bigString += QLatin1String ("\n"); bigString += (*it); } return bigString; } // public QString kpTextSelection::text () const { return kpTextSelection::TextForTextLines (d->textLines); } // public kpTextStyle kpTextSelection::textStyle () const { return d->textStyle; } // public void kpTextSelection::setTextStyle (const kpTextStyle &textStyle) { d->textStyle = textStyle; emit changed (boundingRect ()); } kpPreeditText kpTextSelection::preeditText () const { return d->preeditText; } void kpTextSelection::setPreeditText (const kpPreeditText &preeditText) { d->preeditText = preeditText; emit changed (boundingRect ()); } diff --git a/lgpl/generic/kpColorCollection.cpp b/lgpl/generic/kpColorCollection.cpp index 9107f385..2aff094d 100644 --- a/lgpl/generic/kpColorCollection.cpp +++ b/lgpl/generic/kpColorCollection.cpp @@ -1,535 +1,535 @@ // REFACT0R: Remote open/save file logic is duplicated in kpDocument. // HITODO: Test when remote file support in KDE 4 stabilizes /* This file is part of the KDE libraries Copyright (C) 1999 Waldo Bastian (bastian@kde.org) Copyright (C) 2007 Clarence Dang (dang@kde.org) This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as published by the Free Software Foundation; either version 2 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 Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with this library; see the file COPYING.LIB. If not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ //----------------------------------------------------------------------------- // KDE color collection #define DEBUG_KP_COLOR_COLLECTION 0 #include "kpColorCollection.h" #include "kpUrlFormatter.h" #include // kdelibs4support #include #include #include "kpLogCategories.h" #include #include #include #include #include #include #include #include struct ColorNode { ColorNode(const QColor &c, const QString &n) : color(c), name(n) {} QColor color; QString name; }; //--------------------------------------------------------------------- //BEGIN kpColorCollectionPrivate class kpColorCollectionPrivate { public: kpColorCollectionPrivate(); kpColorCollectionPrivate(const kpColorCollectionPrivate&); QList colorList; QString name; QString desc; kpColorCollection::Editable editable; }; kpColorCollectionPrivate::kpColorCollectionPrivate() : editable(kpColorCollection::Yes) { } kpColorCollectionPrivate::kpColorCollectionPrivate(const kpColorCollectionPrivate& p) : colorList(p.colorList), name(p.name), desc(p.desc), editable(p.editable) { } //END kpColorCollectionPrivate //--------------------------------------------------------------------- QStringList kpColorCollection::installedCollections() { QStringList paletteList; - QStringList paths = QStandardPaths::locateAll(QStandardPaths::GenericConfigLocation, "colors", + QStringList paths = QStandardPaths::locateAll(QStandardPaths::GenericConfigLocation, QStringLiteral("colors"), QStandardPaths::LocateDirectory); for (const auto &path : paths) { paletteList.append(QDir(path).entryList(QStringList(), QDir::Files)); } return paletteList; } kpColorCollection::kpColorCollection() { d = new kpColorCollectionPrivate(); } kpColorCollection::kpColorCollection(const kpColorCollection &p) { d = new kpColorCollectionPrivate(*p.d); } kpColorCollection::~kpColorCollection() { // Need auto-save? delete d; } static void CouldNotOpenDialog (const QUrl &url, QWidget *parent) { KMessageBox::sorry (parent, i18n ("Could not open color palette \"%1\".", kpUrlFormatter::PrettyFilename (url))); } // TODO: Set d->editable? bool kpColorCollection::open(const QUrl &url, QWidget *parent) { QString tempPaletteFilePath; if (url.isEmpty () || !KIO::NetAccess::download (url, tempPaletteFilePath, parent)) { #if DEBUG_KP_COLOR_COLLECTION qCDebug(kpLogMisc) << "\tcould not download"; #endif ::CouldNotOpenDialog (url, parent); return false; } // sync: remember to "KIO::NetAccess::removeTempFile (tempPaletteFilePath)" in all exit paths QFile paletteFile(tempPaletteFilePath); if (!paletteFile.exists() || !paletteFile.open(QIODevice::ReadOnly)) { #if DEBUG_KP_COLOR_COLLECTION qCDebug(kpLogMisc) << "\tcould not open qfile"; #endif KIO::NetAccess::removeTempFile (tempPaletteFilePath); ::CouldNotOpenDialog (url, parent); return false; } // Read first line // Expected "GIMP Palette" QString line = QString::fromLocal8Bit(paletteFile.readLine()); - if (line.indexOf(" Palette") == -1) + if (line.indexOf(QLatin1String(" Palette")) == -1) { KIO::NetAccess::removeTempFile (tempPaletteFilePath); KMessageBox::sorry (parent, i18n ("Could not open color palette \"%1\" - unsupported format.\n" "The file may be corrupt.", kpUrlFormatter::PrettyFilename (url))); return false; } QList newColorList; QString newDesc; while( !paletteFile.atEnd() ) { line = QString::fromLocal8Bit(paletteFile.readLine()); if (line[0] == '#') { // This is a comment line line = line.mid(1); // Strip '#' line = line.trimmed(); // Strip remaining white space.. if (!line.isEmpty()) { newDesc += line+'\n'; // Add comment to description } } else { // This is a color line, hopefully line = line.trimmed(); if (line.isEmpty()) continue; int r, g, b; int pos = 0; if (sscanf(line.toLatin1(), "%d %d %d%n", &r, &g, &b, &pos) >= 3) { r = qBound(0, r, 255); g = qBound(0, g, 255); b = qBound(0, b, 255); QString name = line.mid(pos).trimmed(); newColorList.append(ColorNode(QColor(r, g, b), name)); } } } d->colorList = newColorList; d->name.clear (); d->desc = newDesc; KIO::NetAccess::removeTempFile (tempPaletteFilePath); return true; } static void CouldNotOpenKDEDialog (const QString &name, QWidget *parent) { KMessageBox::sorry (parent, i18n ("Could not open KDE color palette \"%1\".", name)); } bool kpColorCollection::openKDE(const QString &name, QWidget *parent) { #if DEBUG_KP_COLOR_COLLECTION qCDebug(kpLogMisc) << "name=" << name; #endif if (name.isEmpty()) { #if DEBUG_KP_COLOR_COLLECTION qCDebug(kpLogMisc) << "name.isEmpty"; #endif ::CouldNotOpenKDEDialog (name, parent); return false; } QString filename = QStandardPaths::locate(QStandardPaths::GenericConfigLocation, "colors/" + name); if (filename.isEmpty()) { #if DEBUG_KP_COLOR_COLLECTION qCDebug(kpLogMisc) << "could not find file"; #endif ::CouldNotOpenKDEDialog (name, parent); return false; } // (this will pop up an error dialog on failure) if (!open (QUrl::fromLocalFile (filename), parent)) { #if DEBUG_KP_COLOR_COLLECTION qCDebug(kpLogMisc) << "could not open"; #endif return false; } d->name = name; #if DEBUG_KP_COLOR_COLLECTION qCDebug(kpLogMisc) << "opened"; #endif return true; } static void CouldNotSaveDialog (const QUrl &url, QWidget *parent) { // TODO: use file.errorString() KMessageBox::error (parent, i18n ("Could not save color palette as \"%1\".", kpUrlFormatter::PrettyFilename (url))); } static void SaveToFile (kpColorCollectionPrivate *d, QIODevice *device) { // HITODO: QTextStream can fail but does not report errors. // Bug in KColorCollection too. QTextStream str (device); QString description = d->desc.trimmed(); - description = '#'+description.split( '\n', QString::KeepEmptyParts).join("\n#"); + description = '#'+description.split( '\n', QString::KeepEmptyParts).join(QStringLiteral("\n#")); str << "KDE RGB Palette\n"; str << description << "\n"; for (const auto &node : d->colorList) { // Added for KolourPaint. if(!node.color.isValid ()) continue; int r,g,b; node.color.getRgb(&r, &g, &b); str << r << " " << g << " " << b << " " << node.name << "\n"; } str.flush(); } bool kpColorCollection::saveAs(const QUrl &url, bool showOverwritePrompt, QWidget *parent) const { if (showOverwritePrompt && KIO::NetAccess::exists (url, KIO::NetAccess::DestinationSide/*write*/, parent)) { int result = KMessageBox::warningContinueCancel (parent, i18n ("A color palette called \"%1\" already exists.\n" "Do you want to overwrite it?", kpUrlFormatter::PrettyFilename (url)), QString (), KStandardGuiItem::overwrite ()); if (result != KMessageBox::Continue) return false; } if (url.isLocalFile ()) { const QString filename = url.toLocalFile (); // sync: All failure exit paths _must_ call QSaveFile::cancelWriting() or // else, the QSaveFile destructor will overwrite the file, // , despite the failure. QSaveFile atomicFileWriter (filename); { if (!atomicFileWriter.open (QIODevice::WriteOnly)) { // We probably don't need this as has not been // opened. atomicFileWriter.cancelWriting (); #if DEBUG_KP_COLOR_COLLECTION qCDebug(kpLogMisc) << "\treturning false because could not open QSaveFile" << " error=" << atomicFileWriter.error (); #endif ::CouldNotSaveDialog (url, parent); return false; } // Write to local temporary file. ::SaveToFile (d, &atomicFileWriter); // Atomically overwrite local file with the temporary file // we saved to. if (!atomicFileWriter.commit ()) { atomicFileWriter.cancelWriting (); #if DEBUG_KP_COLOR_COLLECTION qCDebug(kpLogMisc) << "\tcould not close QSaveFile"; #endif ::CouldNotSaveDialog (url, parent); return false; } } // sync QSaveFile.cancelWriting() } // Remote file? else { // Create temporary file that is deleted when the variable goes // out of scope. QTemporaryFile tempFile; if (!tempFile.open ()) { #if DEBUG_KP_COLOR_COLLECTION qCDebug(kpLogMisc) << "\treturning false because could not open tempFile"; #endif ::CouldNotSaveDialog (url, parent); return false; } // Write to local temporary file. ::SaveToFile (d, &tempFile); // Collect name of temporary file now, as QTemporaryFile::fileName() // stops working after close() is called. const QString tempFileName = tempFile.fileName (); #if DEBUG_KP_COLOR_COLLECTION qCDebug(kpLogMisc) << "\ttempFileName='" << tempFileName << "'"; #endif Q_ASSERT (!tempFileName.isEmpty ()); tempFile.close (); if (tempFile.error () != QFile::NoError) { #if DEBUG_KP_COLOR_COLLECTION qCDebug(kpLogMisc) << "\treturning false because could not close"; #endif ::CouldNotSaveDialog (url, parent); return false; } // Copy local temporary file to overwrite remote. // TODO: No one seems to know how to do this atomically // [http://lists.kde.org/?l=kde-core-devel&m=117845162728484&w=2]. // At least, fish:// (ssh) is definitely not atomic. if (!KIO::NetAccess::upload (tempFileName, url, parent)) { #if DEBUG_KP_COLOR_COLLECTION qCDebug(kpLogMisc) << "\treturning false because could not upload"; #endif ::CouldNotSaveDialog (url, parent); return false; } } d->name.clear (); return true; } bool kpColorCollection::saveKDE(QWidget *parent) const { const QString name = d->name; QString filename = QStandardPaths::writableLocation(QStandardPaths::GenericConfigLocation) + "colors/" + name; const bool ret = saveAs (QUrl::fromLocalFile (filename), false/*no overwite prompt*/, parent); // (d->name is wiped by saveAs()). d->name = name; return ret; } QString kpColorCollection::description() const { return d->desc; } void kpColorCollection::setDescription(const QString &desc) { d->desc = desc; } QString kpColorCollection::name() const { return d->name; } void kpColorCollection::setName(const QString &name) { d->name = name; } kpColorCollection::Editable kpColorCollection::editable() const { return d->editable; } void kpColorCollection::setEditable(Editable editable) { d->editable = editable; } int kpColorCollection::count() const { return (int) d->colorList.count(); } void kpColorCollection::resize(int newCount) { if (newCount == count()) return; else if (newCount < count()) { d->colorList.erase(d->colorList.begin() + newCount, d->colorList.end()); } else if (newCount > count()) { while(newCount > count()) { const int ret = addColor(QColor(), QString()/*color name*/); Q_ASSERT(ret == count() - 1); } } } kpColorCollection& kpColorCollection::operator=( const kpColorCollection &p) { if (&p == this) return *this; d->colorList = p.d->colorList; d->name = p.d->name; d->desc = p.d->desc; d->editable = p.d->editable; return *this; } QColor kpColorCollection::color(int index) const { if ((index < 0) || (index >= count())) return QColor(); return d->colorList[index].color; } int kpColorCollection::findColor(const QColor &color) const { for (int i = 0; i < d->colorList.size(); ++i) { if (d->colorList[i].color == color) return i; } return -1; } QString kpColorCollection::name(int index) const { if ((index < 0) || (index >= count())) return QString(); return d->colorList[index].name; } QString kpColorCollection::name(const QColor &color) const { return name(findColor(color)); } int kpColorCollection::addColor(const QColor &newColor, const QString &newColorName) { d->colorList.append(ColorNode(newColor, newColorName)); return count() - 1; } int kpColorCollection::changeColor(int index, const QColor &newColor, const QString &newColorName) { if ((index < 0) || (index >= count())) return -1; ColorNode& node = d->colorList[index]; node.color = newColor; node.name = newColorName; return index; } int kpColorCollection::changeColor(const QColor &oldColor, const QColor &newColor, const QString &newColorName) { return changeColor( findColor(oldColor), newColor, newColorName); } diff --git a/mainWindow/kpMainWindow.cpp b/mainWindow/kpMainWindow.cpp index 8d47e62e..21946390 100644 --- a/mainWindow/kpMainWindow.cpp +++ b/mainWindow/kpMainWindow.cpp @@ -1,924 +1,924 @@ /* 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 "kpMainWindow.h" #include "kpMainWindowPrivate.h" #include "layers/selections/image/kpAbstractImageSelection.h" #include "environments/commands/kpCommandEnvironment.h" #include "environments/tools/kpToolEnvironment.h" #include "widgets/kpColorCells.h" #include "widgets/toolbars/kpColorToolBar.h" #include "commands/kpCommandHistory.h" #include "kpDefs.h" #include "document/kpDocument.h" #include "environments/document/kpDocumentEnvironment.h" #include "layers/selections/kpSelectionDrag.h" #include "kpThumbnail.h" #include "tools/kpTool.h" #include "widgets/toolbars/kpToolToolBar.h" #include "views/manager/kpViewManager.h" #include "kpViewScrollableContainer.h" #include "generic/kpWidgetMapper.h" #include "views/kpZoomedThumbnailView.h" #include "views/kpZoomedView.h" #include #include #include #include #include #include #include "kpLogCategories.h" //--------------------------------------------------------------------- kpMainWindow::kpMainWindow () : KXmlGuiWindow (nullptr/*parent*/) { init (); open (QUrl (), true/*create an empty doc*/); d->isFullyConstructed = true; } //--------------------------------------------------------------------- kpMainWindow::kpMainWindow (const QUrl &url) : KXmlGuiWindow (nullptr/*parent*/) { init (); open (url, true/*create an empty doc with the same url if url !exist*/); d->isFullyConstructed = true; } //--------------------------------------------------------------------- kpMainWindow::kpMainWindow (kpDocument *newDoc) : KXmlGuiWindow (nullptr/*parent*/) { init (); setDocument (newDoc); d->isFullyConstructed = true; } //--------------------------------------------------------------------- // TODO: Move into appropriate kpMainWindow_*.cpp or another class // private void kpMainWindow::readGeneralSettings () { #if DEBUG_KP_MAIN_WINDOW qCDebug(kpLogMainWindow) << "\tkpMainWindow(" << objectName () << ")::readGeneralSettings()"; #endif KConfigGroup cfg (KSharedConfig::openConfig (), kpSettingsGroupGeneral); d->configFirstTime = cfg.readEntry (kpSettingFirstTime, true); d->configShowGrid = cfg.readEntry (kpSettingShowGrid, false); d->configShowPath = cfg.readEntry (kpSettingShowPath, false); d->moreEffectsDialogLastEffect = cfg.readEntry (kpSettingMoreEffectsLastEffect, 0); kpToolEnvironment::drawAntiAliased = cfg.readEntry(kpSettingDrawAntiAliased, true); if (cfg.hasKey (kpSettingOpenImagesInSameWindow)) { d->configOpenImagesInSameWindow = cfg.readEntry (kpSettingOpenImagesInSameWindow, false); } else { d->configOpenImagesInSameWindow = false; #if DEBUG_KP_MAIN_WINDOW qCDebug(kpLogMainWindow) << "\tconfigOpenImagesInSameWindow: first time" << " - writing default: " << d->configOpenImagesInSameWindow; #endif // TODO: More hidden options have to write themselves out on startup, // not on use, to be discoverable (e.g. printing centered on page). cfg.writeEntry (kpSettingOpenImagesInSameWindow, d->configOpenImagesInSameWindow); cfg.sync (); } d->configPrintImageCenteredOnPage = cfg.readEntry (kpSettingPrintImageCenteredOnPage, true); #if DEBUG_KP_MAIN_WINDOW qCDebug(kpLogMainWindow) << "\t\tGeneral Settings: firstTime=" << d->configFirstTime << " showGrid=" << d->configShowGrid << " showPath=" << d->configShowPath << " moreEffectsDialogLastEffect=" << d->moreEffectsDialogLastEffect << " openImagesInSameWindow=" << d->configOpenImagesInSameWindow << " printImageCenteredOnPage=" << d->configPrintImageCenteredOnPage; #endif } //--------------------------------------------------------------------- // private void kpMainWindow::readThumbnailSettings () { #if DEBUG_KP_MAIN_WINDOW qCDebug(kpLogMainWindow) << "\tkpMainWindow(" << objectName () << ")::readThumbnailSettings()"; #endif KConfigGroup cfg (KSharedConfig::openConfig (), kpSettingsGroupThumbnail); d->configThumbnailShown = cfg.readEntry (kpSettingThumbnailShown, false); d->configThumbnailGeometry = cfg.readEntry (kpSettingThumbnailGeometry, QRect ()); d->configZoomedThumbnail = cfg.readEntry (kpSettingThumbnailZoomed, true); d->configThumbnailShowRectangle = cfg.readEntry (kpSettingThumbnailShowRectangle, true); #if DEBUG_KP_MAIN_WINDOW qCDebug(kpLogMainWindow) << "\t\tThumbnail Settings: shown=" << d->configThumbnailShown << " geometry=" << d->configThumbnailGeometry << " zoomed=" << d->configZoomedThumbnail << " showRectangle=" << d->configThumbnailShowRectangle; #endif } //--------------------------------------------------------------------- void kpMainWindow::finalizeGUI(KXMLGUIClient *client) { if ( client == this ) { - const QList menuToHide = findChildren("toolToolBarHiddenMenu"); + const QList menuToHide = findChildren(QStringLiteral("toolToolBarHiddenMenu")); // should only contain one but... for (auto *menu : menuToHide) { menu->menuAction()->setVisible(false); } } } //--------------------------------------------------------------------- // private void kpMainWindow::init () { #if DEBUG_KP_MAIN_WINDOW qCDebug(kpLogMainWindow) << "kpMainWindow(" << objectName () << ")::init()"; QTime totalTime; totalTime.start (); #endif d = new kpMainWindowPrivate; // // set mainwindow properties // setMinimumSize (320, 260); setAcceptDrops (true); // // read config // // KConfig::readEntry() does not actually reread from disk, hence doesn't // realize what other processes have done e.g. Settings / Show Path KSharedConfig::openConfig ()->reparseConfiguration (); readGeneralSettings (); readThumbnailSettings (); // // create GUI // setupActions (); createStatusBar (); createGUI (); createColorBox (); createToolBox (); // Let the Tool Box take all the vertical space, since it can be quite // tall with all its tool option widgets. This also avoids occasional // bugs like the Tool Box overlapping the Color Tool Bar. setCorner(Qt::BottomLeftCorner, Qt::LeftDockWidgetArea); setCorner(Qt::BottomRightCorner, Qt::RightDockWidgetArea); // no tabbed docks; does not make sense with only 2 dock widgets setDockOptions(QMainWindow::AnimatedDocks | QMainWindow::AllowNestedDocks); addDockWidget(Qt::BottomDockWidgetArea, d->colorToolBar, Qt::Horizontal); d->scrollView = new kpViewScrollableContainer (this); - d->scrollView->setObjectName ( QLatin1String("scrollView" )); + d->scrollView->setObjectName ( QStringLiteral("scrollView" )); connect (d->scrollView, &kpViewScrollableContainer::beganDocResize, this, &kpMainWindow::slotBeganDocResize); connect (d->scrollView, &kpViewScrollableContainer::continuedDocResize, this, &kpMainWindow::slotContinuedDocResize); connect (d->scrollView, &kpViewScrollableContainer::cancelledDocResize, this, &kpMainWindow::slotCancelledDocResize); connect (d->scrollView, &kpViewScrollableContainer::endedDocResize, this, &kpMainWindow::slotEndedDocResize); connect (d->scrollView, &kpViewScrollableContainer::statusMessageChanged, this, &kpMainWindow::slotDocResizeMessageChanged); connect (d->scrollView, &kpViewScrollableContainer::contentsMoved, this, &kpMainWindow::slotScrollViewAfterScroll); setCentralWidget (d->scrollView); // // set initial pos/size of GUI // setAutoSaveSettings (); // our non-XMLGUI tools-toolbar will get initially the toolButtonStyle as // all other toolbars, but we want to show only icons for the tools by default // (have to do this _after_ setAutoSaveSettings as that applies the default settings) if (d->configFirstTime) { d->toolToolBar->setToolButtonStyle(Qt::ToolButtonIconOnly); KConfigGroup cfg(KSharedConfig::openConfig(), kpSettingsGroupGeneral); cfg.writeEntry(kpSettingFirstTime, d->configFirstTime = false); cfg.sync(); } #if DEBUG_KP_MAIN_WINDOW qCDebug(kpLogMainWindow) << "\tall done in " << totalTime.elapsed () << "msec"; #endif } //--------------------------------------------------------------------- // private virtual [base KMainWindow] void kpMainWindow::readProperties (const KConfigGroup &configGroup) { #if DEBUG_KP_MAIN_WINDOW qCDebug(kpLogMainWindow) << "kpMainWindow<" << this << ">::readProperties()"; #endif // No document at all? if (!configGroup.hasKey (kpSessionSettingDocumentUrl)) { #if DEBUG_KP_MAIN_WINDOW qCDebug(kpLogMainWindow) << "\tno url - no document"; #endif setDocument (nullptr); } // Have a document. else { const QUrl url = QUrl (configGroup.readEntry (kpSessionSettingDocumentUrl, QString ())); #if DEBUG_KP_MAIN_WINDOW qCDebug(kpLogMainWindow) << "\turl=" << url; #endif const QSize notFromURLDocSize = configGroup.readEntry (kpSessionSettingNotFromUrlDocumentSize, QSize ()); // Is from URL? if (notFromURLDocSize.isEmpty ()) { // If this fails, the empty document that kpMainWindow::kpMainWindow() // created is left untouched. openInternal (url, defaultDocSize (), false/*show error message if url !exist*/); } // Not from URL? else { #if DEBUG_KP_MAIN_WINDOW qCDebug(kpLogMainWindow) << "\tnot from url; doc size=" << notFromURLDocSize; #endif // Either we have an empty URL or we have a "kolourpaint doesnotexist.png" // URL. Regarding the latter case, if a file now actually exists at that // URL, we do open it - ignoring notFromURLDocSize - to avoid putting // the user in a situation where he might accidentally overwrite an // existing file. openInternal (url, notFromURLDocSize, true/*create an empty doc with the same url if url !exist*/); } } } //--------------------------------------------------------------------- // private virtual [base KMainWindow] // WARNING: KMainWindow API Doc says "No user interaction is allowed // in this function!" void kpMainWindow::saveProperties (KConfigGroup &configGroup) { #if DEBUG_KP_MAIN_WINDOW qCDebug(kpLogMainWindow) << "kpMainWindow<" << this << ">::saveProperties()"; #endif // No document at all? if (!d->document) { #if DEBUG_KP_MAIN_WINDOW qCDebug(kpLogMainWindow) << "\tno url - no document"; #endif } // Have a document. else { // Save URL in all cases: // // a) d->document->isFromURL() // b) !d->document->isFromURL() [save size in this case] // i) No URL // ii) URL (from "kolourpaint doesnotexist.png") const QUrl url = d->document->url (); #if DEBUG_KP_MAIN_WINDOW qCDebug(kpLogMainWindow) << "\turl=" << url; #endif configGroup.writeEntry (kpSessionSettingDocumentUrl, url.url ()); // Not from URL e.g. "kolourpaint doesnotexist.png"? // // Note that "kolourpaint doesexist.png" is considered to be from // a URL even if it was deleted in the background (hence the // "false" arg to isFromURL()). This is because the user expects // it to be from a URL, so when we session restore, we pop up a // "cannot find file" dialog, instead of silently creating a new, // blank document. if (!d->document->isFromURL (false/*don't bother checking exists*/)) { // If we don't have a URL either: // // a) it was not modified - so we can use either width() or // constructorWidth() (they'll be equal). // b) the changes were discarded so we use the initial width, // constructorWidth(). // // Similarly for height() and constructorHeight(). const QSize docSize (d->document->constructorWidth (), d->document->constructorHeight ()); #if DEBUG_KP_MAIN_WINDOW qCDebug(kpLogMainWindow) << "\tnot from url; doc size=" << docSize; #endif configGroup.writeEntry (kpSessionSettingNotFromUrlDocumentSize, docSize); } } } //--------------------------------------------------------------------- kpMainWindow::~kpMainWindow () { d->isFullyConstructed = false; // Get the kpTool to finish up. This makes sure that the kpTool destructor // will not need to access any other class (that might be deleted before // the destructor is called by the QObject child-deletion mechanism). if (tool ()) { tool ()->endInternal (); } // Delete document & views. // Note: This will disconnects signals from the current kpTool, so kpTool // must not be destructed yet. setDocument (nullptr); delete d->commandHistory; d->commandHistory = nullptr; delete d->scrollView; d->scrollView = nullptr; delete d; d = nullptr; } //--------------------------------------------------------------------- // public kpDocument *kpMainWindow::document () const { return d->document; } //--------------------------------------------------------------------- // public kpDocumentEnvironment *kpMainWindow::documentEnvironment () { if (!d->documentEnvironment) { d->documentEnvironment = new kpDocumentEnvironment (this); } return d->documentEnvironment; } //--------------------------------------------------------------------- // public kpViewManager *kpMainWindow::viewManager () const { return d->viewManager; } //--------------------------------------------------------------------- // public kpColorToolBar *kpMainWindow::colorToolBar () const { return d->colorToolBar; } //--------------------------------------------------------------------- // public kpColorCells *kpMainWindow::colorCells () const { return d->colorToolBar ? d->colorToolBar->colorCells () : nullptr; } //--------------------------------------------------------------------- // public kpToolToolBar *kpMainWindow::toolToolBar () const { return d->toolToolBar; } //--------------------------------------------------------------------- // public kpCommandHistory *kpMainWindow::commandHistory () const { return d->commandHistory; } //--------------------------------------------------------------------- kpCommandEnvironment *kpMainWindow::commandEnvironment () { if (!d->commandEnvironment) { d->commandEnvironment = new kpCommandEnvironment (this); } return d->commandEnvironment; } //--------------------------------------------------------------------- // private void kpMainWindow::setupActions () { setupFileMenuActions (); setupEditMenuActions (); setupViewMenuActions (); setupImageMenuActions (); setupColorsMenuActions (); setupSettingsMenuActions (); setupTextToolBarActions (); setupToolActions (); } //--------------------------------------------------------------------- // private void kpMainWindow::enableDocumentActions (bool enable) { enableFileMenuDocumentActions (enable); enableEditMenuDocumentActions (enable); enableViewMenuDocumentActions (enable); enableImageMenuDocumentActions (enable); enableColorsMenuDocumentActions (enable); enableSettingsMenuDocumentActions (enable); } //--------------------------------------------------------------------- // private void kpMainWindow::setDocument (kpDocument *newDoc) { //qCDebug(kpLogMainWindow) << newDoc; // is it a close operation? if (!newDoc) { #if DEBUG_KP_MAIN_WINDOW qCDebug(kpLogMainWindow) << "\tdisabling actions"; #endif // sync with the bit marked "sync" below // TODO: Never disable the Color Box because the user should be // able to manipulate the colors, even without a currently // open document. // // We just have to make sure that signals from the Color // Box aren't fired and received unexpectedly when there's // no document. Q_ASSERT (d->colorToolBar); d->colorToolBar->setEnabled (false); enableTextToolBarActions (false); } // Always disable the tools. // If we decide to open a new document/mainView we want // kpTool::begin() to be called again e.g. in case it sets the cursor. // kpViewManager won't do this because we nuke it to avoid stale state. enableToolsDocumentActions (false); if (!newDoc) { enableDocumentActions (false); } delete d->mainView; d->mainView = nullptr; slotDestroyThumbnail (); // viewManager will die and so will the selection d->actionCopy->setEnabled (false); d->actionCut->setEnabled (false); d->actionDelete->setEnabled (false); d->actionDeselect->setEnabled (false); d->actionCopyToFile->setEnabled (false); delete d->viewManager; d->viewManager = nullptr; #if DEBUG_KP_MAIN_WINDOW qCDebug(kpLogMainWindow) << "\tdestroying document"; qCDebug(kpLogMainWindow) << "\t\td->document=" << d->document; #endif // destroy current document delete d->document; d->document = newDoc; if (!d->lastCopyToURL.isEmpty ()) { // remove file name from path QString path = d->lastCopyToURL.path (); path = path.left (path.lastIndexOf (QLatin1Char ('/')) + 1); d->lastCopyToURL.setPath (path); } d->copyToFirstTime = true; if (!d->lastExportURL.isEmpty ()) { QString path = d->lastExportURL.path (); path = path.left (path.lastIndexOf (QLatin1Char ('/')) + 1); d->lastExportURL.setPath (path); } d->exportFirstTime = true; // not a close operation? if (d->document) { #if DEBUG_KP_MAIN_WINDOW qCDebug(kpLogMainWindow) << "\treparenting doc that may have been created into a" << " different mainWindiow"; #endif d->document->setEnviron (documentEnvironment ()); d->viewManager = new kpViewManager (this); d->mainView = new kpZoomedView (d->document, d->toolToolBar, d->viewManager, nullptr/*buddyView*/, d->scrollView, d->scrollView->viewport ()); - d->mainView->setObjectName ( QLatin1String("mainView" )); + d->mainView->setObjectName ( QStringLiteral("mainView" )); d->viewManager->registerView (d->mainView); d->scrollView->setView (d->mainView); d->mainView->show (); #if DEBUG_KP_MAIN_WINDOW qCDebug(kpLogMainWindow) << "\thooking up document signals"; #endif // Copy/Cut/Deselect/Delete connect (d->document, &kpDocument::selectionEnabled, d->actionCut, &QAction::setEnabled); connect (d->document, &kpDocument::selectionEnabled, d->actionCopy, &QAction::setEnabled); connect (d->document, &kpDocument::selectionEnabled, d->actionDelete, &QAction::setEnabled); connect (d->document, &kpDocument::selectionEnabled, d->actionDeselect, &QAction::setEnabled); connect (d->document, &kpDocument::selectionEnabled, d->actionCopyToFile, &QAction::setEnabled); // this code won't actually enable any actions at this stage // (fresh document) but better safe than sorry d->actionCopy->setEnabled (d->document->selection ()); d->actionCut->setEnabled (d->document->selection ()); d->actionDeselect->setEnabled (d->document->selection ()); d->actionDelete->setEnabled (d->document->selection ()); d->actionCopyToFile->setEnabled (d->document->selection ()); connect (d->document, &kpDocument::selectionEnabled, this, &kpMainWindow::slotImageMenuUpdateDueToSelection); connect (d->document, &kpDocument::selectionIsTextChanged, this, &kpMainWindow::slotImageMenuUpdateDueToSelection); // Status bar connect (d->document, &kpDocument::documentOpened, this, &kpMainWindow::recalculateStatusBar); connect (d->document, SIGNAL (sizeChanged(QSize)), this, SLOT (setStatusBarDocSize(QSize))); // Caption (url, modified) connect (d->document, &kpDocument::documentModified, this, &kpMainWindow::slotUpdateCaption); connect (d->document, &kpDocument::documentOpened, this, &kpMainWindow::slotUpdateCaption); connect (d->document, &kpDocument::documentSaved, this, &kpMainWindow::slotUpdateCaption); // File/Reload action only available with non-empty URL connect (d->document, &kpDocument::documentSaved, this, &kpMainWindow::slotEnableReload); connect (d->document, &kpDocument::documentSaved, this, &kpMainWindow::slotEnableSettingsShowPath); // Command history Q_ASSERT (d->commandHistory); connect (d->commandHistory, &kpCommandHistory::documentRestored, this, &kpMainWindow::slotDocumentRestored); // caption "!modified" connect (d->document, &kpDocument::documentSaved, d->commandHistory, &kpCommandHistory::documentSaved); // Sync document -> views connect (d->document, &kpDocument::contentsChanged, d->viewManager, &kpViewManager::updateViews); connect (d->document, static_cast(&kpDocument::sizeChanged), d->viewManager, &kpViewManager::adjustViewsToEnvironment); connect (d->document, static_cast(&kpDocument::sizeChanged), d->viewManager, &kpViewManager::adjustViewsToEnvironment); #if DEBUG_KP_MAIN_WINDOW qCDebug(kpLogMainWindow) << "\tenabling actions"; #endif // sync with the bit marked "sync" above Q_ASSERT (d->colorToolBar); d->colorToolBar->setEnabled (true); // Hide the text toolbar - it will be shown by kpToolText::begin() enableTextToolBarActions (false); enableToolsDocumentActions (true); enableDocumentActions (true); } #if DEBUG_KP_MAIN_WINDOW qCDebug(kpLogMainWindow) << "\tupdating mainWindow elements"; #endif slotImageMenuUpdateDueToSelection (); recalculateStatusBar (); slotUpdateCaption (); // Untitled to start with slotEnableReload (); slotEnableSettingsShowPath (); if (d->commandHistory) { d->commandHistory->clear (); } #if DEBUG_KP_MAIN_WINDOW qCDebug(kpLogMainWindow) << "\tdocument and views ready to go!"; #endif } //--------------------------------------------------------------------- // private virtual [base QWidget] void kpMainWindow::dragEnterEvent (QDragEnterEvent *e) { // It's faster to test for QMimeData::hasText() first due to the // lazy evaluation of the '||' operator. e->setAccepted (e->mimeData ()->hasText () || e->mimeData ()->hasUrls () || kpSelectionDrag::canDecode (e->mimeData ())); } //--------------------------------------------------------------------- // private virtual [base QWidget] void kpMainWindow::dropEvent (QDropEvent *e) { #if DEBUG_KP_MAIN_WINDOW qCDebug(kpLogMainWindow) << "kpMainWindow::dropEvent" << e->pos (); #endif QList urls; kpAbstractImageSelection *sel = kpSelectionDrag::decode (e->mimeData ()); if (sel) { // TODO: How do you actually drop a selection or ordinary images on // the clipboard)? Will this code path _ever_ execute? sel->setTransparency (imageSelectionTransparency ()); // TODO: drop at point like with QTextDrag below? paste (*sel); delete sel; } else if (!(urls = e->mimeData ()->urls ()).isEmpty ()) { // LOTODO: kpSetOverrideCursorSaver cursorSaver (Qt::waitCursor); // // However, you would need to prefix all possible error/warning // dialogs that might be called, with Qt::arrowCursor e.g. in // kpDocument and probably a lot more places. for (const auto &u : urls) open (u); } else if (e->mimeData ()->hasText ()) { const QString text = e->mimeData ()->text (); QPoint selTopLeft = KP_INVALID_POINT; const QPoint globalPos = QWidget::mapToGlobal (e->pos ()); #if DEBUG_KP_MAIN_WINDOW qCDebug(kpLogMainWindow) << "\tpos toGlobal=" << globalPos; #endif kpView *view = nullptr; if (d->viewManager) { view = d->viewManager->viewUnderCursor (); #if DEBUG_KP_MAIN_WINDOW qCDebug(kpLogMainWindow) << "\t\tviewUnderCursor=" << view; #endif if (!view) { // HACK: see kpViewManager::setViewUnderCursor() to see why // it's not reliable #if DEBUG_KP_MAIN_WINDOW qCDebug(kpLogMainWindow) << "\t\tattempting to discover view"; if (d->mainView && d->scrollView) { qCDebug(kpLogMainWindow) << "\t\t\tmainView->globalRect=" << kpWidgetMapper::toGlobal (d->mainView, d->mainView->rect ()) << " scrollView->globalRect=" << kpWidgetMapper::toGlobal (d->scrollView, QRect (0, 0, d->scrollView->viewport()->width (), d->scrollView->viewport()->height ())); } #endif if (d->thumbnailView && kpWidgetMapper::toGlobal (d->thumbnailView, d->thumbnailView->rect ()) .contains (globalPos)) { // TODO: Code will never get executed. // Thumbnail doesn't accept drops. view = d->thumbnailView; } else if (d->mainView && kpWidgetMapper::toGlobal (d->mainView, d->mainView->rect ()) .contains (globalPos) && d->scrollView && kpWidgetMapper::toGlobal (d->scrollView, QRect (0, 0, d->scrollView->viewport()->width (), d->scrollView->viewport()->height ())) .contains (globalPos)) { view = d->mainView; } } } if (view) { const QPoint viewPos = view->mapFromGlobal (globalPos); const QPoint docPoint = view->transformViewToDoc (viewPos); // viewUnderCursor() is hacky and can return a view when we aren't // over one thanks to drags. if (d->document && d->document->rect ().contains (docPoint)) { selTopLeft = docPoint; // TODO: In terms of doc pixels, would be inconsistent behaviour // based on zoomLevel of view. // selTopLeft -= QPoint (-view->selectionResizeHandleAtomicSize (), // -view->selectionResizeHandleAtomicSize ()); } } pasteText (text, true/*force new text selection*/, selTopLeft); } } //--------------------------------------------------------------------- // private slot void kpMainWindow::slotScrollViewAfterScroll () { // OPT: Why can't this be moved into kpViewScrollableContainer::slotDragScroll(), // grouping all drag-scroll-related repaints, which would potentially avoid // double repainting? if (tool ()) { tool ()->somethingBelowTheCursorChanged (); } } //--------------------------------------------------------------------- // private virtual [base QWidget] void kpMainWindow::moveEvent (QMoveEvent * /*e*/) { if (d->thumbnail) { // Disabled because it lags too far behind the mainWindow // d->thumbnail->move (d->thumbnail->pos () + (e->pos () - e->oldPos ())); notifyThumbnailGeometryChanged (); } } //--------------------------------------------------------------------- // private slot void kpMainWindow::slotUpdateCaption () { if (d->document) { setCaption (d->configShowPath ? d->document->prettyUrl () : d->document->prettyFilename (), d->document->isModified ()); } else { setCaption (QString(), false); } } //--------------------------------------------------------------------- // private slot void kpMainWindow::slotDocumentRestored () { if (d->document) { d->document->setModified (false); } slotUpdateCaption (); } //--------------------------------------------------------------------- diff --git a/mainWindow/kpMainWindow_Colors.cpp b/mainWindow/kpMainWindow_Colors.cpp index 56be6016..c586ced7 100644 --- a/mainWindow/kpMainWindow_Colors.cpp +++ b/mainWindow/kpMainWindow_Colors.cpp @@ -1,494 +1,494 @@ /* 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 "kpMainWindow.h" #include "kpMainWindowPrivate.h" #include "widgets/kpColorCells.h" #include "lgpl/generic/kpColorCollection.h" #include "lgpl/generic/kpUrlFormatter.h" #include "widgets/toolbars/kpColorToolBar.h" #include #include #include #include #include "kpLogCategories.h" #include #include //--------------------------------------------------------------------- static QStringList KDEColorCollectionNames () { return kpColorCollection::installedCollections (); } //--------------------------------------------------------------------- // private void kpMainWindow::setupColorsMenuActions () { KActionCollection *ac = actionCollection (); - d->actionColorsDefault = ac->addAction ("colors_default"); + d->actionColorsDefault = ac->addAction (QStringLiteral("colors_default")); d->actionColorsDefault->setText (i18n ("Use KolourPaint Defaults")); connect (d->actionColorsDefault, &QAction::triggered, this, &kpMainWindow::slotColorsDefault); - d->actionColorsKDE = ac->add ("colors_kde"); + d->actionColorsKDE = ac->add (QStringLiteral("colors_kde")); d->actionColorsKDE->setText (i18nc ("@item:inmenu colors", "Use KDE's")); // TODO: Will this slot be called spuriously if there are no colors // installed? connect (d->actionColorsKDE, static_cast(&KSelectAction::triggered), this, &kpMainWindow::slotColorsKDE); for (const auto &colName : ::KDEColorCollectionNames ()) { d->actionColorsKDE->addAction (colName); } - d->actionColorsOpen = ac->addAction ("colors_open"); + d->actionColorsOpen = ac->addAction (QStringLiteral("colors_open")); d->actionColorsOpen->setText (i18nc ("@item:inmenu colors", "&Open...")); connect (d->actionColorsOpen, &QAction::triggered, this, &kpMainWindow::slotColorsOpen); - d->actionColorsReload = ac->addAction ("colors_reload"); + d->actionColorsReload = ac->addAction (QStringLiteral("colors_reload")); d->actionColorsReload->setText (i18nc ("@item:inmenu colors", "Reloa&d")); connect (d->actionColorsReload, &QAction::triggered, this, &kpMainWindow::slotColorsReload); - d->actionColorsSave = ac->addAction ("colors_save"); + d->actionColorsSave = ac->addAction (QStringLiteral("colors_save")); d->actionColorsSave->setText (i18nc ("@item:inmenu colors", "&Save")); connect (d->actionColorsSave, &QAction::triggered, this, &kpMainWindow::slotColorsSave); - d->actionColorsSaveAs = ac->addAction ("colors_save_as"); + d->actionColorsSaveAs = ac->addAction (QStringLiteral("colors_save_as")); d->actionColorsSaveAs->setText (i18nc ("@item:inmenu colors", "Save &As...")); connect (d->actionColorsSaveAs, &QAction::triggered, this, &kpMainWindow::slotColorsSaveAs); - d->actionColorsAppendRow = ac->addAction ("colors_append_row"); + d->actionColorsAppendRow = ac->addAction (QStringLiteral("colors_append_row")); d->actionColorsAppendRow->setText (i18nc ("@item:inmenu colors", "Add Row")); connect (d->actionColorsAppendRow, &QAction::triggered, this, &kpMainWindow::slotColorsAppendRow); - d->actionColorsDeleteRow = ac->addAction ("colors_delete_row"); + d->actionColorsDeleteRow = ac->addAction (QStringLiteral("colors_delete_row")); d->actionColorsDeleteRow->setText (i18nc ("@item:inmenu colors", "Delete Last Row")); connect (d->actionColorsDeleteRow, &QAction::triggered, this, &kpMainWindow::slotColorsDeleteRow); enableColorsMenuDocumentActions (false); } //--------------------------------------------------------------------- // private void kpMainWindow::createColorBox () { d->colorToolBar = new kpColorToolBar (i18n ("Color Box"), this); // (needed for QMainWindow::saveState()) - d->colorToolBar->setObjectName ( QLatin1String("Color Box" )); + d->colorToolBar->setObjectName ( QStringLiteral("Color Box" )); connect (colorCells (), &kpColorCells::rowCountChanged, this, &kpMainWindow::slotUpdateColorsDeleteRowActionEnabled); } //--------------------------------------------------------------------- // private void kpMainWindow::enableColorsMenuDocumentActions (bool enable) { d->actionColorsDefault->setEnabled (enable); d->actionColorsKDE->setEnabled (enable); d->actionColorsOpen->setEnabled (enable); d->actionColorsReload->setEnabled (enable); d->actionColorsSave->setEnabled (enable); d->actionColorsSaveAs->setEnabled (enable); d->actionColorsAppendRow->setEnabled (enable); d->colorMenuDocumentActionsEnabled = enable; slotUpdateColorsDeleteRowActionEnabled (); } //--------------------------------------------------------------------- // private slot void kpMainWindow::slotUpdateColorsDeleteRowActionEnabled () { // Currently, this is always enabled since kpColorCells guarantees that // there will be at least one row of cells (which might all be of the // invalid color). // // But this method is left here for future extensibility. d->actionColorsDeleteRow->setEnabled ( d->colorMenuDocumentActionsEnabled && (colorCells ()->rowCount () > 0)); } //--------------------------------------------------------------------- // Used in 2 situations: // // 1. User opens a color without using the "Use KDE's" submenu. // 2. User attempts to open a color using the "Use KDE's" submenu but the // opening fails. // // TODO: Maybe we could put the 3 actions (for different ways of opening // colors) in an exclusive group -- this might elminate the need for // this hack. // // private void kpMainWindow::deselectActionColorsKDE () { d->actionColorsKDE->setCurrentItem (-1); } //--------------------------------------------------------------------- // private bool kpMainWindow::queryCloseColors () { #if DEBUG_KP_MAIN_WINDOW qCDebug(kpLogMainWindow) << "kpMainWindow::queryCloseColors() colorCells.modified=" << colorCells ()->isModified (); #endif toolEndShape (); if (!colorCells ()->isModified ()) { return true; // ok to close } int result = KMessageBox::Cancel; if (!colorCells ()->url ().isEmpty ()) { result = KMessageBox::warningYesNoCancel (this, i18n ("The color palette \"%1\" has been modified.\n" "Do you want to save it?", kpUrlFormatter::PrettyFilename (colorCells ()->url ())), QString ()/*caption*/, KStandardGuiItem::save (), KStandardGuiItem::discard ()); } else { const QString name = colorCells ()->colorCollection ()->name (); if (!name.isEmpty ()) { result = KMessageBox::warningYesNoCancel (this, i18n ("The KDE color palette \"%1\" has been modified.\n" "Do you want to save it to a file?", name), QString ()/*caption*/, KStandardGuiItem::save (), KStandardGuiItem::discard ()); } else { result = KMessageBox::warningYesNoCancel (this, i18n ("The default color palette has been modified.\n" "Do you want to save it to a file?"), QString ()/*caption*/, KStandardGuiItem::save (), KStandardGuiItem::discard ()); } } switch (result) { case KMessageBox::Yes: return slotColorsSave (); // close only if save succeeds case KMessageBox::No: return true; // close without saving default: return false; // don't close current doc } } //--------------------------------------------------------------------- // private void kpMainWindow::openDefaultColors () { colorCells ()->setColorCollection ( kpColorCells::DefaultColorCollection ()); } //--------------------------------------------------------------------- // private slot void kpMainWindow::slotColorsDefault () { // Call just in case. toolEndShape (); if (!queryCloseColors ()) { return; } openDefaultColors (); deselectActionColorsKDE (); } //--------------------------------------------------------------------- // private bool kpMainWindow::openKDEColors (const QString &name) { #if DEBUG_KP_MAIN_WINDOW qCDebug(kpLogMainWindow) << "kpMainWindow::openKDEColors(" << name << ")"; #endif kpColorCollection colorCol; if (colorCol.openKDE (name, this)) { #if DEBUG_KP_MAIN_WINDOW qCDebug(kpLogMainWindow) << "opened"; #endif colorCells ()->setColorCollection (colorCol); return true; } else { #if DEBUG_KP_MAIN_WINDOW qCDebug(kpLogMainWindow) << "failed to open"; #endif return false; } } //--------------------------------------------------------------------- // private slot void kpMainWindow::slotColorsKDE () { // Call in case an error dialog appears. toolEndShape (); const int curItem = d->actionColorsKDE->currentItem (); if (!queryCloseColors ()) { deselectActionColorsKDE (); return; } // queryCloseColors() calls slotColorSave(), which can call // slotColorSaveAs(), which can call deselectActionColorsKDE(). d->actionColorsKDE->setCurrentItem (curItem); const QStringList colNames = ::KDEColorCollectionNames (); const int selected = d->actionColorsKDE->currentItem (); Q_ASSERT (selected >= 0 && selected < colNames.size ()); if (!openKDEColors (colNames [selected])) { deselectActionColorsKDE (); } } //--------------------------------------------------------------------- // private bool kpMainWindow::openColors (const QUrl &url) { return colorCells ()->openColorCollection (url); } //--------------------------------------------------------------------- // private slot void kpMainWindow::slotColorsOpen () { // Call due to dialog. toolEndShape (); QFileDialog fd(this); fd.setDirectoryUrl(colorCells ()->url()); fd.setWindowTitle(i18nc ("@title:window", "Open Color Palette")); if (fd.exec ()) { if (!queryCloseColors ()) { return; } QList selected = fd.selectedUrls(); if ( selected.count() && openColors(selected[0]) ) { deselectActionColorsKDE(); } } } //--------------------------------------------------------------------- // private slot void kpMainWindow::slotColorsReload () { toolEndShape (); if (colorCells ()->isModified ()) { int result = KMessageBox::Cancel; if (!colorCells ()->url ().isEmpty ()) { result = KMessageBox::warningContinueCancel (this, i18n ("The color palette \"%1\" has been modified.\n" "Reloading will lose all changes since you last saved it.\n" "Are you sure?", kpUrlFormatter::PrettyFilename (colorCells ()->url ())), QString ()/*caption*/, KGuiItem(i18n ("&Reload"))); } else { const QString name = colorCells ()->colorCollection ()->name (); if (!name.isEmpty ()) { result = KMessageBox::warningContinueCancel (this, i18n ("The KDE color palette \"%1\" has been modified.\n" "Reloading will lose all changes.\n" "Are you sure?", colorCells ()->colorCollection ()->name ()), QString ()/*caption*/, KGuiItem (i18n ("&Reload"))); } else { result = KMessageBox::warningContinueCancel (this, i18n ("The default color palette has been modified.\n" "Reloading will lose all changes.\n" "Are you sure?"), QString ()/*caption*/, KGuiItem (i18n ("&Reload"))); } } #if DEBUG_KP_MAIN_WINDOW qCDebug(kpLogMainWindow) << "result=" << result << "vs KMessageBox::Continue" << KMessageBox::Continue; #endif if (result != KMessageBox::Continue) { return; } } if (!colorCells ()->url ().isEmpty ()) { openColors (colorCells ()->url ()); } else { const QString name = colorCells ()->colorCollection ()->name (); if (!name.isEmpty ()) { openKDEColors (name); } else { openDefaultColors (); } } } //--------------------------------------------------------------------- // private slot bool kpMainWindow::slotColorsSave () { // Call due to dialog. toolEndShape (); if (colorCells ()->url ().isEmpty ()) { return slotColorsSaveAs (); } return colorCells ()->saveColorCollection (); } //--------------------------------------------------------------------- // private slot bool kpMainWindow::slotColorsSaveAs () { // Call due to dialog. toolEndShape (); QFileDialog fd(this); fd.setDirectoryUrl(colorCells ()->url()); fd.setWindowTitle(i18n("Save Color Palette As")); fd.setAcceptMode(QFileDialog::AcceptSave); if (fd.exec ()) { QList selected = fd.selectedUrls(); if ( !selected.count() || !colorCells ()->saveColorCollectionAs(selected[0]) ) { return false; } // We're definitely using our own color collection now. deselectActionColorsKDE (); return true; } return false; } //--------------------------------------------------------------------- // private slot void kpMainWindow::slotColorsAppendRow () { // Call just in case. toolEndShape (); kpColorCells *colorCells = d->colorToolBar->colorCells (); colorCells->appendRow (); } //--------------------------------------------------------------------- // private slot void kpMainWindow::slotColorsDeleteRow () { // Call just in case. toolEndShape (); kpColorCells *colorCells = d->colorToolBar->colorCells (); colorCells->deleteLastRow (); } diff --git a/mainWindow/kpMainWindow_Edit.cpp b/mainWindow/kpMainWindow_Edit.cpp index 6bda1a25..2a89be48 100644 --- a/mainWindow/kpMainWindow_Edit.cpp +++ b/mainWindow/kpMainWindow_Edit.cpp @@ -1,932 +1,932 @@ /* 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 = ac->addAction (QStringLiteral("edit_paste_in_new_window")); d->actionPasteInNewWindow->setText (i18n ("Paste in &New Window")); connect (d->actionPasteInNewWindow, &QAction::triggered, this, &kpMainWindow::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 = ac->addAction (QStringLiteral("edit_clear")); d->actionDelete->setText (i18n ("&Delete Selection")); connect (d->actionDelete, &QAction::triggered, this, &kpMainWindow::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 = ac->addAction (QStringLiteral("edit_copy_to_file")); d->actionCopyToFile->setText (i18n ("C&opy to File...")); connect (d->actionCopyToFile, &QAction::triggered, this, &kpMainWindow::slotCopyToFile); - d->actionPasteFromFile = ac->addAction ("edit_paste_from_file"); + d->actionPasteFromFile = ac->addAction (QStringLiteral("edit_paste_from_file")); d->actionPasteFromFile->setText (i18n ("Paste &From File...")); connect (d->actionPasteFromFile, &QAction::triggered, this, &kpMainWindow::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(), &QClipboard::dataChanged, this, &kpMainWindow::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)); + return qobject_cast (guiFactory ()->container (QStringLiteral("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) { auto *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)) { auto *textSel = dynamic_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)) { auto *imageSel = dynamic_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 << ")"; #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 {docTopLeft.x (), docTopLeft.y (), imageWidth, imageHeight}; } } return {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 << ")"; #endif kpSetOverrideCursorSaver cursorSaver (Qt::WaitCursor); toolEndShape (); // // Make sure we've got a document (esp. with File/Close) // if (!d->document) { auto *newDoc = new kpDocument ( sel.width (), sel.height (), documentEnvironment ()); // will also create viewManager setDocument (newDoc); } // // Paste as new selection // const auto *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 ()); #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 << ")"; #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 < 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 << ")"; #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. // auto *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 << ")"; #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_File.cpp b/mainWindow/kpMainWindow_File.cpp index f9179909..92c1a625 100644 --- a/mainWindow/kpMainWindow_File.cpp +++ b/mainWindow/kpMainWindow_File.cpp @@ -1,1524 +1,1524 @@ /* Copyright (c) 2003-2007 Clarence Dang Copyright (c) 2007 John Layt Copyright (c) 2007,2011,2015 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 #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include // kdelibs4support #include #include // kdelibs4support #include #include #include #include #include #include #include // kdelibs4support #include "kpLogCategories.h" #include "commands/kpCommandHistory.h" #include "kpDefs.h" #include "document/kpDocument.h" #include "commands/imagelib/kpDocumentMetaInfoCommand.h" #include "dialogs/imagelib/kpDocumentMetaInfoDialog.h" #include "widgets/kpDocumentSaveOptionsWidget.h" #include "pixmapfx/kpPixmapFX.h" #include "widgets/kpPrintDialogPage.h" #include "views/kpView.h" #include "views/manager/kpViewManager.h" #if HAVE_KSANE #include "../scan/sanedialog.h" #endif // HAVE_KSANE // private void kpMainWindow::setupFileMenuActions () { #if DEBUG_KP_MAIN_WINDOW qCDebug(kpLogMainWindow) << "kpMainWindow::setupFileMenuActions()"; #endif KActionCollection *ac = actionCollection (); d->actionNew = KStandardAction::openNew (this, SLOT (slotNew()), ac); d->actionOpen = KStandardAction::open (this, SLOT (slotOpen()), ac); d->actionOpenRecent = KStandardAction::openRecent(this, &kpMainWindow::slotOpenRecent, ac); connect(d->actionOpenRecent, &KRecentFilesAction::recentListCleared, this, &kpMainWindow::slotRecentListCleared); d->actionOpenRecent->loadEntries (KSharedConfig::openConfig ()->group (kpSettingsGroupRecentFiles)); #if DEBUG_KP_MAIN_WINDOW qCDebug(kpLogMainWindow) << "\trecent URLs=" << d->actionOpenRecent->items (); #endif d->actionSave = KStandardAction::save (this, SLOT (slotSave()), ac); d->actionSaveAs = KStandardAction::saveAs (this, SLOT (slotSaveAs()), ac); - d->actionExport = ac->addAction("file_export"); + d->actionExport = ac->addAction(QStringLiteral("file_export")); d->actionExport->setText (i18n ("E&xport...")); - d->actionExport->setIcon(KDE::icon("document-export")); + d->actionExport->setIcon(KDE::icon(QStringLiteral("document-export"))); connect (d->actionExport, &QAction::triggered, this, &kpMainWindow::slotExport); - d->actionScan = ac->addAction("file_scan"); + d->actionScan = ac->addAction(QStringLiteral("file_scan")); d->actionScan->setText(i18n ("Scan...")); d->actionScan->setIcon(SmallIcon("scanner")); #if HAVE_KSANE connect (d->actionScan, &QAction::triggered, this, &kpMainWindow::slotScan); #else d->actionScan->setEnabled(false); #endif // HAVE_KSANE - d->actionScreenshot = ac->addAction("file_screenshot"); + d->actionScreenshot = ac->addAction(QStringLiteral("file_screenshot")); d->actionScreenshot->setText(i18n("Acquire Screenshot")); connect (d->actionScreenshot, &QAction::triggered, this, &kpMainWindow::slotScreenshot); - d->actionProperties = ac->addAction ("file_properties"); + d->actionProperties = ac->addAction (QStringLiteral("file_properties")); d->actionProperties->setText (i18n ("Properties")); - d->actionProperties->setIcon(KDE::icon("document-properties")); + d->actionProperties->setIcon(KDE::icon(QStringLiteral("document-properties"))); connect (d->actionProperties, &QAction::triggered, this, &kpMainWindow::slotProperties); //d->actionRevert = KStandardAction::revert (this, SLOT (slotRevert()), ac); - d->actionReload = ac->addAction ("file_revert"); + d->actionReload = ac->addAction (QStringLiteral("file_revert")); d->actionReload->setText (i18n ("Reloa&d")); - d->actionReload->setIcon(KDE::icon("view-refresh")); + d->actionReload->setIcon(KDE::icon(QStringLiteral("view-refresh"))); connect (d->actionReload, &QAction::triggered, this, &kpMainWindow::slotReload); ac->setDefaultShortcuts (d->actionReload, KStandardShortcut::reload ()); slotEnableReload (); d->actionPrint = KStandardAction::print (this, SLOT (slotPrint()), ac); d->actionPrintPreview = KStandardAction::printPreview (this, SLOT (slotPrintPreview()), ac); d->actionMail = KStandardAction::mail (this, SLOT (slotMail()), ac); d->actionClose = KStandardAction::close (this, SLOT (slotClose()), ac); d->actionQuit = KStandardAction::quit (this, SLOT (slotQuit()), ac); d->scanDialog = nullptr; enableFileMenuDocumentActions (false); } //--------------------------------------------------------------------- // private void kpMainWindow::enableFileMenuDocumentActions (bool enable) { // d->actionNew // d->actionOpen // d->actionOpenRecent d->actionSave->setEnabled (enable); d->actionSaveAs->setEnabled (enable); d->actionExport->setEnabled (enable); // d->actionScan d->actionProperties->setEnabled (enable); // d->actionReload d->actionPrint->setEnabled (enable); d->actionPrintPreview->setEnabled (enable); d->actionMail->setEnabled (enable); d->actionClose->setEnabled (enable); // d->actionQuit->setEnabled (enable); } //--------------------------------------------------------------------- // private void kpMainWindow::addRecentURL (const QUrl &url_) { // HACK: KRecentFilesAction::loadEntries() clears the KRecentFilesAction::d->urls // map. // // So afterwards, the URL ref, our method is given, points to an // element in this now-cleared map (see KRecentFilesAction::urlSelected(QAction*)). // Accessing it would result in a crash. // // To avoid the crash, make a copy of it before calling // loadEntries() and use this copy, instead of the to-be-dangling // ref. const QUrl& url = url_; #if DEBUG_KP_MAIN_WINDOW qCDebug(kpLogMainWindow) << "kpMainWindow::addRecentURL(" << url << ")"; #endif if (url.isEmpty ()) return; KSharedConfig::Ptr cfg = KSharedConfig::openConfig(); // KConfig::readEntry() does not actually reread from disk, hence doesn't // realize what other processes have done e.g. Settings / Show Path cfg->reparseConfiguration (); #if DEBUG_KP_MAIN_WINDOW qCDebug(kpLogMainWindow) << "\trecent URLs=" << d->actionOpenRecent->items (); #endif // HACK: Something might have changed interprocess. // If we could PROPAGATE: interprocess, then this wouldn't be required. d->actionOpenRecent->loadEntries (cfg->group (kpSettingsGroupRecentFiles)); #if DEBUG_KP_MAIN_WINDOW qCDebug(kpLogMainWindow) << "\tafter loading config=" << d->actionOpenRecent->items (); #endif d->actionOpenRecent->addUrl (url); d->actionOpenRecent->saveEntries (cfg->group (kpSettingsGroupRecentFiles)); cfg->sync (); #if DEBUG_KP_MAIN_WINDOW qCDebug(kpLogMainWindow) << "\tnew recent URLs=" << d->actionOpenRecent->items (); #endif // TODO: PROPAGATE: interprocess // TODO: Is this loop safe since a KMainWindow later along in the list, // could be closed as the code in the body almost certainly re-enters // the event loop? Problem for KDE 3 as well, I think. for (auto *kmw : KMainWindow::memberList ()) { Q_ASSERT (dynamic_cast (kmw)); auto *mw = dynamic_cast (kmw); #if DEBUG_KP_MAIN_WINDOW qCDebug(kpLogMainWindow) << "\t\tmw=" << mw; #endif if (mw != this) { // WARNING: Do not use KRecentFilesAction::setItems() // - it does not work since only its superclass, // KSelectAction, implements setItems() and can't // update KRecentFilesAction's URL list. // Avoid URL memory leak in KRecentFilesAction::loadEntries(). mw->d->actionOpenRecent->clear (); mw->d->actionOpenRecent->loadEntries (cfg->group (kpSettingsGroupRecentFiles)); #if DEBUG_KP_MAIN_WINDOW qCDebug(kpLogMainWindow) << "\t\t\tcheck recent URLs=" << mw->d->actionOpenRecent->items (); #endif } } } //--------------------------------------------------------------------- // private slot // TODO: Disable action if // (d->configOpenImagesInSameWindow && d->document && d->document->isEmpty()) // as it does nothing if this is true. void kpMainWindow::slotNew () { toolEndShape (); if (d->document && !d->configOpenImagesInSameWindow) { // A document -- empty or otherwise -- is open. // Force open a new window. In contrast, open() might not open // a new window in this case. auto *win = new kpMainWindow (); win->show (); } else { open (QUrl (), true/*create an empty doc*/); } } //--------------------------------------------------------------------- // private QSize kpMainWindow::defaultDocSize () const { // KConfig::readEntry() does not actually reread from disk, hence doesn't // realize what other processes have done e.g. Settings / Show Path KSharedConfig::openConfig ()->reparseConfiguration (); KConfigGroup cfg (KSharedConfig::openConfig (), kpSettingsGroupGeneral); QSize docSize = cfg.readEntry (kpSettingLastDocSize, QSize ()); if (docSize.isEmpty ()) { docSize = QSize (400, 300); } else { // Don't get too big or you'll thrash (or even lock up) the computer // just by opening a window docSize = QSize (qMin (2048, docSize.width ()), qMin (2048, docSize.height ())); } return docSize; } //--------------------------------------------------------------------- // private void kpMainWindow::saveDefaultDocSize (const QSize &size) { #if DEBUG_KP_MAIN_WINDOW qCDebug(kpLogMainWindow) << "\tCONFIG: saving Last Doc Size = " << size; #endif KConfigGroup cfg (KSharedConfig::openConfig (), kpSettingsGroupGeneral); cfg.writeEntry (kpSettingLastDocSize, size); cfg.sync (); } //--------------------------------------------------------------------- // private bool kpMainWindow::shouldOpen () { if (d->configOpenImagesInSameWindow) { #if DEBUG_KP_MAIN_WINDOW qCDebug(kpLogMainWindow) << "\topenImagesInSameWindow"; #endif // (this brings up a dialog and might save the current doc) if (!queryCloseDocument ()) { #if DEBUG_KP_MAIN_WINDOW qCDebug(kpLogMainWindow) << "\t\tqueryCloseDocument() aborts open"; #endif return false; } } return true; } //--------------------------------------------------------------------- // private void kpMainWindow::setDocumentChoosingWindow (kpDocument *doc) { // Want new window? if (d->document && !d->document->isEmpty () && !d->configOpenImagesInSameWindow) { // Send doc to new window. auto *win = new kpMainWindow (doc); win->show (); } else { // (sets up views, doc signals) setDocument (doc); } } //--------------------------------------------------------------------- // private kpDocument *kpMainWindow::openInternal (const QUrl &url, const QSize &fallbackDocSize, bool newDocSameNameIfNotExist) { // If using OpenImagesInSameWindow mode, ask whether to close the // current document. if (!shouldOpen ()) return nullptr; // Create/open doc. auto *newDoc = new kpDocument (fallbackDocSize.width (), fallbackDocSize.height (), documentEnvironment ()); if (!newDoc->open (url, newDocSameNameIfNotExist)) { #if DEBUG_KP_MAIN_WINDOW qCDebug(kpLogMainWindow) << "\topen failed"; #endif delete newDoc; return nullptr; } #if DEBUG_KP_MAIN_WINDOW qCDebug(kpLogMainWindow) << "\topen OK"; #endif // Send document to current or new window. setDocumentChoosingWindow (newDoc); return newDoc; } //--------------------------------------------------------------------- // private bool kpMainWindow::open (const QUrl &url, bool newDocSameNameIfNotExist) { #if DEBUG_KP_MAIN_WINDOW qCDebug(kpLogMainWindow) << "kpMainWindow::open(" << url << ",newDocSameNameIfNotExist=" << newDocSameNameIfNotExist << ")"; #endif kpDocument *newDoc = openInternal (url, defaultDocSize (), newDocSameNameIfNotExist); if (newDoc) { if (newDoc->isFromURL (false/*don't bother checking exists*/)) addRecentURL (url); return true; } return false; } //--------------------------------------------------------------------- // private QList kpMainWindow::askForOpenURLs(const QString &caption, bool allowMultipleURLs) { QMimeDatabase db; QStringList filterList; QString filter; for (const auto &type : QImageReader::supportedMimeTypes()) { if ( !filter.isEmpty() ) { filter += QLatin1Char(' '); } QMimeType mime(db.mimeTypeForName(QString::fromLatin1(type))); if ( mime.isValid() ) { QString glob = mime.globPatterns().join(QLatin1Char(' ')); filter += glob; // I want to show the mime comment AND the file glob pattern, // but to avoid that the "All Supported Files" entry shows ALL glob patterns, // I must add the pattern here a second time so that QFileDialog::HideNameFilterDetails // can hide the first pattern and I still see the second one - filterList << mime.comment() + QString(" (%1)(%2)").arg(glob).arg(glob); + filterList << mime.comment() + QStringLiteral(" (%1)(%2)").arg(glob).arg(glob); } } filterList.prepend(i18n("All Supported Files (%1)", filter)); QFileDialog fd(this); fd.setNameFilters(filterList); fd.setOption(QFileDialog::HideNameFilterDetails); fd.setWindowTitle(caption); if ( allowMultipleURLs ) { fd.setFileMode(QFileDialog::ExistingFiles); } if ( fd.exec() ) { return fd.selectedUrls(); } return QList(); } //--------------------------------------------------------------------- // private slot void kpMainWindow::slotOpen () { toolEndShape (); const QList urls = askForOpenURLs(i18nc("@title:window", "Open Image")); for (const auto & url : urls) { open (url); } } //--------------------------------------------------------------------- // private slot void kpMainWindow::slotOpenRecent (const QUrl &url) { #if DEBUG_KP_MAIN_WINDOW qCDebug(kpLogMainWindow) << "kpMainWindow::slotOpenRecent(" << url << ")"; qCDebug(kpLogMainWindow) << "\titems=" << d->actionOpenRecent->items (); #endif toolEndShape (); open (url); // If the open is successful, addRecentURL() would have bubbled up the // URL in the File / Open Recent action. As a side effect, the URL is // deselected. // // If the open fails, we should deselect the URL: // // 1. for consistency // // 2. because it has not been opened. // d->actionOpenRecent->setCurrentItem (-1); } //--------------------------------------------------------------------- void kpMainWindow::slotRecentListCleared() { d->actionOpenRecent->saveEntries(KSharedConfig::openConfig()->group(kpSettingsGroupRecentFiles)); } //--------------------------------------------------------------------- #if HAVE_KSANE // private slot void kpMainWindow::slotScan () { #if DEBUG_KP_MAIN_WINDOW qCDebug(kpLogMainWindow) << "kpMainWindow::slotScan() scanDialog=" << d->scanDialog; #endif toolEndShape (); if (!d->scanDialog) { // Create scan dialog d->scanDialog = new SaneDialog(this); // No scanning support (kdegraphics/libkscan) installed? if (!d->scanDialog) { KMessageBox::sorry (this, i18n("Failed to open scanning dialog."), i18nc("@title:window", "Scanning Failed")); return; } #if DEBUG_KP_MAIN_WINDOW qCDebug(kpLogMainWindow) << "\tcreated scanDialog=" << d->scanDialog; #endif connect (d->scanDialog, &SaneDialog::finalImage, this, &kpMainWindow::slotScanned); } // If using OpenImagesInSameWindow mode, ask whether to close the // current document. // // Do this after scan support is detected. Because if it's not, what // would be the point of closing the document? // // Ideally, we would do this after the user presses "Final Scan" in // the scan dialog and before the scan begins (if the user wants to // cancel the scan operation, it would be annoying to offer this choice // only after the slow scan is completed) but the KScanDialog API does // not allow this. So we settle for doing this before any // scan dialogs are shown. We don't do this between KScanDialog::setup() // and KScanDialog::exec() as it could be confusing alternating between // scanning and KolourPaint dialogs. if (!shouldOpen ()) { return; } #if DEBUG_KP_MAIN_WINDOW qCDebug(kpLogMainWindow) << "\tcalling setup"; #endif // Bring up dialog to select scan device. // If there is no scanner, we find that this does not bring up a dialog // but still returns true. if (d->scanDialog->setup ()) { #if DEBUG_KP_MAIN_WINDOW qCDebug(kpLogMainWindow) << "\t\tOK - showing dialog"; #endif // Called only if scanner configured/available. // // In reality, this seems to be called even if you press "Cancel" in // the KScanDialog::setup() dialog! // // We use exec() to make sure it's modal. show() seems to work too // but better safe than sorry. d->scanDialog->exec (); } else { // Have never seen this code path execute even if "Cancel" is pressed. #if DEBUG_KP_MAIN_WINDOW qCDebug(kpLogMainWindow) << "\t\tFAIL"; #endif } } //--------------------------------------------------------------------- // private slot void kpMainWindow::slotScanned (const QImage &image, int) { #if DEBUG_KP_MAIN_WINDOW qCDebug(kpLogMainWindow) << "kpMainWindow::slotScanned() image.rect=" << image.rect (); #endif #if DEBUG_KP_MAIN_WINDOW qCDebug(kpLogMainWindow) << "\thiding dialog"; #endif // (KScanDialog does not close itself after a scan is made) // // Close the dialog, first thing: // // 1. This means that any dialogs we bring up won't be nested on top. // // 2. We don't want to return from this method but forget to close // the dialog. So do it before anything else. d->scanDialog->hide (); // (just in case there's some drawing between slotScan() exiting and // us being called) toolEndShape (); // TODO: Maybe this code should be moved into kpdocument.cpp - // since it resembles the responsibilities of kpDocument::open(). kpDocumentSaveOptions saveOptions; kpDocumentMetaInfo metaInfo; kpDocument::getDataFromImage(image, saveOptions, metaInfo); // Create document from image and meta info. auto *doc = new kpDocument (image.width (), image.height (), documentEnvironment ()); doc->setImage (image); doc->setSaveOptions (saveOptions); doc->setMetaInfo (metaInfo); // Send document to current or new window. setDocumentChoosingWindow (doc); } #endif // HAVE_KSANE //--------------------------------------------------------------------- void kpMainWindow::slotScreenshot() { toolEndShape(); auto *dialog = new QDialog(this); auto *buttons = new QDialogButtonBox(QDialogButtonBox::Ok | QDialogButtonBox::Cancel, dialog); connect (buttons, &QDialogButtonBox::accepted, dialog, &QDialog::accept); connect (buttons, &QDialogButtonBox::rejected, dialog, &QDialog::reject); auto *label = new QLabel(i18n("Snapshot Delay")); auto *seconds = new KPluralHandlingSpinBox; seconds->setRange(0, 99); seconds->setSuffix(ki18np(" second", " seconds")); seconds->setSpecialValueText(i18n("No delay")); auto *hideWindow = new QCheckBox(i18n("Hide Main Window")); hideWindow->setChecked(true); auto *vbox = new QVBoxLayout(dialog); vbox->addWidget(label); vbox->addWidget(seconds); vbox->addWidget(hideWindow); vbox->addWidget(buttons); if ( dialog->exec() == QDialog::Rejected ) { delete dialog; return; } if ( hideWindow->isChecked() ) { hide(); } // at least 1 seconds to make sure the window is hidden and the hide effect already stopped - QTimer::singleShot((seconds->value() + 1) * 1000, this, SLOT(slotMakeScreenshot())); + QTimer::singleShot((seconds->value() + 1) * 1000, this, &kpMainWindow::slotMakeScreenshot); delete dialog; } //--------------------------------------------------------------------- void kpMainWindow::slotMakeScreenshot() { QCoreApplication::processEvents(); QPixmap pixmap = QGuiApplication::primaryScreen()->grabWindow(QApplication::desktop()->winId()); auto *doc = new kpDocument(pixmap.width(), pixmap.height(), documentEnvironment()); doc->setImage(pixmap.toImage()); // Send document to current or new window. setDocumentChoosingWindow(doc); show(); // in case we hid the mainwindow, show it again } //--------------------------------------------------------------------- // private slot void kpMainWindow::slotProperties () { toolEndShape (); kpDocumentMetaInfoDialog dialog (document ()->metaInfo (), this); if (dialog.exec () && !dialog.isNoOp ()) { commandHistory ()->addCommand ( new kpDocumentMetaInfoCommand ( i18n ("Document Properties"), dialog.metaInfo ()/*new*/, *document ()->metaInfo ()/*old*/, commandEnvironment ())); } } //--------------------------------------------------------------------- // private slot bool kpMainWindow::save (bool localOnly) { if (d->document->url ().isEmpty () || !QImageWriter::supportedMimeTypes() .contains(d->document->saveOptions ()->mimeType().toLatin1()) || // SYNC: kpDocument::getPixmapFromFile() can't determine quality // from file so it has been set initially to an invalid value. (d->document->saveOptions ()->mimeTypeHasConfigurableQuality () && d->document->saveOptions ()->qualityIsInvalid ()) || (localOnly && !d->document->url ().isLocalFile ())) { return saveAs (localOnly); } if (d->document->save (false/*no overwrite prompt*/, !d->document->savedAtLeastOnceBefore ()/*lossy prompt*/)) { addRecentURL (d->document->url ()); return true; } return false; } //--------------------------------------------------------------------- // private slot bool kpMainWindow::slotSave () { toolEndShape (); return save (); } //--------------------------------------------------------------------- // private QUrl kpMainWindow::askForSaveURL (const QString &caption, const QString &startURL, const kpImage &imageToBeSaved, const kpDocumentSaveOptions &startSaveOptions, const kpDocumentMetaInfo &docMetaInfo, const QString &forcedSaveOptionsGroup, bool localOnly, kpDocumentSaveOptions *chosenSaveOptions, bool isSavingForFirstTime, bool *allowOverwritePrompt, bool *allowLossyPrompt) { #if DEBUG_KP_MAIN_WINDOW qCDebug(kpLogMainWindow) << "kpMainWindow::askForURL() startURL=" << startURL; startSaveOptions.printDebug ("\tstartSaveOptions"); #endif bool reparsedConfiguration = false; // KConfig::readEntry() does not actually reread from disk, hence doesn't // realize what other processes have done e.g. Settings / Show Path // so reparseConfiguration() must be called #define SETUP_READ_CFG() \ if (!reparsedConfiguration) \ { \ KSharedConfig::openConfig ()->reparseConfiguration (); \ reparsedConfiguration = true; \ } \ \ KConfigGroup cfg (KSharedConfig::openConfig (), forcedSaveOptionsGroup); if (chosenSaveOptions) { *chosenSaveOptions = kpDocumentSaveOptions (); } if (allowOverwritePrompt) { *allowOverwritePrompt = true; // play it safe for now } if (allowLossyPrompt) { *allowLossyPrompt = true; // play it safe for now } kpDocumentSaveOptions fdSaveOptions = startSaveOptions; QStringList mimeTypes; for (const auto &type : QImageWriter::supportedMimeTypes()) { mimeTypes << QString::fromLatin1(type); } #if DEBUG_KP_MAIN_WINDOW QStringList sortedMimeTypes = mimeTypes; sortedMimeTypes.sort (); qCDebug(kpLogMainWindow) << "\tmimeTypes=" << mimeTypes << "\tsortedMimeTypes=" << sortedMimeTypes; #endif if (mimeTypes.isEmpty ()) { qCCritical(kpLogMainWindow) << "No output mimetypes!"; return QUrl (); } #define MIME_TYPE_IS_VALID() (!fdSaveOptions.mimeTypeIsInvalid () && \ mimeTypes.contains (fdSaveOptions.mimeType ())) if (!MIME_TYPE_IS_VALID ()) { #if DEBUG_KP_MAIN_WINDOW qCDebug(kpLogMainWindow) << "\tmimeType=" << fdSaveOptions.mimeType () << " not valid, get default"; #endif SETUP_READ_CFG (); fdSaveOptions.setMimeType (kpDocumentSaveOptions::defaultMimeType (cfg)); if (!MIME_TYPE_IS_VALID ()) { #if DEBUG_KP_MAIN_WINDOW qCDebug(kpLogMainWindow) << "\tmimeType=" << fdSaveOptions.mimeType () << " not valid, get hardcoded"; #endif - if (mimeTypes.contains ("image/png")) { - fdSaveOptions.setMimeType ("image/png"); + if (mimeTypes.contains (QStringLiteral("image/png"))) { + fdSaveOptions.setMimeType (QStringLiteral("image/png")); } - else if (mimeTypes.contains ("image/bmp")) { - fdSaveOptions.setMimeType ("image/bmp"); + else if (mimeTypes.contains (QStringLiteral("image/bmp"))) { + fdSaveOptions.setMimeType (QStringLiteral("image/bmp")); } else { fdSaveOptions.setMimeType (mimeTypes.first ()); } } } #undef MIME_TYPE_IS_VALID if (fdSaveOptions.colorDepthIsInvalid ()) { SETUP_READ_CFG (); fdSaveOptions.setColorDepth (kpDocumentSaveOptions::defaultColorDepth (cfg)); fdSaveOptions.setDither (kpDocumentSaveOptions::defaultDither (cfg)); } if (fdSaveOptions.qualityIsInvalid ()) { SETUP_READ_CFG (); fdSaveOptions.setQuality (kpDocumentSaveOptions::defaultQuality (cfg)); } #if DEBUG_KP_MAIN_WINDOW fdSaveOptions.printDebug ("\tcorrected saveOptions passed to fileDialog"); #endif auto *saveOptionsWidget = new kpDocumentSaveOptionsWidget (imageToBeSaved, fdSaveOptions, docMetaInfo, this); KFileDialog fd (QUrl (startURL), QString(), this, saveOptionsWidget); saveOptionsWidget->setVisualParent (&fd); fd.setWindowTitle (caption); fd.setOperationMode (KFileDialog::Saving); fd.setMimeFilter (mimeTypes, fdSaveOptions.mimeType ()); if (localOnly) { fd.setMode (KFile::File | KFile::LocalOnly); } connect (&fd, &KFileDialog::filterChanged, saveOptionsWidget, &kpDocumentSaveOptionsWidget::setMimeType); if ( fd.exec() == QDialog::Accepted ) { kpDocumentSaveOptions newSaveOptions = saveOptionsWidget->documentSaveOptions (); #if DEBUG_KP_MAIN_WINDOW newSaveOptions.printDebug ("\tnewSaveOptions"); #endif KConfigGroup cfg (KSharedConfig::openConfig (), forcedSaveOptionsGroup); // Save options user forced - probably want to use them in future kpDocumentSaveOptions::saveDefaultDifferences (cfg, fdSaveOptions, newSaveOptions); cfg.sync (); if (chosenSaveOptions) { *chosenSaveOptions = newSaveOptions; } bool shouldAllowOverwritePrompt = (fd.selectedUrl () != QUrl (startURL) || newSaveOptions.mimeType () != startSaveOptions.mimeType ()); if (allowOverwritePrompt) { *allowOverwritePrompt = shouldAllowOverwritePrompt; #if DEBUG_KP_MAIN_WINDOW qCDebug(kpLogMainWindow) << "\tallowOverwritePrompt=" << *allowOverwritePrompt; #endif } if (allowLossyPrompt) { // SYNC: kpDocumentSaveOptions elements - everything except quality // (one quality setting is "just as lossy" as another so no // need to continually warn due to quality change) *allowLossyPrompt = (isSavingForFirstTime || shouldAllowOverwritePrompt || newSaveOptions.mimeType () != startSaveOptions.mimeType () || newSaveOptions.colorDepth () != startSaveOptions.colorDepth () || newSaveOptions.dither () != startSaveOptions.dither ()); #if DEBUG_KP_MAIN_WINDOW qCDebug(kpLogMainWindow) << "\tallowLossyPrompt=" << *allowLossyPrompt; #endif } #if DEBUG_KP_MAIN_WINDOW qCDebug(kpLogMainWindow) << "\tselectedUrl=" << fd.selectedUrl (); #endif return fd.selectedUrl (); } return QUrl (); #undef SETUP_READ_CFG } //--------------------------------------------------------------------- // private slot bool kpMainWindow::saveAs (bool localOnly) { kpDocumentSaveOptions chosenSaveOptions; bool allowOverwritePrompt, allowLossyPrompt; QUrl chosenURL = askForSaveURL (i18nc ("@title:window", "Save Image As"), d->document->url ().url (), d->document->imageWithSelection (), *d->document->saveOptions (), *d->document->metaInfo (), kpSettingsGroupFileSaveAs, localOnly, &chosenSaveOptions, !d->document->savedAtLeastOnceBefore (), &allowOverwritePrompt, &allowLossyPrompt); if (chosenURL.isEmpty ()) { return false; } if (!d->document->saveAs (chosenURL, chosenSaveOptions, allowOverwritePrompt, allowLossyPrompt)) { return false; } addRecentURL (chosenURL); return true; } //--------------------------------------------------------------------- // private slot bool kpMainWindow::slotSaveAs () { toolEndShape (); return saveAs (); } //--------------------------------------------------------------------- // private slot bool kpMainWindow::slotExport () { toolEndShape (); kpDocumentSaveOptions chosenSaveOptions; bool allowOverwritePrompt, allowLossyPrompt; QUrl chosenURL = askForSaveURL (i18nc ("@title:window", "Export"), d->lastExportURL.url (), d->document->imageWithSelection (), d->lastExportSaveOptions, *d->document->metaInfo (), kpSettingsGroupFileExport, false/*allow remote files*/, &chosenSaveOptions, d->exportFirstTime, &allowOverwritePrompt, &allowLossyPrompt); if (chosenURL.isEmpty ()) { return false; } if (!kpDocument::savePixmapToFile (d->document->imageWithSelection (), chosenURL, chosenSaveOptions, *d->document->metaInfo (), allowOverwritePrompt, allowLossyPrompt, this)) { return false; } addRecentURL (chosenURL); d->lastExportURL = chosenURL; d->lastExportSaveOptions = chosenSaveOptions; d->exportFirstTime = false; return true; } //--------------------------------------------------------------------- // private slot void kpMainWindow::slotEnableReload () { d->actionReload->setEnabled (d->document); } //--------------------------------------------------------------------- // private slot bool kpMainWindow::slotReload () { toolEndShape (); Q_ASSERT (d->document); QUrl oldURL = d->document->url (); if (d->document->isModified ()) { int result = KMessageBox::Cancel; if (d->document->isFromURL (false/*don't bother checking exists*/) && !oldURL.isEmpty ()) { result = KMessageBox::warningContinueCancel (this, i18n ("The document \"%1\" has been modified.\n" "Reloading will lose all changes since you last saved it.\n" "Are you sure?", d->document->prettyFilename ()), QString()/*caption*/, KGuiItem(i18n ("&Reload"))); } else { result = KMessageBox::warningContinueCancel (this, i18n ("The document \"%1\" has been modified.\n" "Reloading will lose all changes.\n" "Are you sure?", d->document->prettyFilename ()), QString()/*caption*/, KGuiItem(i18n ("&Reload"))); } if (result != KMessageBox::Continue) { return false; } } kpDocument *doc = nullptr; // If it's _supposed to_ come from a URL or it exists if (d->document->isFromURL (false/*don't bother checking exists*/) || (!oldURL.isEmpty () && KIO::NetAccess::exists (oldURL, KIO::NetAccess::SourceSide/*open*/, this))) { #if DEBUG_KP_MAIN_WINDOW qCDebug(kpLogMainWindow) << "kpMainWindow::slotReload() reloading from disk!"; #endif doc = new kpDocument (1, 1, documentEnvironment ()); if (!doc->open (oldURL)) { delete doc; doc = nullptr; return false; } addRecentURL (oldURL); } else { #if DEBUG_KP_MAIN_WINDOW qCDebug(kpLogMainWindow) << "kpMainWindow::slotReload() create doc"; #endif doc = new kpDocument (d->document->constructorWidth (), d->document->constructorHeight (), documentEnvironment ()); doc->setURL (oldURL, false/*not from URL*/); } setDocument (doc); return true; } // private void kpMainWindow::sendDocumentNameToPrinter (QPrinter *printer) { QUrl url = d->document->url (); if (!url.isEmpty ()) { int dot; QString fileName = url.fileName (); dot = fileName.lastIndexOf ('.'); // file.ext but not .hidden-file? if (dot > 0) { fileName.truncate (dot); } #if DEBUG_KP_MAIN_WINDOW qCDebug(kpLogMainWindow) << "kpMainWindow::sendDocumentNameToPrinter() fileName=" << fileName << " dir=" << url.path(); #endif printer->setDocName (fileName); } } //-------------------------------------------------------------------------------- void kpMainWindow::sendPreviewToPrinter(QPrinter *printer) { sendImageToPrinter(printer, false); } //-------------------------------------------------------------------------------- // private void kpMainWindow::sendImageToPrinter (QPrinter *printer, bool showPrinterSetupDialog) { // Get image to be printed. kpImage image = d->document->imageWithSelection (); // Get image DPI. auto imageDotsPerMeterX = double (d->document->metaInfo ()->dotsPerMeterX ()); auto imageDotsPerMeterY = double (d->document->metaInfo ()->dotsPerMeterY ()); #if DEBUG_KP_MAIN_WINDOW qCDebug(kpLogMainWindow) << "kpMainWindow::sendImageToPrinter() image:" << " width=" << image.width () << " height=" << image.height () << " dotsPerMeterX=" << imageDotsPerMeterX << " dotsPerMeterY=" << imageDotsPerMeterY; #endif // Image DPI invalid (e.g. new image, could not read from file // or Qt3 doesn't implement DPI for JPEG)? if (imageDotsPerMeterX <= 0 || imageDotsPerMeterY <= 0) { // Even if just one DPI dimension is invalid, mutate both DPI // dimensions as we have no information about the intended // aspect ratio anyway (and other dimension likely to be invalid). // When rendering text onto a document, the fonts are rasterised // according to the screen's DPI. // TODO: I think we should use the image's DPI. Technically // possible? // // So no matter what computer you draw text on, you get // the same pixels. // // So we must print at the screen's DPI to get the right text size. // // Unfortunately, this means that moving to a different screen DPI // affects printing. If you edited the image at a different screen // DPI than when you print, you get incorrect results. Furthermore, // this is bogus if you don't have text in your image. Worse still, // what if you have multiple screens connected to the same computer // with different DPIs? // TODO: mysteriously, someone else is setting this to 96dpi always. QPixmap arbitraryScreenElement(1, 1); const QPaintDevice *screenDevice = &arbitraryScreenElement; const auto dpiX = screenDevice->logicalDpiX (); const auto dpiY = screenDevice->logicalDpiY (); #if DEBUG_KP_MAIN_WINDOW qCDebug(kpLogMainWindow) << "\tusing screen dpi: x=" << dpiX << " y=" << dpiY; #endif imageDotsPerMeterX = dpiX * KP_INCHES_PER_METER; imageDotsPerMeterY = dpiY * KP_INCHES_PER_METER; } // Get page size (excluding margins). // Coordinate (0,0) is the X here: // mmmmm // mX m // m m m = margin // m m // mmmmm const auto printerWidthMM = printer->widthMM (); const auto printerHeightMM = printer->heightMM (); auto dpiX = imageDotsPerMeterX / KP_INCHES_PER_METER; auto dpiY = imageDotsPerMeterY / KP_INCHES_PER_METER; #if DEBUG_KP_MAIN_WINDOW qCDebug(kpLogMainWindow) << "\tprinter: widthMM=" << printerWidthMM << " heightMM=" << printerHeightMM; qCDebug(kpLogMainWindow) << "\timage: dpiX=" << dpiX << " dpiY=" << dpiY; #endif // // If image doesn't fit on page at intended DPI, change the DPI. // const auto scaleDpiX = (image.width () / (printerWidthMM / KP_MILLIMETERS_PER_INCH)) / dpiX; const auto scaleDpiY = (image.height () / (printerHeightMM / KP_MILLIMETERS_PER_INCH)) / dpiY; const auto scaleDpi = qMax (scaleDpiX, scaleDpiY); #if DEBUG_KP_MAIN_WINDOW qCDebug(kpLogMainWindow) << "\t\tscaleDpi: x=" << scaleDpiX << " y=" << scaleDpiY << " --> scale at " << scaleDpi << " to fit?"; #endif // Need to increase resolution to fit page? if (scaleDpi > 1.0) { dpiX *= scaleDpi; dpiY *= scaleDpi; #if DEBUG_KP_MAIN_WINDOW qCDebug(kpLogMainWindow) << "\t\t\tto fit page, scaled to:" << " dpiX=" << dpiX << " dpiY=" << dpiY; #endif } // Make sure DPIs are equal as that's all QPrinter::setResolution() // supports. We do this in such a way that we only ever stretch an // image, to avoid losing information. Don't antialias as the printer // will do that to translate our DPI to its physical resolution and // double-antialiasing looks bad. if (dpiX > dpiY) { #if DEBUG_KP_MAIN_WINDOW qCDebug(kpLogMainWindow) << "\tdpiX > dpiY; stretching image height to equalise DPIs to dpiX=" << dpiX; #endif kpPixmapFX::scale (&image, image.width (), qMax (1, qRound (image.height () * dpiX / dpiY)), false/*don't antialias*/); dpiY = dpiX; } else if (dpiY > dpiX) { #if DEBUG_KP_MAIN_WINDOW qCDebug(kpLogMainWindow) << "\tdpiY > dpiX; stretching image width to equalise DPIs to dpiY=" << dpiY; #endif kpPixmapFX::scale (&image, qMax (1, qRound (image.width () * dpiY / dpiX)), image.height (), false/*don't antialias*/); dpiX = dpiY; } Q_ASSERT (dpiX == dpiY); // QPrinter::setResolution() has to be called before QPrinter::setup(). printer->setResolution (qMax (1, qRound (dpiX))); sendDocumentNameToPrinter (printer); if (showPrinterSetupDialog) { auto *optionsPage = new kpPrintDialogPage (this); optionsPage->setPrintImageCenteredOnPage (d->configPrintImageCenteredOnPage); QPrintDialog *printDialog = KdePrint::createPrintDialog ( printer, QList () << optionsPage, this); printDialog->setWindowTitle (i18nc ("@title:window", "Print Image")); // Display dialog. const bool wantToPrint = printDialog->exec (); if (optionsPage->printImageCenteredOnPage () != d->configPrintImageCenteredOnPage) { // Save config option even if the dialog was cancelled. d->configPrintImageCenteredOnPage = optionsPage->printImageCenteredOnPage (); KConfigGroup cfg (KSharedConfig::openConfig (), kpSettingsGroupGeneral); cfg.writeEntry (kpSettingPrintImageCenteredOnPage, d->configPrintImageCenteredOnPage); cfg.sync (); } delete printDialog; if (!wantToPrint) { return; } } // Send image to printer. QPainter painter; painter.begin(printer); double originX = 0, originY = 0; // Center image on page? if (d->configPrintImageCenteredOnPage) { originX = (printer->width() - image.width ()) / 2; originY = (printer->height() - image.height ()) / 2; } painter.drawImage(qRound(originX), qRound(originY), image); painter.end(); } //--------------------------------------------------------------------- // private slot void kpMainWindow::slotPrint () { toolEndShape (); QPrinter printer; sendImageToPrinter (&printer, true/*showPrinterSetupDialog*/); } //--------------------------------------------------------------------- // private slot void kpMainWindow::slotPrintPreview () { toolEndShape (); QPrintPreviewDialog printPreview(this); connect(&printPreview, &QPrintPreviewDialog::paintRequested, this, &kpMainWindow::sendPreviewToPrinter); printPreview.exec (); } //--------------------------------------------------------------------- // private slot void kpMainWindow::slotMail () { toolEndShape (); if (d->document->url ().isEmpty ()/*no name*/ || !d->document->isFromURL () || d->document->isModified ()/*needs to be saved*/) { int result = KMessageBox::questionYesNo (this, i18n ("You must save this image before sending it.\n" "Do you want to save it?"), QString(), KStandardGuiItem::save (), KStandardGuiItem::cancel ()); if (result == KMessageBox::Yes) { if (!save ()) { // save failed or aborted - don't email return; } } else { // don't want to save - don't email return; } } KToolInvocation::invokeMailer ( QString()/*to*/, QString()/*cc*/, QString()/*bcc*/, d->document->prettyFilename()/*subject*/, QString()/*body*/, QString()/*messageFile*/, QStringList(d->document->url().url())/*attachments*/); } //--------------------------------------------------------------------- // private bool kpMainWindow::queryCloseDocument () { toolEndShape (); if (!d->document || !d->document->isModified ()) { return true; // ok to close current doc } int result = KMessageBox::warningYesNoCancel (this, i18n ("The document \"%1\" has been modified.\n" "Do you want to save it?", d->document->prettyFilename ()), QString()/*caption*/, KStandardGuiItem::save (), KStandardGuiItem::discard ()); switch (result) { case KMessageBox::Yes: return slotSave (); // close only if save succeeds case KMessageBox::No: return true; // close without saving default: return false; // don't close current doc } } //--------------------------------------------------------------------- // private virtual [base KMainWindow] bool kpMainWindow::queryClose () { #if DEBUG_KP_MAIN_WINDOW qCDebug(kpLogMainWindow) << "kpMainWindow::queryClose()"; #endif toolEndShape (); if (!queryCloseDocument ()) { return false; } if (!queryCloseColors ()) { return false; } return true; } //--------------------------------------------------------------------- // private slot void kpMainWindow::slotClose () { toolEndShape (); if (!queryCloseDocument ()) { return; } setDocument (nullptr); } //--------------------------------------------------------------------- // private slot void kpMainWindow::slotQuit () { toolEndShape (); close (); // will call queryClose() } //--------------------------------------------------------------------- diff --git a/mainWindow/kpMainWindow_Image.cpp b/mainWindow/kpMainWindow_Image.cpp index c10c9c96..af301cec 100644 --- a/mainWindow/kpMainWindow_Image.cpp +++ b/mainWindow/kpMainWindow_Image.cpp @@ -1,625 +1,625 @@ /* 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 = ac->addAction (QStringLiteral("image_resize_scale")); d->actionResizeScale->setText (i18n ("R&esize / Scale...")); connect (d->actionResizeScale, &QAction::triggered, this, &kpMainWindow::slotResizeScale); ac->setDefaultShortcut (d->actionResizeScale, Qt::CTRL + Qt::Key_E); - d->actionCrop = ac->addAction ("image_crop"); + d->actionCrop = ac->addAction (QStringLiteral("image_crop")); d->actionCrop->setText (i18n ("Se&t as Image (Crop)")); connect (d->actionCrop, &QAction::triggered, this, &kpMainWindow::slotCrop); ac->setDefaultShortcut (d->actionCrop, Qt::CTRL + Qt::Key_T); - d->actionAutoCrop = ac->addAction ("image_auto_crop"); + d->actionAutoCrop = ac->addAction (QStringLiteral("image_auto_crop")); d->actionAutoCrop->setText (autoCropText ()); connect (d->actionAutoCrop, &QAction::triggered, this, &kpMainWindow::slotAutoCrop); ac->setDefaultShortcut (d->actionAutoCrop, Qt::CTRL + Qt::Key_U); - d->actionFlip = ac->addAction ("image_flip"); + d->actionFlip = ac->addAction (QStringLiteral("image_flip")); d->actionFlip->setText (i18n ("&Flip (upside down)")); connect (d->actionFlip, &QAction::triggered, this, &kpMainWindow::slotFlip); ac->setDefaultShortcut (d->actionFlip, Qt::CTRL + Qt::Key_F); - d->actionMirror = ac->addAction ("image_mirror"); + d->actionMirror = ac->addAction (QStringLiteral("image_mirror")); d->actionMirror->setText (i18n ("Mirror (horizontally)")); connect (d->actionMirror, &QAction::triggered, this, &kpMainWindow::slotMirror); //ac->setDefaultShortcut (d->actionMirror, Qt::CTRL + Qt::Key_M); - d->actionRotate = ac->addAction ("image_rotate"); + d->actionRotate = ac->addAction (QStringLiteral("image_rotate")); d->actionRotate->setText (i18n ("&Rotate...")); - d->actionRotate->setIcon(KDE::icon("transform-rotate")); + d->actionRotate->setIcon(KDE::icon(QStringLiteral("transform-rotate"))); connect (d->actionRotate, &QAction::triggered, this, &kpMainWindow::slotRotate); ac->setDefaultShortcut (d->actionRotate, Qt::CTRL + Qt::Key_R); - d->actionRotateLeft = ac->addAction ("image_rotate_270deg"); + d->actionRotateLeft = ac->addAction (QStringLiteral("image_rotate_270deg")); d->actionRotateLeft->setText (i18n ("Rotate &Left")); - d->actionRotateLeft->setIcon(KDE::icon("object-rotate-left")); + d->actionRotateLeft->setIcon(KDE::icon(QStringLiteral("object-rotate-left"))); connect (d->actionRotateLeft, &QAction::triggered, this, &kpMainWindow::slotRotate270); ac->setDefaultShortcut (d->actionRotateLeft, Qt::CTRL + Qt::SHIFT + Qt::Key_Left); - d->actionRotateRight = ac->addAction ("image_rotate_90deg"); + d->actionRotateRight = ac->addAction (QStringLiteral("image_rotate_90deg")); d->actionRotateRight->setText (i18n ("Rotate Righ&t")); - d->actionRotateRight->setIcon(KDE::icon("object-rotate-right")); + d->actionRotateRight->setIcon(KDE::icon(QStringLiteral("object-rotate-right"))); connect (d->actionRotateRight, &QAction::triggered, this, &kpMainWindow::slotRotate90); ac->setDefaultShortcut (d->actionRotateRight, Qt::CTRL + Qt::SHIFT + Qt::Key_Right); - d->actionSkew = ac->addAction ("image_skew"); + d->actionSkew = ac->addAction (QStringLiteral("image_skew")); d->actionSkew->setText (i18n ("S&kew...")); connect (d->actionSkew, &QAction::triggered, this, &kpMainWindow::slotSkew); ac->setDefaultShortcut (d->actionSkew, Qt::CTRL + Qt::Key_K); - d->actionConvertToBlackAndWhite = ac->addAction ("image_convert_to_black_and_white"); + d->actionConvertToBlackAndWhite = ac->addAction (QStringLiteral("image_convert_to_black_and_white")); d->actionConvertToBlackAndWhite->setText (i18n ("Reduce to Mo&nochrome (Dithered)")); connect (d->actionConvertToBlackAndWhite, &QAction::triggered, this, &kpMainWindow::slotConvertToBlackAndWhite); - d->actionConvertToGrayscale = ac->addAction ("image_convert_to_grayscale"); + d->actionConvertToGrayscale = ac->addAction (QStringLiteral("image_convert_to_grayscale")); d->actionConvertToGrayscale->setText (i18n ("Reduce to &Grayscale")); connect (d->actionConvertToGrayscale, &QAction::triggered, this, &kpMainWindow::slotConvertToGrayscale); - d->actionInvertColors = ac->addAction ("image_invert_colors"); + d->actionInvertColors = ac->addAction (QStringLiteral("image_invert_colors")); d->actionInvertColors->setText (i18n ("&Invert Colors")); connect (d->actionInvertColors, &QAction::triggered, this, &kpMainWindow::slotInvertColors); ac->setDefaultShortcut (d->actionInvertColors, Qt::CTRL + Qt::Key_I); - d->actionClear = ac->addAction ("image_clear"); + d->actionClear = ac->addAction (QStringLiteral("image_clear")); d->actionClear->setText (i18n ("C&lear")); connect (d->actionClear, &QAction::triggered, this, &kpMainWindow::slotClear); ac->setDefaultShortcut (d->actionClear, Qt::CTRL + Qt::SHIFT + Qt::Key_N); - d->actionBlur = ac->addAction("image_make_confidential"); + d->actionBlur = ac->addAction(QStringLiteral("image_make_confidential")); d->actionBlur->setText(i18n("Make Confidential")); connect(d->actionBlur, &QAction::triggered, this, &kpMainWindow::slotMakeConfidential); - d->actionMoreEffects = ac->addAction ("image_more_effects"); + d->actionMoreEffects = ac->addAction (QStringLiteral("image_more_effects")); d->actionMoreEffects->setText (i18n ("&More Effects...")); connect (d->actionMoreEffects, &QAction::triggered, this, &kpMainWindow::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 ()); for (auto *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; } 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; #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); #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 ()) { auto *imageSel = dynamic_cast (sel); auto *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 ()) { auto *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 (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 (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 (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_Settings.cpp b/mainWindow/kpMainWindow_Settings.cpp index 8556334b..8eb1afd0 100644 --- a/mainWindow/kpMainWindow_Settings.cpp +++ b/mainWindow/kpMainWindow_Settings.cpp @@ -1,160 +1,160 @@ /* 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 #include "kpDefs.h" #include "document/kpDocument.h" #include "tools/kpToolAction.h" #include "widgets/toolbars/kpToolToolBar.h" #include "environments/tools/kpToolEnvironment.h" //--------------------------------------------------------------------- // private void kpMainWindow::setupSettingsMenuActions () { KActionCollection *ac = actionCollection (); // Settings/Toolbars |> %s setStandardToolBarMenuEnabled (true); // Settings/Show Statusbar createStandardStatusBarAction (); d->actionFullScreen = KStandardAction::fullScreen (this, SLOT (slotFullScreen()), this/*window*/, ac); - d->actionShowPath = ac->add ("settings_show_path"); + d->actionShowPath = ac->add (QStringLiteral("settings_show_path")); d->actionShowPath->setText (i18n ("Show &Path")); connect (d->actionShowPath, &QAction::triggered, this, &kpMainWindow::slotShowPathToggled); slotEnableSettingsShowPath (); - auto *action = ac->add("settings_draw_antialiased"); + auto *action = ac->add(QStringLiteral("settings_draw_antialiased")); action->setText(i18n("Draw Anti-Aliased")); action->setChecked(kpToolEnvironment::drawAntiAliased); connect (action, &KToggleAction::triggered, this, &kpMainWindow::slotDrawAntiAliasedToggled); d->actionKeyBindings = KStandardAction::keyBindings (this, SLOT (slotKeyBindings()), ac); KStandardAction::configureToolbars(this, SLOT(configureToolbars()), actionCollection()); enableSettingsMenuDocumentActions (false); } //--------------------------------------------------------------------- // private void kpMainWindow::enableSettingsMenuDocumentActions (bool /*enable*/) { } //--------------------------------------------------------------------- // private slot void kpMainWindow::slotFullScreen () { KToggleFullScreenAction::setFullScreen( this, d->actionFullScreen->isChecked ()); } //--------------------------------------------------------------------- // private slot void kpMainWindow::slotEnableSettingsShowPath () { #if DEBUG_KP_MAIN_WINDOW qCDebug(kpLogMainWindow) << "kpMainWindow::slotEnableSettingsShowPath()"; #endif const bool enable = (d->document && !d->document->url ().isEmpty ()); d->actionShowPath->setEnabled (enable); d->actionShowPath->setChecked (enable && d->configShowPath); } //--------------------------------------------------------------------- // private slot void kpMainWindow::slotShowPathToggled () { #if DEBUG_KP_MAIN_WINDOW qCDebug(kpLogMainWindow) << "kpMainWindow::slotShowPathToggled()"; #endif d->configShowPath = d->actionShowPath->isChecked (); slotUpdateCaption (); KConfigGroup cfg (KSharedConfig::openConfig (), kpSettingsGroupGeneral); cfg.writeEntry (kpSettingShowPath, d->configShowPath); cfg.sync (); } //--------------------------------------------------------------------- void kpMainWindow::slotDrawAntiAliasedToggled(bool on) { kpToolEnvironment::drawAntiAliased = on; KConfigGroup cfg(KSharedConfig::openConfig(), kpSettingsGroupGeneral); cfg.writeEntry(kpSettingDrawAntiAliased, kpToolEnvironment::drawAntiAliased); cfg.sync(); } //--------------------------------------------------------------------- // private slot void kpMainWindow::slotKeyBindings () { toolEndShape (); if (KShortcutsDialog::configure (actionCollection (), KShortcutsEditor::LetterShortcutsAllowed, this)) { // TODO: PROPAGATE: thru mainWindow's and interprocess } } //--------------------------------------------------------------------- diff --git a/mainWindow/kpMainWindow_Text.cpp b/mainWindow/kpMainWindow_Text.cpp index bce89c91..abdc7229 100644 --- a/mainWindow/kpMainWindow_Text.cpp +++ b/mainWindow/kpMainWindow_Text.cpp @@ -1,436 +1,436 @@ /* 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 #include #include #include "kpLogCategories.h" #include #include #include #include #include #include #include "widgets/toolbars/kpColorToolBar.h" #include "kpDefs.h" #include "layers/selections/text/kpTextStyle.h" #include "tools/selection/text/kpToolText.h" #include "widgets/toolbars/kpToolToolBar.h" #include "widgets/toolbars/options/kpToolWidgetOpaqueOrTransparent.h" #include "views/kpZoomedView.h" // private void kpMainWindow::setupTextToolBarActions () { KActionCollection *ac = actionCollection (); - d->actionTextFontFamily = ac->add ("text_font_family"); + d->actionTextFontFamily = ac->add (QStringLiteral("text_font_family")); d->actionTextFontFamily->setText (i18n ("Font Family")); connect (d->actionTextFontFamily, static_cast(&KFontAction::triggered), this, &kpMainWindow::slotTextFontFamilyChanged); - d->actionTextFontSize = ac->add ("text_font_size"); + d->actionTextFontSize = ac->add (QStringLiteral("text_font_size")); d->actionTextFontSize->setText (i18n ("Font Size")); connect (d->actionTextFontSize, static_cast(&KFontSizeAction::triggered), this, &kpMainWindow::slotTextFontSizeChanged); - d->actionTextBold = ac->add ("text_bold"); - d->actionTextBold->setIcon(KDE::icon("format-text-bold")); + d->actionTextBold = ac->add (QStringLiteral("text_bold")); + d->actionTextBold->setIcon(KDE::icon(QStringLiteral("format-text-bold"))); d->actionTextBold->setText (i18n ("Bold")); connect (d->actionTextBold, &KToggleAction::triggered, this, &kpMainWindow::slotTextBoldChanged); - d->actionTextItalic = ac->add ("text_italic"); - d->actionTextItalic->setIcon (KDE::icon("format-text-italic")); + d->actionTextItalic = ac->add (QStringLiteral("text_italic")); + d->actionTextItalic->setIcon (KDE::icon(QStringLiteral("format-text-italic"))); d->actionTextItalic->setText (i18n ("Italic")); connect (d->actionTextItalic, &KToggleAction::triggered, this, &kpMainWindow::slotTextItalicChanged); - d->actionTextUnderline = ac->add ("text_underline"); - d->actionTextUnderline->setIcon (KDE::icon("format-text-underline")); + d->actionTextUnderline = ac->add (QStringLiteral("text_underline")); + d->actionTextUnderline->setIcon (KDE::icon(QStringLiteral("format-text-underline"))); d->actionTextUnderline->setText (i18n ("Underline")); connect (d->actionTextUnderline, &KToggleAction::triggered, this, &kpMainWindow::slotTextUnderlineChanged); - d->actionTextStrikeThru = ac->add ("text_strike_thru"); - d->actionTextStrikeThru->setIcon(KDE::icon("format-text-strikethrough")); + d->actionTextStrikeThru = ac->add (QStringLiteral("text_strike_thru")); + d->actionTextStrikeThru->setIcon(KDE::icon(QStringLiteral("format-text-strikethrough"))); d->actionTextStrikeThru->setText (i18n ("Strike Through")); connect (d->actionTextStrikeThru, &KToggleAction::triggered, this, &kpMainWindow::slotTextStrikeThruChanged); readAndApplyTextSettings (); enableTextToolBarActions (false); } // private void kpMainWindow::readAndApplyTextSettings () { KConfigGroup cfg (KSharedConfig::openConfig (), kpSettingsGroupText); - const QString font (cfg.readEntry (kpSettingFontFamily, QString::fromLatin1 ("Times"))); + const QString font (cfg.readEntry (kpSettingFontFamily, QStringLiteral ("Times"))); d->actionTextFontFamily->setFont (font); #if DEBUG_KP_MAIN_WINDOW qCDebug(kpLogMainWindow) << "asked setFont to set to=" << font << "- got back=" << d->actionTextFontFamily->font (); #endif d->actionTextFontSize->setFontSize (cfg.readEntry (kpSettingFontSize, 14)); d->actionTextBold->setChecked (cfg.readEntry (kpSettingBold, false)); d->actionTextItalic->setChecked (cfg.readEntry (kpSettingItalic, false)); d->actionTextUnderline->setChecked (cfg.readEntry (kpSettingUnderline, false)); d->actionTextStrikeThru->setChecked (cfg.readEntry (kpSettingStrikeThru, false)); d->textOldFontFamily = d->actionTextFontFamily->font (); d->textOldFontSize = d->actionTextFontSize->fontSize (); } // public void kpMainWindow::enableTextToolBarActions (bool enable) { #if DEBUG_KP_MAIN_WINDOW qCDebug(kpLogMainWindow) << "kpMainWindow::enableTextToolBarActions(" << enable << ")"; #endif d->actionTextFontFamily->setEnabled (enable); d->actionTextFontSize->setEnabled (enable); d->actionTextBold->setEnabled (enable); d->actionTextItalic->setEnabled (enable); d->actionTextUnderline->setEnabled (enable); d->actionTextStrikeThru->setEnabled (enable); if (textToolBar ()) { #if DEBUG_KP_MAIN_WINDOW qCDebug(kpLogMainWindow) << "\thave toolbar - setShown"; #endif // COMPAT: KDE4 does not place the Text Tool Bar in a new row, underneath // the Main Tool Bar, if there isn't enough room. This makes // accessing the Text Tool Bar's buttons difficult. textToolBar ()->setVisible (enable); } } // private slot void kpMainWindow::slotTextFontFamilyChanged () { #if DEBUG_KP_MAIN_WINDOW qCDebug(kpLogMainWindow) << "kpMainWindow::slotTextFontFamilyChanged() alive=" << d->isFullyConstructed << "fontFamily=" << d->actionTextFontFamily->font () << "action.currentItem=" << d->actionTextFontFamily->currentItem (); #endif if (!d->isFullyConstructed) { return; } if (d->toolText && d->toolText->hasBegun ()) { toolEndShape (); d->toolText->slotFontFamilyChanged (d->actionTextFontFamily->font (), d->textOldFontFamily); } // Since editable KSelectAction's steal focus from view, switch back to mainView // TODO: back to the last view if (d->mainView) { d->mainView->setFocus (); } KConfigGroup cfg (KSharedConfig::openConfig (), kpSettingsGroupText); cfg.writeEntry (kpSettingFontFamily, d->actionTextFontFamily->font ()); cfg.sync (); d->textOldFontFamily = d->actionTextFontFamily->font (); } // private slot void kpMainWindow::slotTextFontSizeChanged () { #if DEBUG_KP_MAIN_WINDOW qCDebug(kpLogMainWindow) << "kpMainWindow::slotTextFontSizeChanged() alive=" << d->isFullyConstructed << " fontSize=" << d->actionTextFontSize->fontSize (); #endif if (!d->isFullyConstructed) { return; } if (d->toolText && d->toolText->hasBegun ()) { toolEndShape (); d->toolText->slotFontSizeChanged (d->actionTextFontSize->fontSize (), d->textOldFontSize); } // Since editable KSelectAction's steal focus from view, switch back to mainView // TODO: back to the last view if (d->mainView) { d->mainView->setFocus (); } KConfigGroup cfg (KSharedConfig::openConfig (), kpSettingsGroupText); cfg.writeEntry (kpSettingFontSize, d->actionTextFontSize->fontSize ()); cfg.sync (); d->textOldFontSize = d->actionTextFontSize->fontSize (); } // private slot void kpMainWindow::slotTextBoldChanged () { #if DEBUG_KP_MAIN_WINDOW qCDebug(kpLogMainWindow) << "kpMainWindow::slotTextFontBoldChanged() alive=" << d->isFullyConstructed << " bold=" << d->actionTextBold->isChecked (); #endif if (!d->isFullyConstructed) { return; } if (d->toolText && d->toolText->hasBegun ()) { toolEndShape (); d->toolText->slotBoldChanged (d->actionTextBold->isChecked ()); } KConfigGroup cfg (KSharedConfig::openConfig (), kpSettingsGroupText); cfg.writeEntry (kpSettingBold, d->actionTextBold->isChecked ()); cfg.sync (); } // private slot void kpMainWindow::slotTextItalicChanged () { #if DEBUG_KP_MAIN_WINDOW qCDebug(kpLogMainWindow) << "kpMainWindow::slotTextFontItalicChanged() alive=" << d->isFullyConstructed << " bold=" << d->actionTextItalic->isChecked (); #endif if (!d->isFullyConstructed) { return; } if (d->toolText && d->toolText->hasBegun ()) { toolEndShape (); d->toolText->slotItalicChanged (d->actionTextItalic->isChecked ()); } KConfigGroup cfg (KSharedConfig::openConfig (), kpSettingsGroupText); cfg.writeEntry (kpSettingItalic, d->actionTextItalic->isChecked ()); cfg.sync (); } // private slot void kpMainWindow::slotTextUnderlineChanged () { #if DEBUG_KP_MAIN_WINDOW qCDebug(kpLogMainWindow) << "kpMainWindow::slotTextFontUnderlineChanged() alive=" << d->isFullyConstructed << " underline=" << d->actionTextUnderline->isChecked (); #endif if (!d->isFullyConstructed) { return; } if (d->toolText && d->toolText->hasBegun ()) { toolEndShape (); d->toolText->slotUnderlineChanged (d->actionTextUnderline->isChecked ()); } KConfigGroup cfg (KSharedConfig::openConfig (), kpSettingsGroupText); cfg.writeEntry (kpSettingUnderline, d->actionTextUnderline->isChecked ()); cfg.sync (); } // private slot void kpMainWindow::slotTextStrikeThruChanged () { #if DEBUG_KP_MAIN_WINDOW qCDebug(kpLogMainWindow) << "kpMainWindow::slotTextStrikeThruChanged() alive=" << d->isFullyConstructed << " strikeThru=" << d->actionTextStrikeThru->isChecked (); #endif if (!d->isFullyConstructed) { return; } if (d->toolText && d->toolText->hasBegun ()) { toolEndShape (); d->toolText->slotStrikeThruChanged (d->actionTextStrikeThru->isChecked ()); } KConfigGroup cfg (KSharedConfig::openConfig (), kpSettingsGroupText); cfg.writeEntry (kpSettingStrikeThru, d->actionTextStrikeThru->isChecked ()); cfg.sync (); } // public KToolBar *kpMainWindow::textToolBar () { - return toolBar ("textToolBar"); + return toolBar (QStringLiteral("textToolBar")); } bool kpMainWindow::isTextStyleBackgroundOpaque () const { if (d->toolToolBar) { kpToolWidgetOpaqueOrTransparent *oot = d->toolToolBar->toolWidgetOpaqueOrTransparent (); if (oot) { return oot->isOpaque (); } } return true; } // public kpTextStyle kpMainWindow::textStyle () const { return kpTextStyle (d->actionTextFontFamily->font (), d->actionTextFontSize->fontSize (), d->actionTextBold->isChecked (), d->actionTextItalic->isChecked (), d->actionTextUnderline->isChecked (), d->actionTextStrikeThru->isChecked (), d->colorToolBar ? d->colorToolBar->foregroundColor () : kpColor::Invalid, d->colorToolBar ? d->colorToolBar->backgroundColor () : kpColor::Invalid, isTextStyleBackgroundOpaque ()); } // public void kpMainWindow::setTextStyle (const kpTextStyle &textStyle_) { #if DEBUG_KP_MAIN_WINDOW qCDebug(kpLogMainWindow) << "kpMainWindow::setTextStyle()"; #endif d->settingTextStyle++; if (textStyle_.fontFamily () != d->actionTextFontFamily->font ()) { d->actionTextFontFamily->setFont (textStyle_.fontFamily ()); slotTextFontFamilyChanged (); } if (textStyle_.fontSize () != d->actionTextFontSize->fontSize ()) { d->actionTextFontSize->setFontSize (textStyle_.fontSize ()); slotTextFontSizeChanged (); } if (textStyle_.isBold () != d->actionTextBold->isChecked ()) { d->actionTextBold->setChecked (textStyle_.isBold ()); slotTextBoldChanged (); } if (textStyle_.isItalic () != d->actionTextItalic->isChecked ()) { d->actionTextItalic->setChecked (textStyle_.isItalic ()); slotTextItalicChanged (); } if (textStyle_.isUnderline () != d->actionTextUnderline->isChecked ()) { d->actionTextUnderline->setChecked (textStyle_.isUnderline ()); slotTextUnderlineChanged (); } if (textStyle_.isStrikeThru () != d->actionTextStrikeThru->isChecked ()) { d->actionTextStrikeThru->setChecked (textStyle_.isStrikeThru ()); slotTextStrikeThruChanged (); } if (textStyle_.foregroundColor () != d->colorToolBar->foregroundColor ()) { d->colorToolBar->setForegroundColor (textStyle_.foregroundColor ()); } if (textStyle_.backgroundColor () != d->colorToolBar->backgroundColor ()) { d->colorToolBar->setBackgroundColor (textStyle_.backgroundColor ()); } if (textStyle_.isBackgroundOpaque () != isTextStyleBackgroundOpaque ()) { if (d->toolToolBar) { kpToolWidgetOpaqueOrTransparent *oot = d->toolToolBar->toolWidgetOpaqueOrTransparent (); if (oot) { oot->setOpaque (textStyle_.isBackgroundOpaque ()); } } } d->settingTextStyle--; } // public int kpMainWindow::settingTextStyle () const { return d->settingTextStyle; } diff --git a/mainWindow/kpMainWindow_Tools.cpp b/mainWindow/kpMainWindow_Tools.cpp index 776a9033..a191761d 100644 --- a/mainWindow/kpMainWindow_Tools.cpp +++ b/mainWindow/kpMainWindow_Tools.cpp @@ -1,834 +1,834 @@ /* 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 = ac->addAction (QStringLiteral("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, &QAction::triggered, this, &kpMainWindow::slotActionPrevToolOptionGroup1); - d->actionNextToolOptionGroup1 = ac->addAction ("next_tool_option_group_1"); + d->actionNextToolOptionGroup1 = ac->addAction (QStringLiteral("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, &QAction::triggered, this, &kpMainWindow::slotActionNextToolOptionGroup1); - d->actionPrevToolOptionGroup2 = ac->addAction ("prev_tool_option_group_2"); + d->actionPrevToolOptionGroup2 = ac->addAction (QStringLiteral("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, &QAction::triggered, this, &kpMainWindow::slotActionPrevToolOptionGroup2); - d->actionNextToolOptionGroup2 = ac->addAction ("next_tool_option_group_2"); + d->actionNextToolOptionGroup2 = ac->addAction (QStringLiteral("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, &QAction::triggered, this, &kpMainWindow::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 = ac->add (QStringLiteral("image_draw_opaque")); d->actionDrawOpaque->setText (i18n ("&Draw Opaque")); connect (d->actionDrawOpaque, &QAction::triggered, this, &kpMainWindow::slotActionDrawOpaqueToggled); - d->actionDrawColorSimilarity = ac->addAction ("image_draw_color_similarity"); + d->actionDrawColorSimilarity = ac->addAction (QStringLiteral("image_draw_color_similarity")); d->actionDrawColorSimilarity->setText (i18n ("Draw With Color Similarity...")); connect (d->actionDrawColorSimilarity, &QAction::triggered, this, &kpMainWindow::slotActionDrawColorSimilarity); } //--------------------------------------------------------------------- // private void kpMainWindow::createToolBox () { - d->toolToolBar = new kpToolToolBar(QLatin1String("Tool Box"), 2/*columns/rows*/, this); + d->toolToolBar = new kpToolToolBar(QStringLiteral("Tool Box"), 2/*columns/rows*/, this); d->toolToolBar->setWindowTitle(i18n("Tool Box")); connect (d->toolToolBar, &kpToolToolBar::sigToolSelected, this, &kpMainWindow::slotToolSelected); connect (d->toolToolBar, &kpToolToolBar::toolWidgetOptionSelected, this, &kpMainWindow::updateToolOptionPrevNextActionsEnabled); connect (d->toolToolBar->toolWidgetOpaqueOrTransparent(), &kpToolWidgetOpaqueOrTransparent::isOpaqueChanged, this, &kpMainWindow::updateActionDrawOpaqueChecked); updateActionDrawOpaqueChecked (); for (auto *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 < 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); for (auto *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 () : nullptr) << " (is selection=" << toolIsASelectionTool () << ")"; #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 () : nullptr) << " forceColorChange=" << forceColorChange; #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, &kpTool::movedAndAboutToDraw, this, &kpMainWindow::slotDragScroll); disconnect (previousTool, &kpTool::endedDraw, this, &kpMainWindow::slotEndDragScroll); disconnect (previousTool, &kpTool::cancelledShape, this, &kpMainWindow::slotEndDragScroll); disconnect (previousTool, &kpTool::userMessageChanged, this, &kpMainWindow::recalculateStatusBarMessage); disconnect (previousTool, &kpTool::userShapePointsChanged, this, &kpMainWindow::recalculateStatusBarShape); disconnect (previousTool, &kpTool::userShapeSizeChanged, this, &kpMainWindow::recalculateStatusBarShape); disconnect (d->colorToolBar, &kpColorToolBar::colorsSwapped, previousTool, &kpTool::slotColorsSwappedInternal); disconnect (d->colorToolBar, &kpColorToolBar::foregroundColorChanged, previousTool, &kpTool::slotForegroundColorChangedInternal); disconnect (d->colorToolBar, &kpColorToolBar::backgroundColorChanged, previousTool, &kpTool::slotBackgroundColorChangedInternal); disconnect (d->colorToolBar, &kpColorToolBar::colorSimilarityChanged, previousTool, &kpTool::slotColorSimilarityChangedInternal); } if (tool) { connect (tool, &kpTool::movedAndAboutToDraw, this, &kpMainWindow::slotDragScroll); connect (tool, &kpTool::endedDraw, this, &kpMainWindow::slotEndDragScroll); connect (tool, &kpTool::cancelledShape, this, &kpMainWindow::slotEndDragScroll); connect (tool, &kpTool::userMessageChanged, this, &kpMainWindow::recalculateStatusBarMessage); connect (tool, &kpTool::userShapePointsChanged, this, &kpMainWindow::recalculateStatusBarShape); connect (tool, &kpTool::userShapeSizeChanged, this, &kpMainWindow::recalculateStatusBarShape); recalculateStatusBar (); connect (d->colorToolBar, &kpColorToolBar::colorsSwapped, tool, &kpTool::slotColorsSwappedInternal); connect (d->colorToolBar, &kpColorToolBar::foregroundColorChanged, tool, &kpTool::slotForegroundColorChangedInternal); connect (d->colorToolBar, &kpColorToolBar::backgroundColorChanged, tool, &kpTool::slotBackgroundColorChangedInternal); connect (d->colorToolBar, &kpColorToolBar::colorSimilarityChanged, tool, &kpTool::slotColorSimilarityChangedInternal); 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 >= 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 (); #endif if (maybeDragScrollingMainView ()) { return d->scrollView->beginDragScroll(zoomLevel, scrolled); } 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; #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.cpp b/mainWindow/kpMainWindow_View.cpp index e7dc2ef1..ad426d9c 100644 --- a/mainWindow/kpMainWindow_View.cpp +++ b/mainWindow/kpMainWindow_View.cpp @@ -1,163 +1,163 @@ /* 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 "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" // private void kpMainWindow::setupViewMenuActions () { KActionCollection *ac = actionCollection (); /*d->actionFullScreen = KStandardAction::fullScreen (0, 0, ac); d->actionFullScreen->setEnabled (false);*/ setupViewMenuZoomActions (); - d->actionShowGrid = ac->add ("view_show_grid"); + d->actionShowGrid = ac->add (QStringLiteral("view_show_grid")); d->actionShowGrid->setText (i18n ("Show &Grid")); ac->setDefaultShortcut (d->actionShowGrid, Qt::CTRL + Qt::Key_G); //d->actionShowGrid->setCheckedState (KGuiItem(i18n ("Hide &Grid"))); connect (d->actionShowGrid, &KToggleAction::triggered, this, &kpMainWindow::slotShowGridToggled); setupViewMenuThumbnailActions (); enableViewMenuDocumentActions (false); } //--------------------------------------------------------------------- // private bool kpMainWindow::viewMenuDocumentActionsEnabled () const { return d->viewMenuDocumentActionsEnabled; } //--------------------------------------------------------------------- // private void kpMainWindow::enableViewMenuDocumentActions (bool enable) { d->viewMenuDocumentActionsEnabled = enable; enableViewMenuZoomDocumentActions (enable); actionShowGridUpdate (); enableViewMenuThumbnailDocumentActions (enable); } //--------------------------------------------------------------------- // private void kpMainWindow::actionShowGridUpdate () { #if DEBUG_KP_MAIN_WINDOW qCDebug(kpLogMainWindow) << "kpMainWindow::actionShowGridUpdate()"; #endif const bool enable = (viewMenuDocumentActionsEnabled () && d->mainView && d->mainView->canShowGrid ()); d->actionShowGrid->setEnabled (enable); d->actionShowGrid->setChecked (enable && d->configShowGrid); } //--------------------------------------------------------------------- // private slot void kpMainWindow::slotShowGridToggled () { #if DEBUG_KP_MAIN_WINDOW qCDebug(kpLogMainWindow) << "kpMainWindow::slotActionShowGridToggled()"; #endif updateMainViewGrid (); KConfigGroup cfg (KSharedConfig::openConfig (), kpSettingsGroupGeneral); cfg.writeEntry (kpSettingShowGrid, d->configShowGrid = d->actionShowGrid->isChecked ()); cfg.sync (); } //--------------------------------------------------------------------- // private void kpMainWindow::updateMainViewGrid () { #if DEBUG_KP_MAIN_WINDOW qCDebug(kpLogMainWindow) << "kpMainWindow::updateMainViewGrid ()"; #endif if (d->mainView) { d->mainView->showGrid (d->actionShowGrid->isChecked ()); } } //--------------------------------------------------------------------- // private QRect kpMainWindow::mapToGlobal (const QRect &rect) const { return kpWidgetMapper::toGlobal (this, rect); } //--------------------------------------------------------------------- // private QRect kpMainWindow::mapFromGlobal (const QRect &rect) const { return kpWidgetMapper::fromGlobal (this, rect); } //--------------------------------------------------------------------- diff --git a/mainWindow/kpMainWindow_View_Thumbnail.cpp b/mainWindow/kpMainWindow_View_Thumbnail.cpp index 608f80c1..3cae287f 100644 --- a/mainWindow/kpMainWindow_View_Thumbnail.cpp +++ b/mainWindow/kpMainWindow_View_Thumbnail.cpp @@ -1,479 +1,479 @@ /* 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" // private void kpMainWindow::setupViewMenuThumbnailActions () { d->thumbnailSaveConfigTimer = nullptr; KActionCollection *ac = actionCollection (); - d->actionShowThumbnail = ac->add ("view_show_thumbnail"); + d->actionShowThumbnail = ac->add (QStringLiteral("view_show_thumbnail")); d->actionShowThumbnail->setText (i18n ("Show T&humbnail")); // TODO: This doesn't work when the thumbnail has focus. // Testcase: Press CTRL+H twice on a fresh KolourPaint. // The second CTRL+H doesn't close the thumbnail. ac->setDefaultShortcut (d->actionShowThumbnail, Qt::CTRL + Qt::Key_H); //d->actionShowThumbnail->setCheckedState (KGuiItem(i18n ("Hide T&humbnail"))); connect (d->actionShowThumbnail, &KToggleAction::triggered, this, &kpMainWindow::slotShowThumbnailToggled); // Please do not use setCheckedState() here - it wouldn't make sense - d->actionZoomedThumbnail = ac->add ("view_zoomed_thumbnail"); + d->actionZoomedThumbnail = ac->add (QStringLiteral("view_zoomed_thumbnail")); d->actionZoomedThumbnail->setText (i18n ("Zoo&med Thumbnail Mode")); connect (d->actionZoomedThumbnail, &KToggleAction::triggered, this, &kpMainWindow::slotZoomedThumbnailToggled); // For consistency with the above action, don't use setCheckedState() // // Also, don't use "Show Thumbnail Rectangle" because if entire doc // can be seen in scrollView, checking option won't "Show" anything // since rect _surrounds_ entire doc (hence, won't be rendered). - d->actionShowThumbnailRectangle = ac->add ("view_show_thumbnail_rectangle"); + d->actionShowThumbnailRectangle = ac->add (QStringLiteral("view_show_thumbnail_rectangle")); d->actionShowThumbnailRectangle->setText (i18n ("Enable Thumbnail &Rectangle")); connect (d->actionShowThumbnailRectangle, &KToggleAction::triggered, this, &kpMainWindow::slotThumbnailShowRectangleToggled); } // private void kpMainWindow::enableViewMenuThumbnailDocumentActions (bool enable) { d->actionShowThumbnail->setEnabled (enable); enableThumbnailOptionActions (enable); } // private slot void kpMainWindow::slotDestroyThumbnail () { #if DEBUG_KP_MAIN_WINDOW qCDebug(kpLogMainWindow) << "kpMainWindow::slotDestroyThumbnail()"; #endif d->actionShowThumbnail->setChecked (false); enableThumbnailOptionActions (false); updateThumbnail (); } // private slot void kpMainWindow::slotDestroyThumbnailInitatedByUser () { #if DEBUG_KP_MAIN_WINDOW qCDebug(kpLogMainWindow) << "kpMainWindow::slotDestroyThumbnailInitiatedByUser()"; #endif d->actionShowThumbnail->setChecked (false); slotShowThumbnailToggled (); } // private slot void kpMainWindow::slotCreateThumbnail () { #if DEBUG_KP_MAIN_WINDOW qCDebug(kpLogMainWindow) << "kpMainWindow::slotCreateThumbnail()"; #endif d->actionShowThumbnail->setChecked (true); enableThumbnailOptionActions (true); updateThumbnail (); } // public void kpMainWindow::notifyThumbnailGeometryChanged () { #if DEBUG_KP_MAIN_WINDOW qCDebug(kpLogMainWindow) << "kpMainWindow::notifyThumbnailGeometryChanged()"; #endif if (!d->thumbnailSaveConfigTimer) { d->thumbnailSaveConfigTimer = new QTimer (this); d->thumbnailSaveConfigTimer->setSingleShot (true); connect (d->thumbnailSaveConfigTimer, &QTimer::timeout, this, &kpMainWindow::slotSaveThumbnailGeometry); } // (single shot) d->thumbnailSaveConfigTimer->start (500/*msec*/); } // private slot void kpMainWindow::slotSaveThumbnailGeometry () { #if DEBUG_KP_MAIN_WINDOW qCDebug(kpLogMainWindow) << "kpMainWindow::saveThumbnailGeometry()"; #endif if (!d->thumbnail) { return; } QRect rect (d->thumbnail->x (), d->thumbnail->y (), d->thumbnail->width (), d->thumbnail->height ()); #if DEBUG_KP_MAIN_WINDOW qCDebug(kpLogMainWindow) << "\tthumbnail relative geometry=" << rect; #endif d->configThumbnailGeometry = mapFromGlobal (rect); #if DEBUG_KP_MAIN_WINDOW qCDebug(kpLogMainWindow) << "\tCONFIG: saving thumbnail geometry " << d->configThumbnailGeometry; #endif KConfigGroup cfg (KSharedConfig::openConfig (), kpSettingsGroupThumbnail); cfg.writeEntry (kpSettingThumbnailGeometry, d->configThumbnailGeometry); cfg.sync (); } // private slot void kpMainWindow::slotShowThumbnailToggled () { #if DEBUG_KP_MAIN_WINDOW qCDebug(kpLogMainWindow) << "kpMainWindow::slotShowThumbnailToggled()"; #endif d->configThumbnailShown = d->actionShowThumbnail->isChecked (); KConfigGroup cfg (KSharedConfig::openConfig (), kpSettingsGroupThumbnail); cfg.writeEntry (kpSettingThumbnailShown, d->configThumbnailShown); cfg.sync (); enableThumbnailOptionActions (d->actionShowThumbnail->isChecked ()); updateThumbnail (); } // private slot void kpMainWindow::updateThumbnailZoomed () { #if DEBUG_KP_MAIN_WINDOW qCDebug(kpLogMainWindow) << "kpMainWindow::updateThumbnailZoomed() zoomed=" << d->actionZoomedThumbnail->isChecked (); #endif if (!d->thumbnailView) { return; } destroyThumbnailView (); createThumbnailView (); } // private slot void kpMainWindow::slotZoomedThumbnailToggled () { #if DEBUG_KP_MAIN_WINDOW qCDebug(kpLogMainWindow) << "kpMainWindow::slotZoomedThumbnailToggled()"; #endif d->configZoomedThumbnail = d->actionZoomedThumbnail->isChecked (); KConfigGroup cfg (KSharedConfig::openConfig (), kpSettingsGroupThumbnail); cfg.writeEntry (kpSettingThumbnailZoomed, d->configZoomedThumbnail); cfg.sync (); updateThumbnailZoomed (); } // private slot void kpMainWindow::slotThumbnailShowRectangleToggled () { #if DEBUG_KP_MAIN_WINDOW qCDebug(kpLogMainWindow) << "kpMainWindow::slotThumbnailShowRectangleToggled()"; #endif d->configThumbnailShowRectangle = d->actionShowThumbnailRectangle->isChecked (); KConfigGroup cfg (KSharedConfig::openConfig (), kpSettingsGroupThumbnail); cfg.writeEntry (kpSettingThumbnailShowRectangle, d->configThumbnailShowRectangle); cfg.sync (); if (d->thumbnailView) { d->thumbnailView->showBuddyViewScrollableContainerRectangle ( d->actionShowThumbnailRectangle->isChecked ()); } } // private void kpMainWindow::enableViewZoomedThumbnail (bool enable) { #if DEBUG_KP_MAIN_WINDOW qCDebug(kpLogMainWindow) << "kpMainWindow::enableSettingsViewZoomedThumbnail()"; #endif d->actionZoomedThumbnail->setEnabled (enable && d->actionShowThumbnail->isChecked ()); // Note: Don't uncheck if disabled - being able to see the zoomed state // before turning on the thumbnail can be useful. d->actionZoomedThumbnail->setChecked (d->configZoomedThumbnail); } // private void kpMainWindow::enableViewShowThumbnailRectangle (bool enable) { #if DEBUG_KP_MAIN_WINDOW qCDebug(kpLogMainWindow) << "kpMainWindow::enableViewShowThumbnailRectangle()"; #endif d->actionShowThumbnailRectangle->setEnabled (enable && d->actionShowThumbnail->isChecked ()); // Note: Don't uncheck if disabled for consistency with // enableViewZoomedThumbnail() d->actionShowThumbnailRectangle->setChecked ( d->configThumbnailShowRectangle); } // private void kpMainWindow::enableThumbnailOptionActions (bool enable) { enableViewZoomedThumbnail (enable); enableViewShowThumbnailRectangle (enable); } // private void kpMainWindow::createThumbnailView () { #if DEBUG_KP_MAIN_WINDOW qCDebug(kpLogMainWindow) << "\t\tcreating new kpView:"; #endif if (d->thumbnailView) { qCDebug(kpLogMainWindow) << "kpMainWindow::createThumbnailView() had to destroy view"; destroyThumbnailView (); } if (d->actionZoomedThumbnail->isChecked ()) { d->thumbnailView = new kpZoomedThumbnailView ( d->document, d->toolToolBar, d->viewManager, d->mainView, nullptr/*scrollableContainer*/, d->thumbnail); - d->thumbnailView->setObjectName ( QLatin1String("thumbnailView" )); + d->thumbnailView->setObjectName ( QStringLiteral("thumbnailView" )); } else { d->thumbnailView = new kpUnzoomedThumbnailView ( d->document, d->toolToolBar, d->viewManager, d->mainView, nullptr/*scrollableContainer*/, d->thumbnail); - d->thumbnailView->setObjectName ( QLatin1String("thumbnailView" )); + d->thumbnailView->setObjectName ( QStringLiteral("thumbnailView" )); } d->thumbnailView->showBuddyViewScrollableContainerRectangle ( d->actionShowThumbnailRectangle->isChecked ()); #if DEBUG_KP_MAIN_WINDOW qCDebug(kpLogMainWindow) << "\t\tgive kpThumbnail the kpView:"; #endif if (d->thumbnail) { d->thumbnail->setView (d->thumbnailView); } else { qCCritical(kpLogMainWindow) << "kpMainWindow::createThumbnailView() no thumbnail"; } #if DEBUG_KP_MAIN_WINDOW qCDebug(kpLogMainWindow) << "\t\tregistering the kpView:"; #endif if (d->viewManager) { d->viewManager->registerView (d->thumbnailView); } } // private void kpMainWindow::destroyThumbnailView () { if (!d->thumbnailView) { return; } if (d->viewManager) { d->viewManager->unregisterView (d->thumbnailView); } if (d->thumbnail) { d->thumbnail->setView (nullptr); } d->thumbnailView->deleteLater (); d->thumbnailView = nullptr; } // private void kpMainWindow::updateThumbnail () { #if DEBUG_KP_MAIN_WINDOW qCDebug(kpLogMainWindow) << "kpMainWindow::updateThumbnail()"; #endif bool enable = d->actionShowThumbnail->isChecked (); #if DEBUG_KP_MAIN_WINDOW qCDebug(kpLogMainWindow) << "\tthumbnail=" << bool (d->thumbnail) << " action_isChecked=" << enable; #endif if (bool (d->thumbnail) == enable) { return; } if (!d->thumbnail) { #if DEBUG_KP_MAIN_WINDOW qCDebug(kpLogMainWindow) << "\tcreating thumbnail"; #endif // Read last saved geometry before creating thumbnail & friends // in case they call notifyThumbnailGeometryChanged() QRect thumbnailGeometry = d->configThumbnailGeometry; #if DEBUG_KP_MAIN_WINDOW qCDebug(kpLogMainWindow) << "\t\tlast used geometry=" << thumbnailGeometry; #endif d->thumbnail = new kpThumbnail (this); createThumbnailView (); #if DEBUG_KP_MAIN_WINDOW qCDebug(kpLogMainWindow) << "\t\tmoving thumbnail to right place"; #endif if (!thumbnailGeometry.isEmpty () && QRect (0, 0, width (), height ()).intersects (thumbnailGeometry)) { const QRect geometry = mapToGlobal (thumbnailGeometry); d->thumbnail->resize (geometry.size ()); d->thumbnail->move (geometry.topLeft ()); } else { if (d->scrollView) { const int margin = 20; const int initialWidth = 160, initialHeight = 120; QRect geometryRect (width () - initialWidth - margin * 2, d->scrollView->y () + margin, initialWidth, initialHeight); #if DEBUG_KP_MAIN_WINDOW qCDebug(kpLogMainWindow) << "\t\tcreating geometry=" << geometryRect; #endif geometryRect = mapToGlobal (geometryRect); #if DEBUG_KP_MAIN_WINDOW qCDebug(kpLogMainWindow) << "\t\tmap to global=" << geometryRect; #endif d->thumbnail->resize (geometryRect.size ()); d->thumbnail->move (geometryRect.topLeft ()); } } #if DEBUG_KP_MAIN_WINDOW qCDebug(kpLogMainWindow) << "\t\tshowing thumbnail"; #endif d->thumbnail->show (); #if DEBUG_KP_MAIN_WINDOW qCDebug(kpLogMainWindow) << "\t\tconnecting signal thumbnail::windowClosed to destroy slot"; #endif connect (d->thumbnail, &kpThumbnail::windowClosed, this, &kpMainWindow::slotDestroyThumbnailInitatedByUser); #if DEBUG_KP_MAIN_WINDOW qCDebug(kpLogMainWindow) << "\t\tDONE"; #endif } else { #if DEBUG_KP_MAIN_WINDOW qCDebug(kpLogMainWindow) << "\tdestroying thumbnail d->thumbnail=" << d->thumbnail; #endif if (d->thumbnailSaveConfigTimer && d->thumbnailSaveConfigTimer->isActive ()) { d->thumbnailSaveConfigTimer->stop (); slotSaveThumbnailGeometry (); } // Must be done before hiding the thumbnail to avoid triggering // this signal - re-entering this code. disconnect (d->thumbnail, &kpThumbnail::windowClosed, this, &kpMainWindow::slotDestroyThumbnailInitatedByUser); // Avoid change/flicker of caption due to view delete // (destroyThumbnailView()) d->thumbnail->hide (); destroyThumbnailView (); d->thumbnail->deleteLater (); d->thumbnail = nullptr; } } diff --git a/mainWindow/kpMainWindow_View_Zoom.cpp b/mainWindow/kpMainWindow_View_Zoom.cpp index 410d409b..6ca38e75 100644 --- a/mainWindow/kpMainWindow_View_Zoom.cpp +++ b/mainWindow/kpMainWindow_View_Zoom.cpp @@ -1,693 +1,693 @@ // 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 } 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 = ac->add (QStringLiteral("view_zoom_to")); d->actionZoom->setText (i18n ("&Zoom")); connect (d->actionZoom, static_cast(&KSelectAction::triggered), this, &kpMainWindow::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); 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 (); #endif if (viewMenuDocumentActionsEnabled ()) { d->actionActualSize->setEnabled (zoomLevel != 100); 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; #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 (); qCDebug(kpLogMainWindow) << "\tnewCenterX=" << newCenterX << " newCenterY=" << newCenterY; #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 (); #endif const auto viewX = vuc->transformDocToViewX (targetDocX); const auto 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 (static_cast (viewX), static_cast (viewY)); #if DEBUG_KP_MAIN_WINDOW qCDebug(kpLogMainWindow) << "\t\tdoc: (" << targetDocX << "," << targetDocY << ")" << " viewUnderCursor: (" << viewX << "," << viewY << ")"; #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"; #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 () << ")"; #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; << " -> 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*/, 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 ( 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 (); #endif const int targetItem = d->actionZoom->currentItem () + 1; 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 (); #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 (); #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 () << "'"; #endif zoomAccordingToZoomAction (false/*don't center under cursor*/); } //--------------------------------------------------------------------- diff --git a/pixmapfx/kpPixmapFX_Transforms.cpp b/pixmapfx/kpPixmapFX_Transforms.cpp index a761a1c3..083c66d4 100644 --- a/pixmapfx/kpPixmapFX_Transforms.cpp +++ b/pixmapfx/kpPixmapFX_Transforms.cpp @@ -1,669 +1,669 @@ /* 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 << ")"; #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 = qRadiansToDegrees (std::tan (1.0 / 10000.0)) / (2.0/*max error allowed*/ * 2.0/*for good measure*/); static void MatrixDebug (const QString& matrixName, const QTransform &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)); } #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 QTransform MatrixWithZeroOrigin (const QTransform &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 QTransform 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 (std::fabs (x - qRound (x)) < TrueMatrixEpsilon) { return qRound (x); } return x; } //--------------------------------------------------------------------- static QTransform TrueMatrix (const QTransform &matrix, int srcPixmapWidth, int srcPixmapHeight) { - ::MatrixDebug ("TrueMatrix(): org", matrix); + ::MatrixDebug (QStringLiteral("TrueMatrix(): org"), matrix); const QTransform truMat = QPixmap::trueMatrix (matrix, srcPixmapWidth, srcPixmapHeight); - ::MatrixDebug ("TrueMatrix(): passed through QPixmap::trueMatrix()", truMat); + ::MatrixDebug (QStringLiteral("TrueMatrix(): passed through QPixmap::trueMatrix()"), truMat); const QTransform retMat ( ::TrueMatrixFixInts (truMat.m11 ()), ::TrueMatrixFixInts (truMat.m12 ()), ::TrueMatrixFixInts (truMat.m21 ()), ::TrueMatrixFixInts (truMat.m22 ()), ::TrueMatrixFixInts (truMat.dx ()), ::TrueMatrixFixInts (truMat.dy ())); - ::MatrixDebug ("TrueMatrix(): fixed ints", retMat); + ::MatrixDebug (QStringLiteral("TrueMatrix(): fixed ints"), retMat); return retMat; } //--------------------------------------------------------------------- // Like QPixmap::transformed() but fills new areas with // (unless is invalid) and works around internal QTransform // 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 QTransform &transformMatrix_, const kpColor &backgroundColor, int targetWidth, int targetHeight) { QTransform transformMatrix = transformMatrix_; #if DEBUG_KP_PIXMAP_FX && 1 qCDebug(kpLogPixmapfx) << "kppixmapfx.cpp: TransformPixmap(pm.size=" << pm.size () << ",targetWidth=" << targetWidth << ",targetHeight=" << targetHeight << ")"; #endif QRect newRect = transformMatrix.mapRect (pm.rect ()); #if DEBUG_KP_PIXMAP_FX && 1 qCDebug(kpLogPixmapfx) << "\tmappedRect=" << newRect; #endif QTransform 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? QTransform wrongMatrix = transformMatrix * scaleMatrix; QTransform 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 ())); } QTransform 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); QTransform 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 ()) << "\n" << "\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 ()) << "\n" << "\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 ()) << "\n" << "\tsupposedlyCorrectMatrix: m11=" << correctMatrix.m11 () << " m12=" << correctMatrix.m12 () << " m21=" << correctMatrix.m21 () << " m22=" << correctMatrix.m22 () << " dx=" << correctMatrix.dx () << " dy=" << correctMatrix.dy () << " rect=" << correctMatrix.mapRect (pm.rect ()); #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, + ::MatrixDebug (QStringLiteral("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, + ::MatrixDebug (QStringLiteral("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)"; #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.setWorldTransform (transformMatrix); p.drawImage (QPoint (0, 0), pm); } p.end (); #if DEBUG_KP_PIXMAP_FX && 1 qCDebug(kpLogPixmapfx) << "Done"; #endif return newQImage; } //--------------------------------------------------------------------- // public static QTransform kpPixmapFX::skewMatrix (int width, int height, double hangle, double vangle) { if (std::fabs (hangle - 0) < kpPixmapFX::AngleInDegreesEpsilon && std::fabs (vangle - 0) < kpPixmapFX::AngleInDegreesEpsilon) { return {}; } /* 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. * */ //QTransform matrix (1, tan (KP_DEGREES_TO_RADIANS (vangle)), tan (KP_DEGREES_TO_RADIANS (hangle)), 1, 0, 0); // I think this is clearer than above :) QTransform matrix; matrix.shear (std::tan (qDegreesToRadians (hangle)), std::tan (qDegreesToRadians (vangle))); return ::MatrixWithZeroOrigin (matrix, width, height); } //--------------------------------------------------------------------- // public static QTransform 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; #endif if (std::fabs (hangle - 0) < kpPixmapFX::AngleInDegreesEpsilon && std::fabs (vangle - 0) < kpPixmapFX::AngleInDegreesEpsilon && (targetWidth <= 0 && targetHeight <= 0)/*don't want to scale?*/) { return pm; } if (std::fabs (hangle) > 90 - kpPixmapFX::AngleInDegreesEpsilon || std::fabs (vangle) > 90 - kpPixmapFX::AngleInDegreesEpsilon) { qCCritical(kpLogPixmapfx) << "kpPixmapFX::skew() passed hangle and/or vangle out of range (-90 < x < 90)"; return pm; } QTransform matrix = skewMatrix (pm, hangle, vangle); return ::TransformPixmap (pm, matrix, backgroundColor, targetWidth, targetHeight); } //--------------------------------------------------------------------- // public static QTransform kpPixmapFX::rotateMatrix (int width, int height, double angle) { if (std::fabs (angle - 0) < kpPixmapFX::AngleInDegreesEpsilon) { return {}; } QTransform matrix; matrix.translate (width / 2, height / 2); matrix.rotate (angle); return ::MatrixWithZeroOrigin (matrix, width, height); } //--------------------------------------------------------------------- // public static QTransform 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 -= (static_cast (angle)) / 90 * 90; // "Impossible" situation? if (angle < 0 || angle > 90) { qCCritical(kpLogPixmapfx) << "kpPixmapFX::isLosslessRotation(" << angleIn << ") result=" << angle; 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; #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 (std::fabs (angle - 0) < kpPixmapFX::AngleInDegreesEpsilon && (targetWidth <= 0 && targetHeight <= 0)/*don't want to scale?*/) { return pm; } QTransform matrix = rotateMatrix (pm, angle); return ::TransformPixmap (pm, matrix, backgroundColor, targetWidth, targetHeight); } //--------------------------------------------------------------------- diff --git a/scan/sanedialog.cpp b/scan/sanedialog.cpp index 8614fd87..9766619d 100644 --- a/scan/sanedialog.cpp +++ b/scan/sanedialog.cpp @@ -1,120 +1,120 @@ /* ============================================================ * * 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(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, &KSaneIface::KSaneWidget::imageReady, this, &SaneDialog::imageReady); 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(nullptr); if (m_openDev.isEmpty()) { // either no scanner was found or then cancel was pressed. return false; } if (!m_ksanew->openDevice(m_openDev)) { // could not open the scanner KMessageBox::sorry(nullptr, 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"); + KSharedConfigPtr configPtr = KSharedConfig::openConfig(QStringLiteral("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"); + KSharedConfigPtr configPtr = KSharedConfig::openConfig(QStringLiteral("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, static_cast (f)); emit finalImage(img, nextId()); } int SaneDialog::nextId() { return ++m_currentId; } diff --git a/tools/flow/kpToolBrush.cpp b/tools/flow/kpToolBrush.cpp index 9e87f887..a83f8626 100644 --- a/tools/flow/kpToolBrush.cpp +++ b/tools/flow/kpToolBrush.cpp @@ -1,56 +1,56 @@ /* 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 "kpToolBrush.h" #include //--------------------------------------------------------------------- kpToolBrush::kpToolBrush (kpToolEnvironment *environ, QObject *parent) : kpToolFlowPixmapBase (i18n ("Brush"), i18n ("Draw using brushes of different shapes and sizes"), Qt::Key_B, - environ, parent, "tool_brush") + environ, parent, QStringLiteral("tool_brush")) { } //--------------------------------------------------------------------- // protected virtual [base kpToolFlowBase] QString kpToolBrush::haventBegunDrawUserMessage () const { return i18n ("Click to draw dots or drag to draw strokes."); } //--------------------------------------------------------------------- // See the our corresponding .h for brush selection. // Logic is in kpToolFlowPixmapBase. diff --git a/tools/flow/kpToolColorEraser.cpp b/tools/flow/kpToolColorEraser.cpp index f3c8f908..366e8d8b 100644 --- a/tools/flow/kpToolColorEraser.cpp +++ b/tools/flow/kpToolColorEraser.cpp @@ -1,160 +1,160 @@ /* 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_COLOR_ERASER 0 #include "kpToolColorEraser.h" #include #include "kpLogCategories.h" #include #include "imagelib/kpColor.h" #include "commands/kpCommandHistory.h" #include "document/kpDocument.h" #include "commands/kpMacroCommand.h" #include "imagelib/kpPainter.h" #include "pixmapfx/kpPixmapFX.h" #include "commands/tools/flow/kpToolFlowCommand.h" #include "environments/tools/kpToolEnvironment.h" //-------------------------------------------------------------------------------- kpToolColorEraser::kpToolColorEraser (kpToolEnvironment *environ, QObject *parent) : kpToolFlowBase (i18n ("Color Eraser"), i18n ("Replaces pixels of the foreground color with the background color"), Qt::Key_O, environ, parent, - "tool_color_eraser") + QStringLiteral("tool_color_eraser")) { } //-------------------------------------------------------------------------------- kpToolColorEraser::~kpToolColorEraser () = default; //-------------------------------------------------------------------------------- // public virtual [base kpTool] void kpToolColorEraser::globalDraw () { #if DEBUG_KP_TOOL_COLOR_ERASER qCDebug(kpLogTools) << "kpToolColorEraser::globalDraw()"; #endif if (!drawShouldProceed (QPoint ()/*unused*/, QPoint ()/*unused*/, QRect ()/*unused*/)) { return; } QApplication::setOverrideCursor (Qt::WaitCursor); environ ()->flashColorSimilarityToolBarItem (); kpToolFlowCommand *cmd = new kpToolFlowCommand ( i18n ("Color Eraser"), environ ()->commandEnvironment ()); const QRect dirtyRect = kpPainter::washRect (document ()->imagePointer (), 0, 0, document ()->width (), document ()->height (), backgroundColor ()/*color to draw in*/, foregroundColor ()/*color to replace*/, processedColorSimilarity ()); if (!dirtyRect.isEmpty ()) { document ()->slotContentsChanged (dirtyRect); cmd->updateBoundingRect (dirtyRect); cmd->finalize (); commandHistory ()->addCommand (cmd, false /* don't exec */); // don't delete - it's up to the commandHistory cmd = nullptr; } else { #if DEBUG_KP_TOOL_COLOR_ERASER qCDebug(kpLogTools) << "\tisNOP"; #endif delete cmd; cmd = nullptr; } QApplication::restoreOverrideCursor (); } //-------------------------------------------------------------------------------- QString kpToolColorEraser::haventBegunDrawUserMessage () const { return i18n ("Click or drag to erase pixels of the foreground color."); } //-------------------------------------------------------------------------------- bool kpToolColorEraser::drawShouldProceed (const QPoint & /*thisPoint*/, const QPoint & /*lastPoint*/, const QRect & /*normalizedRect*/) { return !(foregroundColor () == backgroundColor () && processedColorSimilarity () == 0); } //-------------------------------------------------------------------------------- QRect kpToolColorEraser::drawLine (const QPoint &thisPoint, const QPoint &lastPoint) { #if DEBUG_KP_TOOL_COLOR_ERASER qCDebug(kpLogTools) << "kpToolColorEraser::drawLine(thisPoint=" << thisPoint << ",lastPoint=" << lastPoint << ")"; #endif environ ()->flashColorSimilarityToolBarItem (); const QRect dirtyRect = kpPainter::washLine (document ()->imagePointer (), lastPoint.x (), lastPoint.y (), thisPoint.x (), thisPoint.y (), color (mouseButton ())/*color to draw in*/, brushWidth (), brushHeight (), color (1 - mouseButton ())/*color to replace*/, processedColorSimilarity ()); #if DEBUG_KP_TOOL_COLOR_ERASER qCDebug(kpLogTools) << "\tdirtyRect=" << dirtyRect; #endif if (!dirtyRect.isEmpty ()) { document ()->slotContentsChanged (dirtyRect); return dirtyRect; } return {}; } //-------------------------------------------------------------------------------- diff --git a/tools/flow/kpToolEraser.cpp b/tools/flow/kpToolEraser.cpp index f26c3420..621cb106 100644 --- a/tools/flow/kpToolEraser.cpp +++ b/tools/flow/kpToolEraser.cpp @@ -1,79 +1,79 @@ /* 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_ERASER 0 #include "kpToolEraser.h" #include "commands/kpCommandHistory.h" #include "commands/imagelib/effects/kpEffectClearCommand.h" #include "environments/tools/kpToolEnvironment.h" #include //--------------------------------------------------------------------- kpToolEraser::kpToolEraser (kpToolEnvironment *environ, QObject *parent) : kpToolFlowPixmapBase (i18n ("Eraser"), i18n ("Lets you rub out mistakes"), Qt::Key_A, - environ, parent, "tool_eraser") + environ, parent, QStringLiteral("tool_eraser")) { } //--------------------------------------------------------------------- // public virtual [base kpTool] void kpToolEraser::globalDraw () { #if DEBUG_KP_TOOL_ERASER qCDebug(kpLogTools) << "kpToolEraser::globalDraw()"; #endif commandHistory ()->addCommand ( new kpEffectClearCommand ( false/*act on doc, not sel*/, backgroundColor (), environ ()->commandEnvironment ())); } //--------------------------------------------------------------------- // protected virtual [base kpToolFlowBase] QString kpToolEraser::haventBegunDrawUserMessage () const { return i18n ("Click or drag to erase."); } //--------------------------------------------------------------------- // See the our corresponding .h for brush selection. // Logic is in kpToolFlowPixmapBase. diff --git a/tools/flow/kpToolPen.cpp b/tools/flow/kpToolPen.cpp index 7b3e9d54..816041fc 100644 --- a/tools/flow/kpToolPen.cpp +++ b/tools/flow/kpToolPen.cpp @@ -1,84 +1,84 @@ /* Copyright (c) 2003-2007 Clarence Dang Copyright (c) 2017 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 "kpToolPen.h" #include "imagelib/kpColor.h" #include "document/kpDocument.h" #include "imagelib/kpImage.h" #include "imagelib/kpPainter.h" #include "commands/tools/flow/kpToolFlowCommand.h" #include "environments/tools/kpToolEnvironment.h" #include #include #include //--------------------------------------------------------------------- kpToolPen::kpToolPen (kpToolEnvironment *environ, QObject *parent) : kpToolFlowBase (i18n ("Pen"), i18n ("Draws dots and freehand strokes"), Qt::Key_P, - environ, parent, "tool_pen") + environ, parent, QStringLiteral("tool_pen")) { } //--------------------------------------------------------------------- // protected virtual [base kpToolFlowBase] QString kpToolPen::haventBegunDrawUserMessage () const { return i18n ("Click to draw dots or drag to draw strokes."); } //--------------------------------------------------------------------- // protected virtual [base kpToolFlowBase] QRect kpToolPen::drawLine (const QPoint &thisPoint, const QPoint &lastPoint) { QRect docRect = kpPainter::normalizedRect(thisPoint, lastPoint); docRect = neededRect (docRect, 1/*pen width*/); kpImage image = document ()->getImageAt (docRect); const QPoint sp = lastPoint - docRect.topLeft (), ep = thisPoint - docRect.topLeft (); QPainter painter(&image); // never use AA - it does not look good for the usually very short lines //painter.setRenderHint(QPainter::Antialiasing, kpToolEnvironment::drawAntiAliased); painter.setPen(color(mouseButton()).toQColor()); painter.drawLine(sp, ep); document ()->setImageAt (image, docRect.topLeft ()); return docRect; } //-------------------------------------------------------------------------------- diff --git a/tools/flow/kpToolSpraycan.cpp b/tools/flow/kpToolSpraycan.cpp index 018fe1ec..9d8b2604 100644 --- a/tools/flow/kpToolSpraycan.cpp +++ b/tools/flow/kpToolSpraycan.cpp @@ -1,259 +1,259 @@ /* 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_SPRAYCAN 0 #include "kpToolSpraycan.h" #include "kpDefs.h" #include "document/kpDocument.h" #include "imagelib/kpPainter.h" #include "pixmapfx/kpPixmapFX.h" #include "environments/tools/kpToolEnvironment.h" #include "commands/tools/flow/kpToolFlowCommand.h" #include "widgets/toolbars/kpToolToolBar.h" #include "widgets/toolbars/options/kpToolWidgetSpraycanSize.h" #include "views/kpView.h" #include "views/manager/kpViewManager.h" #include #include "kpLogCategories.h" #include #include #include #include //--------------------------------------------------------------------- kpToolSpraycan::kpToolSpraycan (kpToolEnvironment *environ, QObject *parent) : kpToolFlowBase (i18n ("Spraycan"), i18n ("Sprays graffiti"), Qt::Key_Y, - environ, parent, "tool_spraycan"), + environ, parent, QStringLiteral("tool_spraycan")), m_toolWidgetSpraycanSize(nullptr) { m_timer = new QTimer (this); m_timer->setInterval (25/*ms*/); connect (m_timer, &QTimer::timeout, this, &kpToolSpraycan::timeoutDraw); } //--------------------------------------------------------------------- // protected virtual [base kpToolFlowBase] QString kpToolSpraycan::haventBegunDrawUserMessage () const { return i18n ("Click or drag to spray graffiti."); } //--------------------------------------------------------------------- // public virtual [base kpToolFlowBase] void kpToolSpraycan::begin () { kpToolToolBar *tb = toolToolBar (); Q_ASSERT (tb); m_toolWidgetSpraycanSize = tb->toolWidgetSpraycanSize (); connect (m_toolWidgetSpraycanSize, &kpToolWidgetSpraycanSize::spraycanSizeChanged, this, &kpToolSpraycan::slotSpraycanSizeChanged); m_toolWidgetSpraycanSize->show (); kpToolFlowBase::begin (); } // public virtual [base kpToolFlowBase] void kpToolSpraycan::end () { kpToolFlowBase::end (); disconnect (m_toolWidgetSpraycanSize, &kpToolWidgetSpraycanSize::spraycanSizeChanged, this, &kpToolSpraycan::slotSpraycanSizeChanged); m_toolWidgetSpraycanSize = nullptr; } // public virtual [base kpToolFlowBase] void kpToolSpraycan::beginDraw () { #if DEBUG_KP_TOOL_SPRAYCAN qCDebug(kpLogTools) << "kpToolSpraycan::beginDraw()"; #endif kpToolFlowBase::beginDraw (); // We draw even if the user doesn't move the mouse. // We still timeout-draw even if the user _does_ move the mouse. m_timer->start (); } // protected QRect kpToolSpraycan::drawLineWithProbability (const QPoint &thisPoint, const QPoint &lastPoint, double probability) { #if DEBUG_KP_TOOL_SPRAYCAN qCDebug(kpLogTools) << "CALL(thisPoint=" << thisPoint << ",lastPoint=" << lastPoint << ")"; #endif QList docPoints = kpPainter::interpolatePoints (lastPoint, thisPoint, false/*no need for cardinally adjacency points*/, probability); #if DEBUG_KP_TOOL_SPRAYCAN qCDebug(kpLogTools) << "\tdocPoints=" << docPoints; #endif // By chance no points to draw? if (docPoints.empty ()) { return {}; } // For efficiency, only get image after NOP check above. QRect docRect = kpPainter::normalizedRect(thisPoint, lastPoint); docRect = neededRect (docRect, spraycanSize ()); kpImage image = document ()->getImageAt (docRect); // Spray at each point, onto the image. // // Note in passing: Unlike other tools such as the Brush, drawing // over the same point does result in a different // appearance. QList imagePoints; for (const auto &dp : docPoints) imagePoints.append (dp - docRect.topLeft ()); kpPainter::sprayPoints (&image, imagePoints, color (mouseButton ()), spraycanSize ()); viewManager ()->setFastUpdates (); document ()->setImageAt (image, docRect.topLeft ()); viewManager ()->restoreFastUpdates (); return docRect; } // public virtual [base kpToolFlowBase] QRect kpToolSpraycan::drawPoint (const QPoint &point) { #if DEBUG_KP_TOOL_SPRAYCAN qCDebug(kpLogTools) << "kpToolSpraycan::drawPoint" << point << " lastPoint=" << lastPoint (); #endif // If this is the first in the flow or if the user is moving the spray, // make the spray line continuous. if (point != lastPoint ()) { // Draw at this single point without delay. return drawLineWithProbability (point, point, 1.0/*100% chance of drawing*/); } return {}; } // public virtual [base kpToolFlowBase] QRect kpToolSpraycan::drawLine (const QPoint &thisPoint, const QPoint &lastPoint) { #if DEBUG_KP_TOOL_SPRAYCAN qCDebug(kpLogTools) << "CALL(thisPoint=" << thisPoint << ",lastPoint=" << lastPoint; #endif // Draw only every so often in response to movement. return drawLineWithProbability (thisPoint, lastPoint, 0.05/*less dense: select 5% of adjacent pixels - not all*/); } // protected slot void kpToolSpraycan::timeoutDraw () { #if DEBUG_KP_TOOL_SPRAYCAN qCDebug(kpLogTools) << "kpToolSpraycan::timeoutDraw()"; #endif // Draw at this single point without delay. const QRect drawnRect = drawLineWithProbability (currentPoint (), currentPoint (), 1.0/*100% chance of drawing*/); // kpToolFlowBase() does this after calling drawPoint() and drawLine() so // we need to do it too. currentCommand ()->updateBoundingRect (drawnRect); } // public virtual [base kpToolFlowBase] void kpToolSpraycan::cancelShape () { #if DEBUG_KP_TOOL_SPRAYCAN qCDebug(kpLogTools) << "kpToolSpraycan::cancelShape()"; #endif m_timer->stop (); kpToolFlowBase::cancelShape (); } // public virtual [base kpToolFlowBase] void kpToolSpraycan::endDraw (const QPoint &thisPoint, const QRect &normalizedRect) { #if DEBUG_KP_TOOL_SPRAYCAN qCDebug(kpLogTools) << "kpToolSpraycan::endDraw(thisPoint=" << thisPoint << ")"; #endif m_timer->stop (); kpToolFlowBase::endDraw (thisPoint, normalizedRect); } // protected int kpToolSpraycan::spraycanSize () const { return m_toolWidgetSpraycanSize->spraycanSize (); } // protected slot void kpToolSpraycan::slotSpraycanSizeChanged (int size) { (void) size; } diff --git a/tools/kpToolColorPicker.cpp b/tools/kpToolColorPicker.cpp index f5d1c3aa..8a2f1713 100644 --- a/tools/kpToolColorPicker.cpp +++ b/tools/kpToolColorPicker.cpp @@ -1,137 +1,137 @@ /* 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_COLOR_PICKER 0 #include "kpToolColorPicker.h" #include "kpLogCategories.h" #include "widgets/toolbars/kpColorToolBar.h" #include "commands/kpCommandHistory.h" #include "kpDefs.h" #include "document/kpDocument.h" #include "pixmapfx/kpPixmapFX.h" #include "commands/tools/kpToolColorPickerCommand.h" #include "environments/tools/kpToolEnvironment.h" #include kpToolColorPicker::kpToolColorPicker (kpToolEnvironment *environ, QObject *parent) : kpTool (i18n ("Color Picker"), i18n ("Lets you select a color from the image"), Qt::Key_C, - environ, parent, "tool_color_picker") + environ, parent, QStringLiteral("tool_color_picker")) { } kpToolColorPicker::~kpToolColorPicker () = default; // private kpColor kpToolColorPicker::colorAtPixel (const QPoint &p) { #if DEBUG_KP_TOOL_COLOR_PICKER && 0 qCDebug(kpLogTools) << "kpToolColorPicker::colorAtPixel" << p; #endif return kpPixmapFX::getColorAtPixel (document ()->image (), p); } // private QString kpToolColorPicker::haventBegunDrawUserMessage () const { return i18n ("Click to select a color."); } // public virtual [base kpTool] void kpToolColorPicker::begin () { setUserMessage (haventBegunDrawUserMessage ()); } // public virtual [base kpTool] void kpToolColorPicker::beginDraw () { m_oldColor = color (mouseButton ()); setUserMessage (cancelUserMessage ()); } // public virtual [base kpTool] void kpToolColorPicker::draw (const QPoint &thisPoint, const QPoint &, const QRect &) { const kpColor color = colorAtPixel (thisPoint); if (color.isValid ()) { environ ()->setColor (mouseButton (), color); setUserShapePoints (thisPoint); } else { environ ()->setColor (mouseButton (), m_oldColor); setUserShapePoints (); } } // public virtual [base kpTool] void kpToolColorPicker::cancelShape () { environ ()->setColor (mouseButton (), m_oldColor); setUserMessage (i18n ("Let go of all the mouse buttons.")); } // public virtual [base kpTool] void kpToolColorPicker::releasedAllButtons () { setUserMessage (haventBegunDrawUserMessage ()); } // public virtual [base kpTool] void kpToolColorPicker::endDraw (const QPoint &thisPoint, const QRect &) { const kpColor color = colorAtPixel (thisPoint); if (color.isValid ()) { auto *cmd = new kpToolColorPickerCommand ( mouseButton (), color, m_oldColor, environ ()->commandEnvironment ()); environ ()->commandHistory ()->addCommand (cmd, false/*no exec*/); setUserMessage (haventBegunDrawUserMessage ()); } else { cancelShape (); } } diff --git a/tools/kpToolFloodFill.cpp b/tools/kpToolFloodFill.cpp index 185093a8..d562e87e 100644 --- a/tools/kpToolFloodFill.cpp +++ b/tools/kpToolFloodFill.cpp @@ -1,169 +1,169 @@ /* 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_FLOOD_FILL 0 #include "kpToolFloodFill.h" #include "commands/kpCommandHistory.h" #include "kpDefs.h" #include "document/kpDocument.h" #include "environments/tools/kpToolEnvironment.h" #include "commands/tools/kpToolFloodFillCommand.h" #include "kpLogCategories.h" #include #include //--------------------------------------------------------------------- struct kpToolFloodFillPrivate { kpToolFloodFillCommand *currentCommand; }; //--------------------------------------------------------------------- kpToolFloodFill::kpToolFloodFill (kpToolEnvironment *environ, QObject *parent) : kpTool (i18n ("Flood Fill"), i18n ("Fills regions in the image"), Qt::Key_F, - environ, parent, "tool_flood_fill"), + environ, parent, QStringLiteral("tool_flood_fill")), d (new kpToolFloodFillPrivate ()) { d->currentCommand = nullptr; } //--------------------------------------------------------------------- kpToolFloodFill::~kpToolFloodFill () { delete d; } //--------------------------------------------------------------------- // private QString kpToolFloodFill::haventBegunDrawUserMessage () const { return i18n ("Click to fill a region."); } //--------------------------------------------------------------------- // public virtual [base kpTool] void kpToolFloodFill::begin () { setUserMessage (haventBegunDrawUserMessage ()); } //--------------------------------------------------------------------- // public virtual [base kpTool] void kpToolFloodFill::beginDraw () { #if DEBUG_KP_TOOL_FLOOD_FILL && 1 qCDebug(kpLogTools) << "kpToolFloodFill::beginDraw()"; #endif QApplication::setOverrideCursor (Qt::WaitCursor); { environ ()->flashColorSimilarityToolBarItem (); // Flood Fill is an expensive CPU operation so we only fill at a // mouse click (beginDraw ()), not on mouse move (virtually draw()) d->currentCommand = new kpToolFloodFillCommand ( currentPoint ().x (), currentPoint ().y (), color (mouseButton ()), processedColorSimilarity (), environ ()->commandEnvironment ()); #if DEBUG_KP_TOOL_FLOOD_FILL && 1 qCDebug(kpLogTools) << "\tperforming new-doc-corner-case check"; #endif if (document ()->url ().isEmpty () && !document ()->isModified ()) { // Collect the colour that gets changed before we change the pixels // (execute() below). Needed in unexecute(). d->currentCommand->prepareColorToChange (); d->currentCommand->setFillEntireImage (); } d->currentCommand->execute (); } QApplication::restoreOverrideCursor (); setUserMessage (cancelUserMessage ()); } //--------------------------------------------------------------------- // public virtual [base kpTool] void kpToolFloodFill::draw (const QPoint &thisPoint, const QPoint &, const QRect &) { setUserShapePoints (thisPoint); } //--------------------------------------------------------------------- // public virtual [base kpTool] void kpToolFloodFill::cancelShape () { d->currentCommand->unexecute (); delete d->currentCommand; d->currentCommand = nullptr; setUserMessage (i18n ("Let go of all the mouse buttons.")); } //--------------------------------------------------------------------- // public virtual [base kpTool] void kpToolFloodFill::releasedAllButtons () { setUserMessage (haventBegunDrawUserMessage ()); } //--------------------------------------------------------------------- // public virtual [base kpTool] void kpToolFloodFill::endDraw (const QPoint &, const QRect &) { environ ()->commandHistory ()->addCommand (d->currentCommand, false/*no exec - we already did it up there*/); // Don't delete - it just got added to the history. d->currentCommand = nullptr; setUserMessage (haventBegunDrawUserMessage ()); } //--------------------------------------------------------------------- diff --git a/tools/kpToolZoom.cpp b/tools/kpToolZoom.cpp index a0e86b7d..fc065e72 100644 --- a/tools/kpToolZoom.cpp +++ b/tools/kpToolZoom.cpp @@ -1,255 +1,255 @@ /* 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_ZOOM 0 #include "kpToolZoom.h" #include "kpDefs.h" #include "document/kpDocument.h" #include "pixmapfx/kpPixmapFX.h" #include "generic/kpSetOverrideCursorSaver.h" #include "layers/tempImage/kpTempImage.h" #include "environments/tools/kpToolEnvironment.h" #include "tools/kpToolAction.h" #include "views/manager/kpViewManager.h" #include "kpLogCategories.h" #include #include #include //--------------------------------------------------------------------- struct DrawZoomRectPackage { QRect normalizedRect; }; static void DrawZoomRect (kpImage *destImage, const QPoint &topLeft, void *userData) { auto *pack = static_cast (userData); kpPixmapFX::drawStippleRect(destImage, topLeft.x (), topLeft.y (), pack->normalizedRect.width (), pack->normalizedRect.height (), kpColor::Yellow, kpColor::Green); } struct kpToolZoomPrivate { bool dragHasBegun{}, dragCompleted{}; DrawZoomRectPackage drawPackage; }; kpToolZoom::kpToolZoom (kpToolEnvironment *environ, QWidget *parent) : kpTool (i18n ("Zoom"), i18n ("Zooms in and out of the image"), Qt::Key_Z, - environ, parent, "tool_zoom"), + environ, parent, QStringLiteral("tool_zoom")), d (new kpToolZoomPrivate ()) { // different from objectName() - action()->setIcon(KDE::icon("zoom-original")); + action()->setIcon(KDE::icon(QStringLiteral("zoom-original"))); } //--------------------------------------------------------------------- kpToolZoom::~kpToolZoom () { delete d; } //--------------------------------------------------------------------- // public virtual [base kpTool] bool kpToolZoom::returnToPreviousToolAfterEndDraw () const { // If the user clicks to zoom in or out, s/he generally wants to click // some more to get the exact zoom level wanted. // // However, if they drag out a rectangle to zoom into a particular area, // they probably don't need to do any further zooming so we can return // them to their previous tool. // // Note that if they cancel a drag (cancelShape()), we do _not_ return // them to their previous tool, unlike the Color Picker. This is because // cancelling a drag generally means that the user got the top-left of // the drag wrong and wants to try a different top-left. In contrast, // with the Color Picket, if you've made a mistake while pressing the // mouse, you can just keep holding down the mouse and drag to the intended // color -- a cancel with a Color Picker really means "I've decided not // to pick another color after all", not "I got the start of the drag wrong" // because you can correct that drag. return d->dragCompleted; } // private QString kpToolZoom::haventBegunDrawUserMessage () const { return i18n ("Click to zoom in/out or left drag to zoom into a specific area."); } // public virtual [base kpTool] void kpToolZoom::begin () { viewManager ()->setCursor (Qt::CrossCursor); setUserMessage (haventBegunDrawUserMessage ()); } // public virtual [base kpTool] void kpToolZoom::end () { viewManager ()->unsetCursor (); } // public virtual [base kpTool] void kpToolZoom::globalDraw () { #if DEBUG_KP_TOOL_ZOOM qCDebug(kpLogTools) << "CALL"; #endif environ ()->fitToPage (); } // public virtual [base kpTool] void kpToolZoom::beginDraw () { d->dragHasBegun = false; d->dragCompleted = false; setUserMessage (cancelUserMessage ()); } // public virtual [base kpTool] void kpToolZoom::draw (const QPoint &thisPoint, const QPoint &, const QRect &normalizedRect) { #if DEBUG_KP_TOOL_ZOOM qCDebug(kpLogTools) << "kpToomZoom::draw() currentPoint=" << currentPoint () << " lastPoint=" << lastPoint () << endl; #endif // TODO: Need accidental drag detection from selection tool (when dragging // out new selection) if (!d->dragHasBegun) { if (thisPoint == startPoint ()) { return; } // Left mouse drags select an area to zoom into. // However, it wouldn't make sense to select an area to "zoom out of" // (using the right mouse button). Therefore, make RMB drags do the // same as RMB clicks i.e. a simple zoom out, with no "area" to worry // about. if (mouseButton () == 1/*RMB*/) { return; } d->dragHasBegun = true; } d->drawPackage.normalizedRect = normalizedRect; kpTempImage newTempImage (false/*always display*/, normalizedRect.topLeft (), &::DrawZoomRect, &d->drawPackage, normalizedRect.width (), normalizedRect.height ()); viewManager ()->setFastUpdates (); { viewManager ()->setTempImage (newTempImage); } viewManager ()->restoreFastUpdates (); } // public virtual [base kpTool] void kpToolZoom::cancelShape () { viewManager ()->invalidateTempImage (); // LOREFACTOR: A lot of tools use this - push up to kpTool? setUserMessage (i18n ("Let go of all the mouse buttons.")); } // public virtual [base kpTool] void kpToolZoom::releasedAllButtons () { setUserMessage (haventBegunDrawUserMessage ()); } // public virtual [base kpTool] void kpToolZoom::endDraw (const QPoint &, const QRect &normalizedRect) { #if DEBUG_KP_TOOL_ZOOM qCDebug(kpLogTools) << "kpToolZoom::endDraw(rect=" << normalizedRect << ")" << " dragHasBegun=" << d->dragHasBegun << endl; #endif // TODO: This cursor doesn't stay on for long enough because zooming uses // event loop tricks. kpSetOverrideCursorSaver cursorSaver (Qt::WaitCursor); viewManager ()->invalidateTempImage (); // Click? if (!d->dragHasBegun) { if (mouseButton () == 0/*LMB*/) { environ ()->zoomIn (true/*center under cursor*/); } else { environ ()->zoomOut (false/*don't center under cursor - as is confusing behaviour when zooming out*/); } } // Drag? else if (normalizedRect.isValid()) { environ ()->zoomToRect ( normalizedRect, false/*don't account for grips*/, true/*care about width*/, true/*care about height*/); d->dragCompleted = true; } } diff --git a/tools/kpTool_Utilities.cpp b/tools/kpTool_Utilities.cpp index 51588f24..dd3b4585 100644 --- a/tools/kpTool_Utilities.cpp +++ b/tools/kpTool_Utilities.cpp @@ -1,294 +1,294 @@ /* 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 utility methods - mainly for subclasses' convenience. // #define DEBUG_KP_TOOL 0 #include "tools/kpTool.h" #include "kpToolPrivate.h" #include #include #include "kpLogCategories.h" #include #include "commands/kpCommandSize.h" #include "kpDefs.h" #include "imagelib/kpPainter.h" #include "pixmapfx/kpPixmapFX.h" #include "views/kpView.h" //--------------------------------------------------------------------- // static QRect kpTool::neededRect (const QRect &rect, int lineWidth) { int x1, y1, x2, y2; rect.getCoords (&x1, &y1, &x2, &y2); if (lineWidth < 1) { lineWidth = 1; } // TODO: why not divide by 2? return QRect (QPoint (x1 - lineWidth + 1, y1 - lineWidth + 1), QPoint (x2 + lineWidth - 1, y2 + lineWidth - 1)); } //--------------------------------------------------------------------- // static QImage kpTool::neededPixmap (const QImage &image, const QRect &boundingRect) { return kpPixmapFX::getPixmapAt (image, boundingRect); } //--------------------------------------------------------------------- // public bool kpTool::hasCurrentPoint () const { return (viewUnderStartPoint () || viewUnderCursor ()); } //--------------------------------------------------------------------- // public QPoint kpTool::calculateCurrentPoint (bool zoomToDoc) const { #if DEBUG_KP_TOOL && 0 qCDebug(kpLogTools) << "kpTool::currentPoint(zoomToDoc=" << zoomToDoc << ")"; qCDebug(kpLogTools) << "\tviewUnderStartPoint=" << (viewUnderStartPoint () ? viewUnderStartPoint ()->objectName () : "(none)") << " viewUnderCursor=" << (viewUnderCursor () ? viewUnderCursor ()->objectName () : "(none)") << endl; #endif kpView *v = viewUnderStartPoint (); if (!v) { v = viewUnderCursor (); if (!v) { #if DEBUG_KP_TOOL && 0 qCDebug(kpLogTools) << "\tno view - returning sentinel"; #endif return KP_INVALID_POINT; } } const QPoint globalPos = QCursor::pos (); const QPoint viewPos = v->mapFromGlobal (globalPos); #if DEBUG_KP_TOOL && 0 qCDebug(kpLogTools) << "\tglobalPos=" << globalPos << " viewPos=" << viewPos; #endif if (!zoomToDoc) { return viewPos; } const QPoint docPos = v->transformViewToDoc (viewPos); #if DEBUG_KP_TOOL && 0 qCDebug(kpLogTools) << "\tdocPos=" << docPos; #endif return docPos; } //--------------------------------------------------------------------- // public slot void kpTool::somethingBelowTheCursorChanged () { somethingBelowTheCursorChanged (calculateCurrentPoint (), calculateCurrentPoint (false/*view point*/)); } //--------------------------------------------------------------------- // private // TODO: don't dup code from mouseMoveEvent() void kpTool::somethingBelowTheCursorChanged (const QPoint ¤tPoint_, const QPoint ¤tViewPoint_) { #if DEBUG_KP_TOOL && 1 qCDebug(kpLogTools) << "kpTool::somethingBelowTheCursorChanged(docPoint=" << currentPoint_ << " viewPoint=" << currentViewPoint_ << ")" << endl; qCDebug(kpLogTools) << "\tviewUnderStartPoint=" << (viewUnderStartPoint () ? viewUnderStartPoint ()->objectName () : "(none)") << " viewUnderCursor=" << (viewUnderCursor () ? viewUnderCursor ()->objectName () : "(none)") << endl; qCDebug(kpLogTools) << "\tbegan draw=" << d->beganDraw; #endif d->currentPoint = currentPoint_; d->currentViewPoint = currentViewPoint_; if (d->beganDraw) { if (d->currentPoint != KP_INVALID_POINT) { draw (d->currentPoint, d->lastPoint, normalizedRect ()); d->lastPoint = d->currentPoint; } } else { hover (d->currentPoint); } } //--------------------------------------------------------------------- bool kpTool::currentPointNextToLast () const { if (d->lastPoint == QPoint (-1, -1)) { return true; } int dx = qAbs (d->currentPoint.x () - d->lastPoint.x ()); int dy = qAbs (d->currentPoint.y () - d->lastPoint.y ()); return (dx <= 1 && dy <= 1); } //--------------------------------------------------------------------- bool kpTool::currentPointCardinallyNextToLast () const { if (d->lastPoint == QPoint (-1, -1)) { return true; } return (d->currentPoint == d->lastPoint || kpPainter::pointsAreCardinallyAdjacent (d->currentPoint, d->lastPoint)); } //--------------------------------------------------------------------- // static // TODO: we don't handle Qt::XButton1 and Qt::XButton2 at the moment. int kpTool::mouseButton (Qt::MouseButtons mouseButtons) { // we have nothing to do with mid-buttons if (mouseButtons & Qt::MidButton) { return -1; } // both left & right together is quite meaningless... const Qt::MouseButtons bothButtons = (Qt::LeftButton | Qt::RightButton); if ((mouseButtons & bothButtons) == bothButtons) { return -1; } if (mouseButtons & Qt::LeftButton) { return 0; } if (mouseButtons & Qt::RightButton) { return 1; } return -1; } //--------------------------------------------------------------------- // public static int kpTool::calculateLength (int start, int end) { if (start <= end) { return end - start + 1; } return end - start - 1; } //--------------------------------------------------------------------- // public static bool kpTool::warnIfBigImageSize (int oldWidth, int oldHeight, int newWidth, int newHeight, const QString &text, const QString &caption, const QString &continueButtonText, QWidget *parent) { #if DEBUG_KP_TOOL qCDebug(kpLogTools) << "kpTool::warnIfBigImageSize()" << " old: w=" << oldWidth << " h=" << oldWidth << " new: w=" << newWidth << " h=" << newHeight << " pixmapSize=" << kpPixmapFX::pixmapSize (newWidth, newHeight, QPixmap::defaultDepth ()) << " vs BigImageSize=" << KP_BIG_IMAGE_SIZE << endl; #endif // Only got smaller or unchanged - don't complain if (!(newWidth > oldWidth || newHeight > oldHeight)) { return true; } // Was already large - user was warned before, don't annoy him/her again if (kpCommandSize::PixmapSize (oldWidth, oldHeight, QPixmap::defaultDepth ()) >= KP_BIG_IMAGE_SIZE) { return true; } if (kpCommandSize::PixmapSize (newWidth, newHeight, QPixmap::defaultDepth ()) >= KP_BIG_IMAGE_SIZE) { int accept = KMessageBox::warningContinueCancel (parent, text, caption, KGuiItem (continueButtonText), KStandardGuiItem::cancel(), - QLatin1String ("BigImageDontAskAgain")); + QStringLiteral ("BigImageDontAskAgain")); return (accept == KMessageBox::Continue); } return true; } //--------------------------------------------------------------------- diff --git a/tools/polygonal/kpToolCurve.cpp b/tools/polygonal/kpToolCurve.cpp index ccd852c4..0c1ce7a0 100644 --- a/tools/polygonal/kpToolCurve.cpp +++ b/tools/polygonal/kpToolCurve.cpp @@ -1,196 +1,196 @@ /* Copyright (c) 2003-2007 Clarence Dang Copyright (c) 2017 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_CURVE 0 #include "kpToolCurve.h" #include "kpLogCategories.h" #include "environments/tools/kpToolEnvironment.h" #include "pixmapfx/kpPixmapFX.h" #include #include #include #include //-------------------------------------------------------------------------------- static void DrawCurveShape (kpImage *image, const QPolygon &points, const kpColor &fcolor, int penWidth, const kpColor &bcolor, bool isFinal) { (void) bcolor; (void) isFinal; Q_ASSERT (points.count () >= 2 && points.count () <= 4); const QPoint startPoint = points [0]; const QPoint endPoint = points [1]; QPoint controlPointP, controlPointQ; switch (points.count ()) { // Just a line? case 2: controlPointP = startPoint; controlPointQ = endPoint; break; // Single control point? case 3: controlPointP = controlPointQ = points [2]; break; // Two control points? case 4: controlPointP = points [2]; controlPointQ = points [3]; break; } QPainter painter(image); painter.setRenderHint(QPainter::Antialiasing, kpToolEnvironment::drawAntiAliased); painter.setPen(QPen(fcolor.toQColor(), penWidth, Qt::SolidLine, Qt::RoundCap, Qt::RoundJoin)); if ( kpPixmapFX::Only1PixelInPointArray(points) ) { painter.drawPoint(points[0]); return; } QPainterPath curvePath; curvePath.moveTo(startPoint); curvePath.cubicTo(controlPointP, controlPointQ, endPoint); painter.strokePath(curvePath, painter.pen()); } //-------------------------------------------------------------------------------- kpToolCurve::kpToolCurve (kpToolEnvironment *environ, QObject *parent) : kpToolPolygonalBase ( i18n ("Curve"), i18n ("Draws curves"), &::DrawCurveShape, Qt::Key_V, environ, parent, - "tool_curve") + QStringLiteral("tool_curve")) { } kpToolCurve::~kpToolCurve () = default; // protected virtual [base kpToolPolygonalBase] QString kpToolCurve::haventBegunShapeUserMessage () const { return i18n ("Drag out the start and end points."); } // protected virtual [base kpToolPolygonalBase] bool kpToolCurve::drawingALine () const { // On the initial drag (consisting of 2 points) creates a line. // Future drags are for control points. return (points ()->count () == 2); } // public virtual [base kpTool] void kpToolCurve::endDraw (const QPoint &, const QRect &) { #if DEBUG_KP_TOOL_CURVE qCDebug(kpLogTools) << "kpToolCurve::endDraw() points=" << points ()->toList (); #endif switch (points ()->count ()) { // 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(). case 0: break; case 1: Q_ASSERT (!"kpToolPolygonalBase::beginDraw() ensures we have >= 2 ctrl points"); break; // Just completed initial line? case 2: if (originatingMouseButton () == 0) { setUserMessage ( i18n ("Left drag to set the first control point or right click to finish.")); } else { setUserMessage ( i18n ("Right drag to set the first control point or left click to finish.")); } break; // Have initial line and first control point? case 3: if (originatingMouseButton () == 0) { setUserMessage ( i18n ("Left drag to set the last control point or right click to finish.")); } else { setUserMessage ( i18n ("Right drag to set the last control point or left click to finish.")); } break; // Have initial line and both control points? case 4: #if DEBUG_KP_TOOL_CURVE qCDebug(kpLogTools) << "\tending shape"; #endif endShape (); break; default: Q_ASSERT (!"Impossible number of points"); break; } } diff --git a/tools/polygonal/kpToolLine.cpp b/tools/polygonal/kpToolLine.cpp index b250480e..ef12bb20 100644 --- a/tools/polygonal/kpToolLine.cpp +++ b/tools/polygonal/kpToolLine.cpp @@ -1,73 +1,73 @@ /* 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_LINE 0 #include "kpToolLine.h" #include "kpToolPolyline.h" #include "kpLogCategories.h" #include //-------------------------------------------------------------------------------- kpToolLine::kpToolLine (kpToolEnvironment *environ, QObject *parent) : kpToolPolygonalBase ( i18n ("Line"), i18n ("Draws lines"), &kpToolPolyline::drawShape, Qt::Key_L, environ, parent, - "tool_line") + QStringLiteral("tool_line")) { } //-------------------------------------------------------------------------------- // private virtual [base kpToolPolygonalBase] QString kpToolLine::haventBegunShapeUserMessage () const { return i18n ("Drag to draw."); } //-------------------------------------------------------------------------------- // public virtual [base kpTool] void kpToolLine::endDraw (const QPoint &, const QRect &) { #if DEBUG_KP_TOOL_LINE qCDebug(kpLogTools) << "kpToolLine::endDraw() points=" << points ()->toList () << endl; #endif // After the first drag, we should have a line. Q_ASSERT (points ()->count () == 2); endShape (); } //-------------------------------------------------------------------------------- diff --git a/tools/polygonal/kpToolPolygon.cpp b/tools/polygonal/kpToolPolygon.cpp index 3c370484..07505f0a 100644 --- a/tools/polygonal/kpToolPolygon.cpp +++ b/tools/polygonal/kpToolPolygon.cpp @@ -1,190 +1,190 @@ /* Copyright (c) 2003-2007 Clarence Dang Copyright (c) 2017 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_POLYGON 0 #include "kpToolPolygon.h" #include "widgets/toolbars/kpToolToolBar.h" #include "environments/tools/kpToolEnvironment.h" #include "imagelib/kpColor.h" #include "pixmapfx/kpPixmapFX.h" #include #include #include //-------------------------------------------------------------------------------- static void DrawPolygonShape (kpImage *image, const QPolygon &points, const kpColor &fcolor, int penWidth, const kpColor &bcolor, bool isFinal) { QPainter painter(image); painter.setRenderHint(QPainter::Antialiasing, kpToolEnvironment::drawAntiAliased); painter.setPen(QPen(fcolor.toQColor(), penWidth, Qt::SolidLine, Qt::RoundCap, Qt::RoundJoin)); if ( kpPixmapFX::Only1PixelInPointArray(points) ) { painter.drawPoint(points[0]); return; } if ( bcolor.isValid() ) { painter.setBrush(QBrush(bcolor.toQColor())); } else { painter.setBrush(Qt::NoBrush); } painter.drawPolygon(points, Qt::OddEvenFill); if ( isFinal ) { return; } if ( points.count() <= 2 ) { return; } painter.setCompositionMode(QPainter::RasterOp_SourceXorDestination); painter.setPen(QPen(Qt::white)); painter.drawLine(points[0], points[points.count() - 1]); } //-------------------------------------------------------------------------------- struct kpToolPolygonPrivate { kpToolWidgetFillStyle *toolWidgetFillStyle; }; kpToolPolygon::kpToolPolygon (kpToolEnvironment *environ, QObject *parent) : kpToolPolygonalBase ( i18n ("Polygon"), i18n ("Draws polygons"), &::DrawPolygonShape, Qt::Key_G, environ, parent, - "tool_polygon"), + QStringLiteral("tool_polygon")), d (new kpToolPolygonPrivate ()) { } kpToolPolygon::~kpToolPolygon () { delete d; } // private virtual [base kpToolPolygonBase] QString kpToolPolygon::haventBegunShapeUserMessage () const { return i18n ("Drag to draw the first line."); } // public virtual [base kpToolPolygonalBase] void kpToolPolygon::begin () { kpToolPolygonalBase::begin (); kpToolToolBar *tb = toolToolBar (); Q_ASSERT (tb); d->toolWidgetFillStyle = tb->toolWidgetFillStyle (); connect (d->toolWidgetFillStyle, &kpToolWidgetFillStyle::fillStyleChanged, this, &kpToolPolygon::updateShape); d->toolWidgetFillStyle->show (); } // public virtual [base kpToolPolygonalBase] void kpToolPolygon::end () { kpToolPolygonalBase::end (); disconnect (d->toolWidgetFillStyle, &kpToolWidgetFillStyle::fillStyleChanged, this, &kpToolPolygon::updateShape); d->toolWidgetFillStyle = nullptr; } // TODO: code dup with kpToolRectangle // protected virtual [base kpToolPolygonalBase] kpColor kpToolPolygon::drawingBackgroundColor () const { const kpColor foregroundColor = color (originatingMouseButton ()); const kpColor backgroundColor = color (1 - originatingMouseButton ()); return d->toolWidgetFillStyle->drawingBackgroundColor ( foregroundColor, backgroundColor); } // public virtual [base kpTool] // TODO: dup with kpToolPolyline but we don't want to create another level of // inheritance and readability. void kpToolPolygon::endDraw (const QPoint &, const QRect &) { #if DEBUG_KP_TOOL_POLYGON qCDebug(kpLogTools) << "kpToolPolygon::endDraw() points=" << points ()->toList (); #endif // 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 (points ()->count () == 0) { return; } if (points ()->count () >= kpToolPolygonalBase::MaxPoints) { #if DEBUG_KP_TOOL_POLYGON qCDebug(kpLogTools) << "\tending shape"; #endif endShape (); return; } if (originatingMouseButton () == 0) { setUserMessage (i18n ("Left drag another line or right click to finish.")); } else { setUserMessage (i18n ("Right drag another line or left click to finish.")); } } diff --git a/tools/polygonal/kpToolPolyline.cpp b/tools/polygonal/kpToolPolyline.cpp index 9e61cf89..7bc8cba4 100644 --- a/tools/polygonal/kpToolPolyline.cpp +++ b/tools/polygonal/kpToolPolyline.cpp @@ -1,125 +1,125 @@ /* 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_POLYLINE 0 #include "kpToolPolyline.h" #include "kpLogCategories.h" #include "environments/tools/kpToolEnvironment.h" #include "pixmapfx/kpPixmapFX.h" #include #include #include //-------------------------------------------------------------------------------- kpToolPolyline::kpToolPolyline (kpToolEnvironment *environ, QObject *parent) : kpToolPolygonalBase ( i18n ("Connected Lines"), i18n ("Draws connected lines"), &drawShape, Qt::Key_N, environ, parent, - "tool_polyline") + QStringLiteral("tool_polyline")) { } //-------------------------------------------------------------------------------- // private virtual [base kpToolPolygonalBase] QString kpToolPolyline::haventBegunShapeUserMessage () const { return i18n ("Drag to draw the first line."); } //-------------------------------------------------------------------------------- // public static void kpToolPolyline::drawShape(kpImage *image, const QPolygon &points, const kpColor &fcolor, int penWidth, const kpColor &bcolor, bool isFinal) { (void) bcolor; (void) isFinal; QPainter painter(image); painter.setRenderHint(QPainter::Antialiasing, kpToolEnvironment::drawAntiAliased); painter.setPen(QPen(fcolor.toQColor(), penWidth, Qt::SolidLine, Qt::RoundCap, Qt::RoundJoin)); if ( kpPixmapFX::Only1PixelInPointArray(points) ) { painter.drawPoint(points[0]); } else { painter.drawPolyline(points); } } //-------------------------------------------------------------------------------- // public virtual [base kpTool] void kpToolPolyline::endDraw (const QPoint &, const QRect &) { #if DEBUG_KP_TOOL_POLYLINE qCDebug(kpLogTools) << "kpToolPolyline::endDraw() points=" << points ()->toList (); #endif // 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 (points ()->count () == 0) { return; } if (points ()->count () >= kpToolPolygonalBase::MaxPoints) { #if DEBUG_KP_TOOL_POLYLINE qCDebug(kpLogTools) << "\tending shape"; #endif endShape (); return; } if (originatingMouseButton () == 0) { setUserMessage (i18n ("Left drag another line or right click to finish.")); } else { setUserMessage (i18n ("Right drag another line or left click to finish.")); } } diff --git a/tools/rectangular/kpToolEllipse.cpp b/tools/rectangular/kpToolEllipse.cpp index d99e4030..49598a6b 100644 --- a/tools/rectangular/kpToolEllipse.cpp +++ b/tools/rectangular/kpToolEllipse.cpp @@ -1,86 +1,86 @@ /* Copyright (c) 2003-2007 Clarence Dang Copyright (c) 2017 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 "kpToolEllipse.h" #include "environments/tools/kpToolEnvironment.h" #include "imagelib/kpColor.h" #include #include #include #include //--------------------------------------------------------------------- kpToolEllipse::kpToolEllipse (kpToolEnvironment *environ, QObject *parent) : kpToolRectangularBase (i18n ("Ellipse"), i18n ("Draws ellipses and circles"), &kpToolEllipse::drawEllipse, Qt::Key_E, - environ, parent, "tool_ellipse") + environ, parent, QStringLiteral("tool_ellipse")) { } //--------------------------------------------------------------------- void kpToolEllipse::drawEllipse(kpImage *image, int x, int y, int width, int height, const kpColor &fcolor, int penWidth, const kpColor &bcolor) { if ( (width == 0) || (height == 0) ) { return; } QPainter painter(image); painter.setRenderHint(QPainter::Antialiasing, kpToolEnvironment::drawAntiAliased); if ( ((2 * penWidth) > width) || ((2 * penWidth) > height) ) { penWidth = qMin(width, height) / 2; } painter.setPen(QPen(fcolor.toQColor(), penWidth)); if ( bcolor.isValid() ) { painter.setBrush(QBrush(bcolor.toQColor())); } else { painter.setBrush(Qt::NoBrush); } int offset = painter.testRenderHint(QPainter::Antialiasing) ? 1 : 0; painter.drawEllipse( x + penWidth / 2 + offset, y + penWidth / 2 + offset, qMax(1, width - penWidth - offset), qMax(1, height - penWidth - offset)); } //--------------------------------------------------------------------- diff --git a/tools/rectangular/kpToolRectangle.cpp b/tools/rectangular/kpToolRectangle.cpp index ed179b20..1aa3f876 100644 --- a/tools/rectangular/kpToolRectangle.cpp +++ b/tools/rectangular/kpToolRectangle.cpp @@ -1,87 +1,87 @@ /* Copyright (c) 2003-2007 Clarence Dang Copyright (c) 2017 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 "kpToolRectangle.h" #include "environments/tools/kpToolEnvironment.h" #include "imagelib/kpColor.h" #include #include #include #include //--------------------------------------------------------------------- kpToolRectangle::kpToolRectangle (kpToolEnvironment *environ, QObject *parent) : kpToolRectangularBase (i18n ("Rectangle"), i18n ("Draws rectangles and squares"), &kpToolRectangle::drawRect, Qt::Key_R, - environ, parent, "tool_rectangle") + environ, parent, QStringLiteral("tool_rectangle")) { } //--------------------------------------------------------------------- void kpToolRectangle::drawRect(kpImage *image, int x, int y, int width, int height, const kpColor &fcolor, int penWidth, const kpColor &bcolor) { if ( (width == 0) || (height == 0) ) { return; } QPainter painter(image); painter.setRenderHint(QPainter::Antialiasing, kpToolEnvironment::drawAntiAliased); if ( ((2 * penWidth) > width) || ((2 * penWidth) > height) ) { penWidth = qMin(width, height) / 2; } painter.setPen(QPen(fcolor.toQColor(), penWidth, Qt::SolidLine, Qt::SquareCap, Qt::MiterJoin)); if ( bcolor.isValid() ) { painter.setBrush(QBrush(bcolor.toQColor())); } else { painter.setBrush(Qt::NoBrush); } int offset = painter.testRenderHint(QPainter::Antialiasing) ? 1 : 0; painter.drawRect( x + penWidth / 2 + offset, y + penWidth / 2 + offset, qMax(1, width - penWidth - offset), qMax(1, height - penWidth - offset)); } //--------------------------------------------------------------------- diff --git a/tools/rectangular/kpToolRoundedRectangle.cpp b/tools/rectangular/kpToolRoundedRectangle.cpp index 82ac0633..4d3dadc5 100644 --- a/tools/rectangular/kpToolRoundedRectangle.cpp +++ b/tools/rectangular/kpToolRoundedRectangle.cpp @@ -1,89 +1,89 @@ /* Copyright (c) 2003-2007 Clarence Dang Copyright (c) 2017 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 "kpToolRoundedRectangle.h" #include "environments/tools/kpToolEnvironment.h" #include "imagelib/kpColor.h" #include #include #include #include //--------------------------------------------------------------------- kpToolRoundedRectangle::kpToolRoundedRectangle (kpToolEnvironment *environ, QObject *parent) : kpToolRectangularBase (i18n ("Rounded Rectangle"), i18n ("Draws rectangles and squares with rounded corners"), &kpToolRoundedRectangle::drawRoundedRect, Qt::Key_U, - environ, parent, "tool_rounded_rectangle") + environ, parent, QStringLiteral("tool_rounded_rectangle")) { } //--------------------------------------------------------------------- void kpToolRoundedRectangle::drawRoundedRect(kpImage *image, int x, int y, int width, int height, const kpColor &fcolor, int penWidth, const kpColor &bcolor) { if ( (width == 0) || (height == 0) ) { return; } QPainter painter(image); painter.setRenderHint(QPainter::Antialiasing, kpToolEnvironment::drawAntiAliased); if ( ((2 * penWidth) > width) || ((2 * penWidth) > height) ) { penWidth = qMin(width, height) / 2; } painter.setPen(QPen(fcolor.toQColor(), penWidth, Qt::SolidLine, Qt::SquareCap, Qt::MiterJoin)); if ( bcolor.isValid() ) { painter.setBrush(QBrush(bcolor.toQColor())); } else { painter.setBrush(Qt::NoBrush); } int offset = painter.testRenderHint(QPainter::Antialiasing) ? 1 : 0; int radius = qMin(width, height) / 4; painter.drawRoundedRect( x + penWidth / 2 + offset, y + penWidth / 2 + offset, qMax(1, width - penWidth - offset), qMax(1, height - penWidth - offset), radius, radius); } //--------------------------------------------------------------------- diff --git a/tools/selection/image/kpToolEllipticalSelection.cpp b/tools/selection/image/kpToolEllipticalSelection.cpp index 0ae0d30c..d74ec667 100644 --- a/tools/selection/image/kpToolEllipticalSelection.cpp +++ b/tools/selection/image/kpToolEllipticalSelection.cpp @@ -1,79 +1,79 @@ /* 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_ELLIPTICAL_SELECTION 0 #include "kpToolEllipticalSelection.h" #include "kpLogCategories.h" #include "document/kpDocument.h" #include "layers/selections/image/kpEllipticalImageSelection.h" #include "environments/tools/selection/kpToolSelectionEnvironment.h" #include kpToolEllipticalSelection::kpToolEllipticalSelection (kpToolSelectionEnvironment *environ, QObject *parent) : kpAbstractImageSelectionTool (i18n ("Selection (Elliptical)"), i18n ("Makes an elliptical or circular selection"), Qt::Key_I, environ, parent, - "tool_elliptical_selection") + QStringLiteral("tool_elliptical_selection")) { } kpToolEllipticalSelection::~kpToolEllipticalSelection () = default; // protected virtual [base kpAbstractSelectionTool] bool kpToolEllipticalSelection::drawCreateMoreSelectionAndUpdateStatusBar ( bool dragAccepted, const QPoint &accidentalDragAdjustedPoint, const QRect &normalizedRect) { // Prevent unintentional creation of 1-pixel selections. if (!dragAccepted && accidentalDragAdjustedPoint == startPoint ()) { #if DEBUG_KP_TOOL_ELLIPTICAL_SELECTION && 1 qCDebug(kpLogTools) << "\tnon-text NOP - return"; #endif setUserShapePoints (accidentalDragAdjustedPoint); return false; } Q_ASSERT (accidentalDragAdjustedPoint == currentPoint ()); document ()->setSelection ( kpEllipticalImageSelection ( normalizedRect, environ ()->imageSelectionTransparency ())); setUserShapePoints (startPoint (), currentPoint ()); return true; } diff --git a/tools/selection/image/kpToolFreeFormSelection.cpp b/tools/selection/image/kpToolFreeFormSelection.cpp index c2886115..9afb1e44 100644 --- a/tools/selection/image/kpToolFreeFormSelection.cpp +++ b/tools/selection/image/kpToolFreeFormSelection.cpp @@ -1,139 +1,139 @@ /* 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") + QStringLiteral("tool_free_form_selection")) { } //--------------------------------------------------------------------- kpToolFreeFormSelection::~kpToolFreeFormSelection () = default; //--------------------------------------------------------------------- // 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 << ")"; #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 == static_cast (document ()->selection ())); const kpFreeFormImageSelection *oldPointsSel = nullptr; if (document ()->selection ()) { kpAbstractSelection *sel = document ()->selection (); Q_ASSERT (dynamic_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 (); #endif setUserShapePoints (accidentalDragAdjustedPoint); return true; } //--------------------------------------------------------------------- diff --git a/tools/selection/image/kpToolRectSelection.cpp b/tools/selection/image/kpToolRectSelection.cpp index 4ebdba99..a6d0732e 100644 --- a/tools/selection/image/kpToolRectSelection.cpp +++ b/tools/selection/image/kpToolRectSelection.cpp @@ -1,81 +1,81 @@ /* 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_RECT_SELECTION 0 #include "kpToolRectSelection.h" #include "kpLogCategories.h" #include "document/kpDocument.h" #include "layers/selections/image/kpRectangularImageSelection.h" #include "environments/tools/selection/kpToolSelectionEnvironment.h" #include kpToolRectSelection::kpToolRectSelection (kpToolSelectionEnvironment *environ, QObject *parent) : kpAbstractImageSelectionTool (i18n ("Selection (Rectangular)"), i18n ("Makes a rectangular selection"), Qt::Key_S, environ, parent, - "tool_rect_selection") + QStringLiteral("tool_rect_selection")) { } kpToolRectSelection::~kpToolRectSelection () = default; // protected virtual [base kpAbstractSelectionTool] bool kpToolRectSelection::drawCreateMoreSelectionAndUpdateStatusBar ( bool dragAccepted, const QPoint &accidentalDragAdjustedPoint, const QRect &normalizedRect) { // Prevent unintentional creation of 1-pixel selections. // REFACTOR: This line is duplicated code with other tools. if (!dragAccepted && accidentalDragAdjustedPoint == startPoint ()) { #if DEBUG_KP_TOOL_RECT_SELECTION && 1 qCDebug(kpLogTools) << "\tnon-text NOP - return"; #endif setUserShapePoints (accidentalDragAdjustedPoint); return false; } Q_ASSERT (accidentalDragAdjustedPoint == currentPoint ()); const QRect usefulRect = normalizedRect.intersected (document ()->rect ()); document ()->setSelection ( kpRectangularImageSelection ( usefulRect, environ ()->imageSelectionTransparency ())); setUserShapePoints (startPoint (), QPoint (qMax (0, qMin (currentPoint ().x (), document ()->width () - 1)), qMax (0, qMin (currentPoint ().y (), document ()->height () - 1)))); return true; } diff --git a/tools/selection/text/kpToolText.cpp b/tools/selection/text/kpToolText.cpp index c1c6966a..9e0d3651 100644 --- a/tools/selection/text/kpToolText.cpp +++ b/tools/selection/text/kpToolText.cpp @@ -1,222 +1,222 @@ // REFACTOR: For all files involved in the class, refactor remaining bits and pieces and add APIDoc /* 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/text/kpToolTextGiveContentCommand.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 kpToolText::kpToolText (kpToolSelectionEnvironment *environ, QObject *parent) : kpAbstractSelectionTool (i18n ("Text"), i18n ("Writes text"), Qt::Key_T, - environ, parent, "tool_text"), + environ, parent, QStringLiteral("tool_text")), d (new kpToolTextPrivate ()) { } kpToolText::~kpToolText () { delete d; } // protected virtual [kpAbstractSelectionTool] kpAbstractSelectionContentCommand *kpToolText::newGiveContentCommand () const { kpTextSelection *textSel = document ()->textSelection (); #if DEBUG_KP_TOOL_TEXT qCDebug(kpLogTools) << "kpToolText::newGiveContentCommand()" << " textSel=" << textSel << "; hasContent=" << textSel->hasContent (); #endif Q_ASSERT (textSel && !textSel->hasContent ()); return new kpToolTextGiveContentCommand ( *textSel, QString()/*uninteresting child of macro cmd*/, environ ()->commandEnvironment ()); } // protected virtual [kpAbstractSelectionTool] QString kpToolText::nameOfCreateCommand () const { return i18n ("Text: Create Box"); } // protected virtual [base kpAbstractSelectionTool] void kpToolText::setSelectionBorderForHaventBegunDraw () { viewManager ()->setQueueUpdates (); { kpAbstractSelectionTool::setSelectionBorderForHaventBegunDraw (); viewManager ()->setTextCursorEnabled (true); } viewManager ()->restoreQueueUpdates (); } // public virtual [base kpAbstractSelectionTool] void kpToolText::begin () { #if DEBUG_KP_TOOL_TEXT && 1 qCDebug(kpLogTools) << "kpToolText::begin()"; #endif environ ()->enableTextToolBarActions (true); // We don't actually need this since begin() already calls it via // setSelectionBorderForHaventBegunDraw(). We leave this in for // consistency with end(). viewManager ()->setTextCursorEnabled (true); viewManager()->setInputMethodEnabled (true); endTypingCommands (); kpAbstractSelectionTool::begin (); } // public virtual [base kpAbstractSelectionTool] void kpToolText::end () { #if DEBUG_KP_TOOL_TEXT && 1 qCDebug(kpLogTools) << "kpToolText::end()"; #endif kpAbstractSelectionTool::end (); viewManager()->setInputMethodEnabled (false); viewManager ()->setTextCursorEnabled (false); environ ()->enableTextToolBarActions (false); } // public bool kpToolText::hasBegunText () const { return (d->insertCommand || d->enterCommand || d->backspaceCommand || d->backspaceWordCommand || d->deleteCommand || d->deleteWordCommand); } // public virtual [base kpTool] bool kpToolText::hasBegunShape () const { return (hasBegunDraw () || hasBegunText ()); } // protected virtual [base kpAbstractSelectionTool] kpAbstractSelectionTool::DrawType kpToolText::calculateDrawTypeInsideSelection () const { if (onSelectionToSelectText () && !controlOrShiftPressed ()) { return kpAbstractSelectionTool::SelectText; } return kpAbstractSelectionTool::calculateDrawTypeInsideSelection (); } // public virtual [base kpAbstractSelectionTool] void kpToolText::cancelShape () { #if DEBUG_KP_TOOL_TEXT qCDebug(kpLogTools) << "kpToolText::cancelShape()"; #endif if (drawType () != None) { kpAbstractSelectionTool::cancelShape (); } else if (hasBegunText ()) { endTypingCommands (); commandHistory ()->undo (); } else { kpAbstractSelectionTool::cancelShape (); } } // public virtual [base kpTool] void kpToolText::endShape (const QPoint &thisPoint, const QRect &normalizedRect) { #if DEBUG_KP_TOOL_TEXT qCDebug(kpLogTools) << "kpToolText::endShape()"; #endif if (drawType () != None) { kpAbstractSelectionTool::endDraw (thisPoint, normalizedRect); } else if (hasBegunText ()) { endTypingCommands (); } else { kpAbstractSelectionTool::endDraw (thisPoint, normalizedRect); } } // protected virtual [base kpAbstractSelectionTool] QVariant kpToolText::operation (DrawType drawType, Operation op, const QVariant &data1, const QVariant &data2) { if (drawType == SelectText) { return selectTextOperation (op, data1, data2); } return kpAbstractSelectionTool::operation (drawType, op, data1, data2); } diff --git a/widgets/imagelib/effects/kpEffectBalanceWidget.cpp b/widgets/imagelib/effects/kpEffectBalanceWidget.cpp index f5c66217..489b9231 100644 --- a/widgets/imagelib/effects/kpEffectBalanceWidget.cpp +++ b/widgets/imagelib/effects/kpEffectBalanceWidget.cpp @@ -1,330 +1,330 @@ /* 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 "kpEffectBalanceWidget.h" #include "imagelib/effects/kpEffectBalance.h" #include "commands/imagelib/effects/kpEffectBalanceCommand.h" #include "pixmapfx/kpPixmapFX.h" #include "kpLogCategories.h" #include #include "kpNumInput.h" #include #include #include #include #include #include #if DEBUG_KP_EFFECT_BALANCE #include #endif kpEffectBalanceWidget::kpEffectBalanceWidget (bool actOnSelection, QWidget *parent) : kpEffectWidgetBase (actOnSelection, parent) { auto *lay = new QGridLayout (this); lay->setContentsMargins(0, 0, 0, 0); auto *brightnessLabel = new QLabel (i18n ("&Brightness:"), this); m_brightnessInput = new kpIntNumInput (0/*value*/, this); m_brightnessInput->setRange (-50, 50); auto *brightnessResetPushButton = new QPushButton (i18n ("Re&set"), this); auto *contrastLabel = new QLabel (i18n ("Co&ntrast:"), this); m_contrastInput = new kpIntNumInput (0/*value*/, this); m_contrastInput->setRange (-50, 50); auto *contrastResetPushButton = new QPushButton (i18n ("&Reset"), this); auto *gammaLabel = new QLabel (i18n ("&Gamma:"), this); m_gammaInput = new kpIntNumInput (0/*value*/, this); m_gammaInput->setRange (-50, 50); // TODO: This is what should be shown in the m_gammaInput spinbox m_gammaLabel = new QLabel (this); // TODO: This doesn't seem to be wide enough with some fonts so the // whole layout moves when we drag the gamma slider. - m_gammaLabel->setMinimumWidth (m_gammaLabel->fontMetrics ().width (QLatin1String (" 10.00 "))); + m_gammaLabel->setMinimumWidth (m_gammaLabel->fontMetrics ().width (QStringLiteral (" 10.00 "))); m_gammaLabel->setAlignment (m_gammaLabel->alignment () | Qt::AlignRight); auto *gammaResetPushButton = new QPushButton (i18n ("Rese&t"), this); auto *spaceWidget = new QLabel (this); spaceWidget->setFixedSize (1, fontMetrics ().height () / 4); auto *channelLabel = new QLabel (i18n ("C&hannels:"), this); m_channelsComboBox = new QComboBox (this); m_channelsComboBox->addItem (i18n ("All")); m_channelsComboBox->addItem (i18n ("Red")); m_channelsComboBox->addItem (i18n ("Green")); m_channelsComboBox->addItem (i18n ("Blue")); auto *resetPushButton = new QPushButton (i18n ("Reset &All Values"), this); brightnessLabel->setBuddy (m_brightnessInput); contrastLabel->setBuddy (m_contrastInput); gammaLabel->setBuddy (m_gammaInput); channelLabel->setBuddy (m_channelsComboBox); lay->addWidget (brightnessLabel, 0, 0); lay->addWidget (m_brightnessInput, 0, 1, 1, 2); lay->addWidget (brightnessResetPushButton, 0, 4); lay->addWidget (contrastLabel, 1, 0); lay->addWidget (m_contrastInput, 1, 1, 1, 2); lay->addWidget (contrastResetPushButton, 1, 4); lay->addWidget (gammaLabel, 2, 0); lay->addWidget (m_gammaInput, 2, 1, 1, 2); lay->addWidget (m_gammaLabel, 2, 3); lay->addWidget (gammaResetPushButton, 2, 4); lay->addWidget (spaceWidget, 3, 0, 1, 5); lay->addWidget (resetPushButton, 4, 2, 1, 3, Qt::AlignRight); lay->addWidget (channelLabel, 4, 0); lay->addWidget (m_channelsComboBox, 4, 1, Qt::AlignLeft); //lay->addWidget (resetPushButton, 4, 2, Qt::AlignRight); lay->setColumnStretch (1, 1); // (no need for settingsChangedDelayed() since BCG effect is so fast :)) connect (m_brightnessInput, &kpIntNumInput::valueChanged, this, &kpEffectBalanceWidget::settingsChangedNoWaitCursor); connect (m_contrastInput, &kpIntNumInput::valueChanged, this, &kpEffectBalanceWidget::settingsChangedNoWaitCursor); connect (m_gammaInput, &kpIntNumInput::valueChanged, this, &kpEffectBalanceWidget::recalculateGammaLabel); connect (m_gammaInput, &kpIntNumInput::valueChanged, this, &kpEffectBalanceWidget::settingsChangedNoWaitCursor); connect (m_channelsComboBox, static_cast(&QComboBox::activated), this, &kpEffectBalanceWidget::settingsChanged); connect (brightnessResetPushButton, &QPushButton::clicked, this, &kpEffectBalanceWidget::resetBrightness); connect (contrastResetPushButton, &QPushButton::clicked, this, &kpEffectBalanceWidget::resetContrast); connect (gammaResetPushButton, &QPushButton::clicked, this, &kpEffectBalanceWidget::resetGamma); connect (resetPushButton, &QPushButton::clicked, this, &kpEffectBalanceWidget::resetAll); recalculateGammaLabel (); } kpEffectBalanceWidget::~kpEffectBalanceWidget () = default; // public virtual [base kpEffectWidgetBase] QString kpEffectBalanceWidget::caption () const { return i18n ("Settings"); } // public virtual [base kpEffectWidgetBase] bool kpEffectBalanceWidget::isNoOp () const { return (brightness () == 0 && contrast () == 0 && gamma () == 0); } // public virtual [base kpEffectWidgetBase] kpImage kpEffectBalanceWidget::applyEffect (const kpImage &image) { return kpEffectBalance::applyEffect (image, channels (), brightness (), contrast (), gamma ()); } // public virtual [base kpEffectWidgetBase] kpEffectCommandBase *kpEffectBalanceWidget::createCommand ( kpCommandEnvironment *cmdEnviron) const { return new kpEffectBalanceCommand (channels (), brightness (), contrast (), gamma (), m_actOnSelection, cmdEnviron); } // protected int kpEffectBalanceWidget::channels () const { switch (m_channelsComboBox->currentIndex ()) { default: case 0: return kpEffectBalance::RGB; case 1: return kpEffectBalance::Red; case 2: return kpEffectBalance::Green; case 3: return kpEffectBalance::Blue; } } // protected int kpEffectBalanceWidget::brightness () const { return m_brightnessInput->value (); } // protected int kpEffectBalanceWidget::contrast () const { return m_contrastInput->value (); } // protected int kpEffectBalanceWidget::gamma () const { return m_gammaInput->value (); } // protected slot void kpEffectBalanceWidget::recalculateGammaLabel () { m_gammaLabel->setText ( QLatin1String (" ") + QString::number (std::pow (10, gamma () / 50.0), 'f'/*[-]9.9*/, 2/*precision*/) + QLatin1String (" ")); m_gammaLabel->repaint (); } // protected slot void kpEffectBalanceWidget::resetBrightness () { if (brightness () == 0) { return; } bool sb = signalsBlocked (); if (!sb) { blockSignals (true); } m_brightnessInput->setValue (0); if (!sb) { blockSignals (false); } // Immediate update (if signals aren't blocked) emit settingsChanged (); } // protected slot void kpEffectBalanceWidget::resetContrast () { if (contrast () == 0) { return; } bool sb = signalsBlocked (); if (!sb) { blockSignals (true); } m_contrastInput->setValue (0); if (!sb) { blockSignals (false); } // Immediate update (if signals aren't blocked) emit settingsChanged (); } // protected slot void kpEffectBalanceWidget::resetGamma () { if (gamma () == 0) { return; } bool sb = signalsBlocked (); if (!sb) { blockSignals (true); } m_gammaInput->setValue (0); recalculateGammaLabel (); if (!sb) { blockSignals (false); } // Immediate update (if signals aren't blocked) emit settingsChanged (); } // protected slot void kpEffectBalanceWidget::resetAll () { if (isNoOp ()) { return; } // Prevent multiple settingsChanged() which would normally result in // redundant, expensive preview repaints blockSignals (true); resetBrightness (); resetContrast (); resetGamma (); recalculateGammaLabel (); blockSignals (false); emit settingsChanged (); } diff --git a/widgets/imagelib/effects/kpNumInput.cpp b/widgets/imagelib/effects/kpNumInput.cpp index ca8e8fe7..91ed79f5 100644 --- a/widgets/imagelib/effects/kpNumInput.cpp +++ b/widgets/imagelib/effects/kpNumInput.cpp @@ -1,710 +1,710 @@ /* This file is part of the KDE libraries * Initial implementation: * Copyright (c) 1997 Patrick Dowler * Rewritten and maintained by: * Copyright (c) 2000 Dirk Mueller * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * 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 * Library General Public License for more details. * * You should have received a copy of the GNU Library General Public License * along with this library; see the file COPYING.LIB. If not, write to * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, * Boston, MA 02110-1301, USA. */ #include "kpNumInput.h" #include #include #include #include #include #include #include #include #include #include static inline int calcDiffByTen(int x, int y) { // calculate ( x - y ) / 10 without overflowing ints: return (x / 10) - (y / 10) + (x % 10 - y % 10) / 10; } // ---------------------------------------------------------------------------- class kpNumInputPrivate { public: kpNumInputPrivate(kpNumInput *q) : q(q), column1Width(0), column2Width(0), label(nullptr), slider(nullptr), labelAlignment(nullptr) { } static kpNumInputPrivate *get(const kpNumInput *i) { return i->d; } kpNumInput *q; int column1Width, column2Width; QLabel *label; QSlider *slider; QSize sliderSize, labelSize; Qt::Alignment labelAlignment; }; #define K_USING_kpNumInput_P(_d) kpNumInputPrivate *_d = kpNumInputPrivate::get(this) kpNumInput::kpNumInput(QWidget *parent) : QWidget(parent), d(new kpNumInputPrivate(this)) { setSizePolicy(QSizePolicy(QSizePolicy::Minimum, QSizePolicy::Fixed)); setFocusPolicy(Qt::StrongFocus); - KConfigDialogManager::changedMap()->insert("kpIntNumInput", SIGNAL(valueChanged(int))); - KConfigDialogManager::changedMap()->insert("QSpinBox", SIGNAL(valueChanged(int))); - KConfigDialogManager::changedMap()->insert("kpDoubleSpinBox", SIGNAL(valueChanged(double))); + KConfigDialogManager::changedMap()->insert(QStringLiteral("kpIntNumInput"), SIGNAL(valueChanged(int))); + KConfigDialogManager::changedMap()->insert(QStringLiteral("QSpinBox"), SIGNAL(valueChanged(int))); + KConfigDialogManager::changedMap()->insert(QStringLiteral("kpDoubleSpinBox"), SIGNAL(valueChanged(double))); } kpNumInput::~kpNumInput() { delete d; } QSlider *kpNumInput::slider() const { return d->slider; } bool kpNumInput::showSlider() const { return d->slider; } void kpNumInput::setLabel(const QString &label, Qt::Alignment a) { if (label.isEmpty()) { delete d->label; d->label = nullptr; d->labelAlignment = nullptr; } else { if (!d->label) { d->label = new QLabel(this); } d->label->setText(label); - d->label->setObjectName("kpNumInput::QLabel"); + d->label->setObjectName(QStringLiteral("kpNumInput::QLabel")); d->label->setAlignment(a); // if no vertical alignment set, use Top alignment if (!(a & (Qt::AlignTop | Qt::AlignBottom | Qt::AlignVCenter))) { a |= Qt::AlignTop; } d->labelAlignment = a; } layout(); } QString kpNumInput::label() const { return d->label ? d->label->text() : QString(); } void kpNumInput::layout() { // label sizeHint d->labelSize = (d->label ? d->label->sizeHint() : QSize(0, 0)); if (d->label && (d->labelAlignment & Qt::AlignVCenter)) { d->column1Width = d->labelSize.width() + 4; } else { d->column1Width = 0; } // slider sizeHint d->sliderSize = (d->slider ? d->slider->sizeHint() : QSize(0, 0)); doLayout(); } QSize kpNumInput::sizeHint() const { return minimumSizeHint(); } void kpNumInput::setSteps(int minor, int major) { if (d->slider) { d->slider->setSingleStep(minor); d->slider->setPageStep(major); } } // ---------------------------------------------------------------------------- class kpIntNumInput::kpIntNumInputPrivate { public: kpIntNumInput *q; QSpinBox *intSpinBox; QSize intSpinBoxSize; kpIntNumInputPrivate(kpIntNumInput *q) : q(q) {} }; kpIntNumInput::kpIntNumInput(QWidget *parent) : kpNumInput(parent) , d(new kpIntNumInputPrivate(this)) { initWidget(0); } kpIntNumInput::kpIntNumInput(int val, QWidget *parent) : kpNumInput(parent) , d(new kpIntNumInputPrivate(this)) { initWidget(val); } QSpinBox *kpIntNumInput::spinBox() const { return d->intSpinBox; } void kpIntNumInput::initWidget(int val) { d->intSpinBox = new QSpinBox(this); d->intSpinBox->setRange(INT_MIN, INT_MAX); d->intSpinBox->setSingleStep(1); d->intSpinBox->setValue(val); - d->intSpinBox->setObjectName("kpIntNumInput::QSpinBox"); + d->intSpinBox->setObjectName(QStringLiteral("kpIntNumInput::QSpinBox")); connect(d->intSpinBox, QOverload::of(&QSpinBox::valueChanged), this, &kpIntNumInput::spinValueChanged); setFocusProxy(d->intSpinBox); layout(); } void kpIntNumInput::spinValueChanged(int val) { K_USING_kpNumInput_P(priv); if (priv->slider) { priv->slider->setValue(val); } emit valueChanged(val); } void kpIntNumInput::setRange(int lower, int upper, int singleStep) { if (upper < lower || singleStep <= 0) { qDebug() << "WARNING: kpIntNumInput::setRange() called with bad arguments. Ignoring call..."; return; } d->intSpinBox->setMinimum(lower); d->intSpinBox->setMaximum(upper); d->intSpinBox->setSingleStep(singleStep); singleStep = d->intSpinBox->singleStep(); // maybe QRangeControl didn't like our lineStep? layout(); // update slider information K_USING_kpNumInput_P(priv); if (!priv->slider) { priv->slider = new QSlider(Qt::Horizontal, this); connect(priv->slider, &QSlider::valueChanged, d->intSpinBox, &QSpinBox::setValue); priv->slider->setTickPosition(QSlider::TicksBelow); layout(); } const int value = d->intSpinBox->value(); priv->slider->setRange(d->intSpinBox->minimum(), d->intSpinBox->maximum()); priv->slider->setPageStep(d->intSpinBox->singleStep()); priv->slider->setValue(value); // calculate (upper-lower)/10 without overflowing int's: const int major = calcDiffByTen(d->intSpinBox->maximum(), d->intSpinBox->minimum()); priv->slider->setSingleStep(d->intSpinBox->singleStep()); priv->slider->setPageStep(qMax(1, major)); priv->slider->setTickInterval(major); } void kpIntNumInput::setMinimum(int min) { setRange(min, d->intSpinBox->maximum(), d->intSpinBox->singleStep()); } int kpIntNumInput::minimum() const { return d->intSpinBox->minimum(); } void kpIntNumInput::setMaximum(int max) { setRange(d->intSpinBox->minimum(), max, d->intSpinBox->singleStep()); } int kpIntNumInput::maximum() const { return d->intSpinBox->maximum(); } int kpIntNumInput::singleStep() const { return d->intSpinBox->singleStep(); } void kpIntNumInput::setSingleStep(int singleStep) { d->intSpinBox->setSingleStep(singleStep); } void kpIntNumInput::setSuffix(const QString &suffix) { d->intSpinBox->setSuffix(suffix); layout(); } QString kpIntNumInput::suffix() const { return d->intSpinBox->suffix(); } void kpIntNumInput::setEditFocus(bool mark) { if (mark) { d->intSpinBox->setFocus(); } } QSize kpIntNumInput::minimumSizeHint() const { K_USING_kpNumInput_P(priv); ensurePolished(); int w; int h; h = qMax(d->intSpinBoxSize.height(), priv->sliderSize.height()); // if in extra row, then count it here if (priv->label && (priv->labelAlignment & (Qt::AlignBottom | Qt::AlignTop))) { h += 4 + priv->labelSize.height(); } else { // label is in the same row as the other widgets h = qMax(h, priv->labelSize.height() + 2); } const int spacingHint = style()->pixelMetric(QStyle::PM_DefaultLayoutSpacing); w = priv->slider ? priv->slider->sizeHint().width() + spacingHint : 0; w += priv->column1Width + priv->column2Width; if (priv->labelAlignment & (Qt::AlignTop | Qt::AlignBottom)) { w = qMax(w, priv->labelSize.width() + 4); } return {w, h}; } void kpIntNumInput::doLayout() { K_USING_kpNumInput_P(priv); d->intSpinBoxSize = d->intSpinBox->sizeHint(); priv->column2Width = d->intSpinBoxSize.width(); if (priv->label) { priv->label->setBuddy(d->intSpinBox); } } void kpIntNumInput::resizeEvent(QResizeEvent *e) { K_USING_kpNumInput_P(priv); int w = priv->column1Width; int h = 0; const int spacingHint = style()->pixelMetric(QStyle::PM_DefaultLayoutSpacing); if (priv->label && (priv->labelAlignment & Qt::AlignTop)) { priv->label->setGeometry(0, 0, e->size().width(), priv->labelSize.height()); h += priv->labelSize.height() + spacingHint; } if (priv->label && (priv->labelAlignment & Qt::AlignVCenter)) { priv->label->setGeometry(0, 0, w, d->intSpinBoxSize.height()); } if (qApp->layoutDirection() == Qt::RightToLeft) { d->intSpinBox->setGeometry(w, h, priv->slider ? priv->column2Width : qMax(priv->column2Width, e->size().width() - w), d->intSpinBoxSize.height()); w += priv->column2Width + spacingHint; if (priv->slider) { priv->slider->setGeometry(w, h, e->size().width() - w, d->intSpinBoxSize.height() + spacingHint); } } else if (priv->slider) { priv->slider->setGeometry(w, h, e->size().width() - (w + priv->column2Width + spacingHint), d->intSpinBoxSize.height() + spacingHint); d->intSpinBox->setGeometry(w + priv->slider->size().width() + spacingHint, h, priv->column2Width, d->intSpinBoxSize.height()); } else { d->intSpinBox->setGeometry(w, h, qMax(priv->column2Width, e->size().width() - w), d->intSpinBoxSize.height()); } h += d->intSpinBoxSize.height() + 2; if (priv->label && (priv->labelAlignment & Qt::AlignBottom)) { priv->label->setGeometry(0, h, priv->labelSize.width(), priv->labelSize.height()); } } kpIntNumInput::~kpIntNumInput() { delete d; } void kpIntNumInput::setValue(int val) { d->intSpinBox->setValue(val); // slider value is changed by spinValueChanged } int kpIntNumInput::value() const { return d->intSpinBox->value(); } void kpIntNumInput::setSpecialValueText(const QString &text) { d->intSpinBox->setSpecialValueText(text); layout(); } QString kpIntNumInput::specialValueText() const { return d->intSpinBox->specialValueText(); } void kpIntNumInput::setLabel(const QString &label, Qt::Alignment a) { K_USING_kpNumInput_P(priv); kpNumInput::setLabel(label, a); if (priv->label) { priv->label->setBuddy(d->intSpinBox); } } // ---------------------------------------------------------------------------- class kpDoubleNumInput::kpDoubleNumInputPrivate { public: kpDoubleNumInputPrivate() : spin(nullptr) {} QDoubleSpinBox *spin; QSize editSize; QString specialValue; }; kpDoubleNumInput::kpDoubleNumInput(QWidget *parent) : kpNumInput(parent) , d(new kpDoubleNumInputPrivate()) { initWidget(0.0, 0.0, 9999.0, 0.01, 2); } kpDoubleNumInput::kpDoubleNumInput(double lower, double upper, double value, QWidget *parent, double singleStep, int precision) : kpNumInput(parent) , d(new kpDoubleNumInputPrivate()) { initWidget(value, lower, upper, singleStep, precision); } kpDoubleNumInput::~kpDoubleNumInput() { delete d; } QString kpDoubleNumInput::specialValueText() const { return d->specialValue; } void kpDoubleNumInput::initWidget(double value, double lower, double upper, double singleStep, int precision) { d->spin = new QDoubleSpinBox(this); d->spin->setRange(lower, upper); d->spin->setSingleStep(singleStep); d->spin->setValue(value); d->spin->setDecimals(precision); - d->spin->setObjectName("kpDoubleNumInput::QDoubleSpinBox"); + d->spin->setObjectName(QStringLiteral("kpDoubleNumInput::QDoubleSpinBox")); setFocusProxy(d->spin); connect(d->spin, QOverload::of(&QDoubleSpinBox::valueChanged), this, &kpDoubleNumInput::valueChanged); layout(); } double kpDoubleNumInput::mapSliderToSpin(int val) const { K_USING_kpNumInput_P(priv); // map [slidemin,slidemax] to [spinmin,spinmax] const double spinmin = d->spin->minimum(); const double spinmax = d->spin->maximum(); const double slidemin = priv->slider->minimum(); // cast int to double to avoid const double slidemax = priv->slider->maximum(); // overflow in rel denominator const double rel = (double(val) - slidemin) / (slidemax - slidemin); return spinmin + rel * (spinmax - spinmin); } void kpDoubleNumInput::sliderMoved(int val) { d->spin->setValue(mapSliderToSpin(val)); } void kpDoubleNumInput::spinBoxChanged(double val) { K_USING_kpNumInput_P(priv); const double spinmin = d->spin->minimum(); const double spinmax = d->spin->maximum(); const double slidemin = priv->slider->minimum(); // cast int to double to avoid const double slidemax = priv->slider->maximum(); // overflow in rel denominator const double rel = (val - spinmin) / (spinmax - spinmin); if (priv->slider) { priv->slider->blockSignals(true); priv->slider->setValue(qRound(slidemin + rel * (slidemax - slidemin))); priv->slider->blockSignals(false); } } QSize kpDoubleNumInput::minimumSizeHint() const { K_USING_kpNumInput_P(priv); ensurePolished(); int w; int h; h = qMax(d->editSize.height(), priv->sliderSize.height()); // if in extra row, then count it here if (priv->label && (priv->labelAlignment & (Qt::AlignBottom | Qt::AlignTop))) { h += 4 + priv->labelSize.height(); } else { // label is in the same row as the other widgets h = qMax(h, priv->labelSize.height() + 2); } const int spacingHint = style()->pixelMetric(QStyle::PM_DefaultLayoutSpacing); w = priv->slider ? priv->slider->sizeHint().width() + spacingHint : 0; w += priv->column1Width + priv->column2Width; if (priv->labelAlignment & (Qt::AlignTop | Qt::AlignBottom)) { w = qMax(w, priv->labelSize.width() + 4); } return {w, h}; } void kpDoubleNumInput::resizeEvent(QResizeEvent *e) { K_USING_kpNumInput_P(priv); int w = priv->column1Width; int h = 0; const int spacingHint = style()->pixelMetric(QStyle::PM_DefaultLayoutSpacing); if (priv->label && (priv->labelAlignment & Qt::AlignTop)) { priv->label->setGeometry(0, 0, e->size().width(), priv->labelSize.height()); h += priv->labelSize.height() + 4; } if (priv->label && (priv->labelAlignment & Qt::AlignVCenter)) { priv->label->setGeometry(0, 0, w, d->editSize.height()); } if (qApp->layoutDirection() == Qt::RightToLeft) { d->spin->setGeometry(w, h, priv->slider ? priv->column2Width : e->size().width() - w, d->editSize.height()); w += priv->column2Width + spacingHint; if (priv->slider) { priv->slider->setGeometry(w, h, e->size().width() - w, d->editSize.height() + spacingHint); } } else if (priv->slider) { priv->slider->setGeometry(w, h, e->size().width() - (priv->column1Width + priv->column2Width + spacingHint), d->editSize.height() + spacingHint); d->spin->setGeometry(w + priv->slider->width() + spacingHint, h, priv->column2Width, d->editSize.height()); } else { d->spin->setGeometry(w, h, e->size().width() - w, d->editSize.height()); } h += d->editSize.height() + 2; if (priv->label && (priv->labelAlignment & Qt::AlignBottom)) { priv->label->setGeometry(0, h, priv->labelSize.width(), priv->labelSize.height()); } } void kpDoubleNumInput::doLayout() { K_USING_kpNumInput_P(priv); d->editSize = d->spin->sizeHint(); priv->column2Width = d->editSize.width(); } void kpDoubleNumInput::setValue(double val) { d->spin->setValue(val); } void kpDoubleNumInput::setRange(double lower, double upper, double singleStep) { K_USING_kpNumInput_P(priv); QDoubleSpinBox *spin = d->spin; d->spin->setRange(lower, upper); d->spin->setSingleStep(singleStep); const double range = spin->maximum() - spin->minimum(); const double steps = range * std::pow(10.0, spin->decimals()); if (!priv->slider) { priv->slider = new QSlider(Qt::Horizontal, this); priv->slider->setTickPosition(QSlider::TicksBelow); // feedback line: when one moves, the other moves, too: connect(priv->slider, &QSlider::valueChanged, this, &kpDoubleNumInput::sliderMoved); layout(); } if (steps > 1000 ) { priv->slider->setRange(0, 1000); priv->slider->setSingleStep(1); priv->slider->setPageStep(50); } else { const int singleSteps = qRound(steps); priv->slider->setRange(0, singleSteps); priv->slider->setSingleStep(1); const int pageSteps = qBound(1, singleSteps / 20, 10); priv->slider->setPageStep(pageSteps); } spinBoxChanged(spin->value()); connect(spin, QOverload::of(&QDoubleSpinBox::valueChanged), this, &kpDoubleNumInput::spinBoxChanged); layout(); } void kpDoubleNumInput::setMinimum(double min) { setRange(min, maximum(), d->spin->singleStep()); } double kpDoubleNumInput::minimum() const { return d->spin->minimum(); } void kpDoubleNumInput::setMaximum(double max) { setRange(minimum(), max, d->spin->singleStep()); } double kpDoubleNumInput::maximum() const { return d->spin->maximum(); } double kpDoubleNumInput::singleStep() const { return d->spin->singleStep(); } void kpDoubleNumInput::setSingleStep(double singleStep) { d->spin->setSingleStep(singleStep); } double kpDoubleNumInput::value() const { return d->spin->value(); } QString kpDoubleNumInput::suffix() const { return d->spin->suffix(); } void kpDoubleNumInput::setSuffix(const QString &suffix) { d->spin->setSuffix(suffix); layout(); } void kpDoubleNumInput::setDecimals(int decimals) { d->spin->setDecimals(decimals); layout(); } int kpDoubleNumInput::decimals() const { return d->spin->decimals(); } void kpDoubleNumInput::setSpecialValueText(const QString &text) { d->spin->setSpecialValueText(text); layout(); } void kpDoubleNumInput::setLabel(const QString &label, Qt::Alignment a) { K_USING_kpNumInput_P(priv); kpNumInput::setLabel(label, a); if (priv->label) { priv->label->setBuddy(d->spin); } } #include "moc_kpNumInput.cpp" diff --git a/widgets/kpDocumentSaveOptionsWidget.cpp b/widgets/kpDocumentSaveOptionsWidget.cpp index f658af75..fed56424 100644 --- a/widgets/kpDocumentSaveOptionsWidget.cpp +++ b/widgets/kpDocumentSaveOptionsWidget.cpp @@ -1,754 +1,754 @@ /* 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 "widgets/kpDocumentSaveOptionsWidget.h" #include "kpDefs.h" #include "document/kpDocument.h" #include "dialogs/kpDocumentSaveOptionsPreviewDialog.h" #include "pixmapfx/kpPixmapFX.h" #include "generic/widgets/kpResizeSignallingLabel.h" #include "dialogs/imagelib/transforms/kpTransformPreviewDialog.h" #include "generic/kpWidgetMapper.h" #include "kpLogCategories.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include kpDocumentSaveOptionsWidget::kpDocumentSaveOptionsWidget ( const QImage &docPixmap, const kpDocumentSaveOptions &saveOptions, const kpDocumentMetaInfo &metaInfo, QWidget *parent) : QWidget (parent), m_visualParent (parent) { init (); setDocumentSaveOptions (saveOptions); setDocumentPixmap (docPixmap); setDocumentMetaInfo (metaInfo); } kpDocumentSaveOptionsWidget::kpDocumentSaveOptionsWidget ( QWidget *parent) : QWidget (parent), m_visualParent (parent) { init (); } // private void kpDocumentSaveOptionsWidget::init () { m_documentPixmap = nullptr; m_previewDialog = nullptr; m_visualParent = nullptr; m_colorDepthLabel = new QLabel (i18n ("Convert &to:"), this); m_colorDepthCombo = new QComboBox (this); m_colorDepthSpaceWidget = new QWidget (this); m_qualityLabel = new QLabel(i18n ("Quali&ty:"), this); m_qualityInput = new QSpinBox(this); // Note that we set min to 1 not 0 since "0 Quality" is a bit misleading // and 101 quality settings would be weird. So we lose 1 quality setting // according to QImage::save(). // TODO: 100 quality is also misleading since that implies perfect quality. m_qualityInput->setRange (1, 100); m_previewButton = new QPushButton (i18n ("&Preview"), this); m_previewButton->setCheckable (true); m_colorDepthLabel->setBuddy (m_colorDepthCombo); m_qualityLabel->setBuddy (m_qualityInput); auto *lay = new QHBoxLayout (this); lay->setContentsMargins(0, 0, 0, 0); lay->addWidget (m_colorDepthLabel, 0/*stretch*/, Qt::AlignLeft); lay->addWidget (m_colorDepthCombo, 0/*stretch*/); lay->addWidget (m_colorDepthSpaceWidget, 1/*stretch*/); lay->addWidget (m_qualityLabel, 0/*stretch*/, Qt::AlignLeft); lay->addWidget (m_qualityInput, 2/*stretch*/); lay->addWidget (m_previewButton, 0/*stretch*/, Qt::AlignRight); connect (m_colorDepthCombo, static_cast(&QComboBox::activated), this, &kpDocumentSaveOptionsWidget::slotColorDepthSelected); connect (m_colorDepthCombo, static_cast(&QComboBox::activated), this, &kpDocumentSaveOptionsWidget::updatePreview); connect (m_qualityInput, static_cast(&QSpinBox::valueChanged), this, &kpDocumentSaveOptionsWidget::updatePreviewDelayed); connect (m_previewButton, &QPushButton::toggled, this, &kpDocumentSaveOptionsWidget::showPreview); m_updatePreviewDelay = 200/*ms*/; m_updatePreviewTimer = new QTimer (this); m_updatePreviewTimer->setSingleShot (true); connect (m_updatePreviewTimer, &QTimer::timeout, this, &kpDocumentSaveOptionsWidget::updatePreview); m_updatePreviewDialogLastRelativeGeometryTimer = new QTimer (this); connect (m_updatePreviewDialogLastRelativeGeometryTimer, &QTimer::timeout, this, &kpDocumentSaveOptionsWidget::updatePreviewDialogLastRelativeGeometry); setMode (None); slotColorDepthSelected (); } kpDocumentSaveOptionsWidget::~kpDocumentSaveOptionsWidget () { #if DEBUG_KP_DOCUMENT_SAVE_OPTIONS_WIDGET qCDebug(kpLogWidgets) << "kpDocumentSaveOptionsWidget::()"; #endif hidePreview (); delete m_documentPixmap; } // public void kpDocumentSaveOptionsWidget::setVisualParent (QWidget *visualParent) { #if DEBUG_KP_DOCUMENT_SAVE_OPTIONS_WIDGET qCDebug(kpLogWidgets) << "kpDocumentSaveOptionsWidget::setVisualParent(" << visualParent << ")" << endl; #endif m_visualParent = visualParent; } // protected bool kpDocumentSaveOptionsWidget::mimeTypeHasConfigurableColorDepth () const { return kpDocumentSaveOptions::mimeTypeHasConfigurableColorDepth (mimeType ()); } // protected bool kpDocumentSaveOptionsWidget::mimeTypeHasConfigurableQuality () const { return kpDocumentSaveOptions::mimeTypeHasConfigurableQuality (mimeType ()); } // public QString kpDocumentSaveOptionsWidget::mimeType () const { return m_baseDocumentSaveOptions.mimeType (); } // public slots void kpDocumentSaveOptionsWidget::setMimeType (const QString &string) { #if DEBUG_KP_DOCUMENT_SAVE_OPTIONS_WIDGET qCDebug(kpLogWidgets) << "kpDocumentSaveOptionsWidget::setMimeType(" << string << ") maxColorDepth=" << kpDocumentSaveOptions::mimeTypeMaximumColorDepth (string) << endl; #endif const int newMimeTypeMaxDepth = kpDocumentSaveOptions::mimeTypeMaximumColorDepth (string); #if DEBUG_KP_DOCUMENT_SAVE_OPTIONS_WIDGET qCDebug(kpLogWidgets) << "\toldMimeType=" << mimeType () << " maxColorDepth=" << kpDocumentSaveOptions::mimeTypeMaximumColorDepth ( mimeType ()) << endl; #endif if (mimeType ().isEmpty () || kpDocumentSaveOptions::mimeTypeMaximumColorDepth (mimeType ()) != newMimeTypeMaxDepth) { m_colorDepthCombo->clear (); m_colorDepthCombo->insertItem (0, i18n ("Monochrome")); m_colorDepthCombo->insertItem (1, i18n ("Monochrome (Dithered)")); if (newMimeTypeMaxDepth >= 8) { m_colorDepthCombo->insertItem (2, i18n ("256 Color")); m_colorDepthCombo->insertItem (3, i18n ("256 Color (Dithered)")); } if (newMimeTypeMaxDepth >= 24) { m_colorDepthCombo->insertItem (4, i18n ("24-bit Color")); } if (m_colorDepthComboLastSelectedItem >= 0 && m_colorDepthComboLastSelectedItem < m_colorDepthCombo->count ()) { #if DEBUG_KP_DOCUMENT_SAVE_OPTIONS_WIDGET qCDebug(kpLogWidgets) << "\tsetting colorDepthCombo to " << m_colorDepthComboLastSelectedItem << endl; #endif m_colorDepthCombo->setCurrentIndex (m_colorDepthComboLastSelectedItem); } else { #if DEBUG_KP_DOCUMENT_SAVE_OPTIONS_WIDGET qCDebug(kpLogWidgets) << "\tsetting colorDepthCombo to max item since" << " m_colorDepthComboLastSelectedItem=" << m_colorDepthComboLastSelectedItem << " out of range" << endl; #endif m_colorDepthCombo->setCurrentIndex (m_colorDepthCombo->count () - 1); } } m_baseDocumentSaveOptions.setMimeType (string); if (mimeTypeHasConfigurableColorDepth ()) { setMode (ColorDepth); } else if (mimeTypeHasConfigurableQuality ()) { setMode (Quality); } else { setMode (None); } updatePreview (); } // public int kpDocumentSaveOptionsWidget::colorDepth () const { if (mode () & ColorDepth) { // The returned values match QImage's supported depths. switch (m_colorDepthCombo->currentIndex ()) { case 0: case 1: return 1; case 2: case 3: return 8; case 4: // 24-bit is known as 32-bit with QImage. return 32; default: return kpDocumentSaveOptions::invalidColorDepth (); } } else { return m_baseDocumentSaveOptions.colorDepth (); } } // public bool kpDocumentSaveOptionsWidget::dither () const { if (mode () & ColorDepth) { return (m_colorDepthCombo->currentIndex () == 1 || m_colorDepthCombo->currentIndex () == 3); } return m_baseDocumentSaveOptions.dither (); } // protected static int kpDocumentSaveOptionsWidget::colorDepthComboItemFromColorDepthAndDither ( int depth, bool dither) { switch (depth) { case 1: if (!dither) { return 0; } return 1; case 8: if (!dither) { return 2; } return 3; case 32: return 4; default: return -1; } } // public slots void kpDocumentSaveOptionsWidget::setColorDepthDither (int newDepth, bool newDither) { #if DEBUG_KP_DOCUMENT_SAVE_OPTIONS_WIDGET qCDebug(kpLogWidgets) << "kpDocumentSaveOptionsWidget::setColorDepthDither(" << "depth=" << newDepth << ",dither=" << newDither << ")" << endl; #endif m_baseDocumentSaveOptions.setColorDepth (newDepth); m_baseDocumentSaveOptions.setDither (newDither); const int comboItem = colorDepthComboItemFromColorDepthAndDither ( newDepth, newDither); // TODO: Ignoring when comboItem >= m_colorDepthCombo->count() is wrong. // This happens if this mimeType has configurable colour depth // and an incorrect maximum colour depth (less than a QImage of // this mimeType, opened by kpDocument). if (comboItem >= 0 && comboItem < m_colorDepthCombo->count ()) { m_colorDepthCombo->setCurrentIndex (comboItem); } slotColorDepthSelected (); } // protected slot void kpDocumentSaveOptionsWidget::slotColorDepthSelected () { if (mode () & ColorDepth) { m_colorDepthComboLastSelectedItem = m_colorDepthCombo->currentIndex (); } else { m_colorDepthComboLastSelectedItem = colorDepthComboItemFromColorDepthAndDither ( m_baseDocumentSaveOptions.colorDepth (), m_baseDocumentSaveOptions.dither ()); } #if DEBUG_KP_DOCUMENT_SAVE_OPTIONS_WIDGET qCDebug(kpLogWidgets) << "kpDocumentSaveOptionsWidget::slotColorDepthSelected()" << " mode&ColorDepth=" << (mode () & ColorDepth) << " colorDepthComboLastSelectedItem=" << m_colorDepthComboLastSelectedItem << endl; #endif } // public int kpDocumentSaveOptionsWidget::quality () const { if (mode () & Quality) { return m_qualityInput->value (); } return m_baseDocumentSaveOptions.quality (); } // public void kpDocumentSaveOptionsWidget::setQuality (int newQuality) { #if DEBUG_KP_DOCUMENT_SAVE_OPTIONS_WIDGET qCDebug(kpLogWidgets) << "kpDocumentSaveOptionsWidget::setQuality(" << newQuality << ")" << endl; #endif m_baseDocumentSaveOptions.setQuality (newQuality); m_qualityInput->setValue (newQuality == -1/*QImage::save() default*/ ? 75 : newQuality); } // public kpDocumentSaveOptions kpDocumentSaveOptionsWidget::documentSaveOptions () const { return kpDocumentSaveOptions (mimeType (), colorDepth (), dither (), quality ()); } // public void kpDocumentSaveOptionsWidget::setDocumentSaveOptions ( const kpDocumentSaveOptions &saveOptions) { setMimeType (saveOptions.mimeType ()); setColorDepthDither (saveOptions.colorDepth (), saveOptions.dither ()); setQuality (saveOptions.quality ()); } // public void kpDocumentSaveOptionsWidget::setDocumentPixmap (const QImage &documentPixmap) { delete m_documentPixmap; m_documentPixmap = new QImage (documentPixmap); updatePreview (); } // public void kpDocumentSaveOptionsWidget::setDocumentMetaInfo ( const kpDocumentMetaInfo &metaInfo) { m_documentMetaInfo = metaInfo; updatePreview (); } // public kpDocumentSaveOptionsWidget::Mode kpDocumentSaveOptionsWidget::mode () const { return m_mode; } // public void kpDocumentSaveOptionsWidget::setMode (Mode mode) { m_mode = mode; // If mode == None, we show still show the Color Depth widgets but disabled m_colorDepthLabel->setVisible (mode != Quality); m_colorDepthCombo->setVisible (mode != Quality); m_colorDepthSpaceWidget->setVisible (mode != Quality); m_qualityLabel->setVisible (mode == Quality); m_qualityInput->setVisible (mode == Quality); m_colorDepthLabel->setEnabled (mode == ColorDepth); m_colorDepthCombo->setEnabled (mode == ColorDepth); m_qualityLabel->setEnabled (mode == Quality); m_qualityInput->setEnabled (mode == Quality); // SYNC: HACK: When changing between color depth and quality widgets, // we change the height of "this", causing the text on the labels // to move but the first instance of the text doesn't get erased. // Qt bug. - QTimer::singleShot (0, this, SLOT (repaintLabels())); + QTimer::singleShot (0, this, &kpDocumentSaveOptionsWidget::repaintLabels); } // protected slot void kpDocumentSaveOptionsWidget::repaintLabels () { if (mode () != Quality) { m_colorDepthLabel->repaint (); } if (mode () == Quality) { m_qualityLabel->repaint (); } } // protected slot void kpDocumentSaveOptionsWidget::showPreview (bool yes) { #if DEBUG_KP_DOCUMENT_SAVE_OPTIONS_WIDGET qCDebug(kpLogWidgets) << "kpDocumentSaveOptionsWidget::showPreview(" << yes << ")" << " m_previewDialog=" << bool (m_previewDialog) << endl; #endif if (yes == bool (m_previewDialog)) { return; } if (!m_visualParent) { return; } if (yes) { m_previewDialog = new kpDocumentSaveOptionsPreviewDialog( m_visualParent ); - m_previewDialog->setObjectName( QLatin1String( "previewSaveDialog" ) ); + m_previewDialog->setObjectName( QStringLiteral( "previewSaveDialog" ) ); updatePreview (); connect (m_previewDialog, &kpDocumentSaveOptionsPreviewDialog::finished, this, &kpDocumentSaveOptionsWidget::hidePreview); KConfigGroup cfg (KSharedConfig::openConfig (), kpSettingsGroupPreviewSave); if (cfg.hasKey (kpSettingPreviewSaveUpdateDelay)) { m_updatePreviewDelay = cfg.readEntry (kpSettingPreviewSaveUpdateDelay, 0); } else { cfg.writeEntry (kpSettingPreviewSaveUpdateDelay, m_updatePreviewDelay); cfg.sync (); } if (m_updatePreviewDelay < 0) { m_updatePreviewDelay = 0; } #if DEBUG_KP_DOCUMENT_SAVE_OPTIONS_WIDGET qCDebug(kpLogWidgets) << "\tread cfg preview dialog update delay=" << m_updatePreviewDelay; #endif if (m_previewDialogLastRelativeGeometry.isEmpty ()) { #if DEBUG_KP_DOCUMENT_SAVE_OPTIONS_WIDGET qCDebug(kpLogWidgets) << "\tread cfg preview dialog last rel geometry"; #endif KConfigGroup cfg (KSharedConfig::openConfig (), kpSettingsGroupPreviewSave); m_previewDialogLastRelativeGeometry = cfg.readEntry ( kpSettingPreviewSaveGeometry, QRect ()); } #if DEBUG_KP_DOCUMENT_SAVE_OPTIONS_WIDGET qCDebug(kpLogWidgets) << "\tpreviewDialogLastRelativeGeometry=" << m_previewDialogLastRelativeGeometry << " visualParent->rect()=" << m_visualParent->rect () << endl; #endif QRect relativeGeometry; if (!m_previewDialogLastRelativeGeometry.isEmpty () && m_visualParent->rect ().intersects (m_previewDialogLastRelativeGeometry)) { #if DEBUG_KP_DOCUMENT_SAVE_OPTIONS_WIDGET qCDebug(kpLogWidgets) << "\tok"; #endif relativeGeometry = m_previewDialogLastRelativeGeometry; } else { #if DEBUG_KP_DOCUMENT_SAVE_OPTIONS_WIDGET qCDebug(kpLogWidgets) << "\t\tinvalid"; #endif const int margin = 20; relativeGeometry = QRect (m_visualParent->width () - m_previewDialog->preferredMinimumSize ().width () - margin, margin * 2, // Avoid folder combo m_previewDialog->preferredMinimumSize ().width (), m_previewDialog->preferredMinimumSize ().height ()); } const QRect globalGeometry = kpWidgetMapper::toGlobal (m_visualParent, relativeGeometry); #if DEBUG_KP_DOCUMENT_SAVE_OPTIONS_WIDGET qCDebug(kpLogWidgets) << "\trelativeGeometry=" << relativeGeometry << " globalGeometry=" << globalGeometry << endl; #endif m_previewDialog->resize (globalGeometry.size ()); m_previewDialog->move (globalGeometry.topLeft ()); m_previewDialog->show (); #if DEBUG_KP_DOCUMENT_SAVE_OPTIONS_WIDGET qCDebug(kpLogWidgets) << "\tgeometry after show=" << QRect (m_previewDialog->x (), m_previewDialog->y (), m_previewDialog->width (), m_previewDialog->height ()) << endl; #endif updatePreviewDialogLastRelativeGeometry (); connect (m_previewDialog, &kpDocumentSaveOptionsPreviewDialog::moved, this, &kpDocumentSaveOptionsWidget::updatePreviewDialogLastRelativeGeometry); connect (m_previewDialog, &kpDocumentSaveOptionsPreviewDialog::resized, this, &kpDocumentSaveOptionsWidget::updatePreviewDialogLastRelativeGeometry); m_updatePreviewDialogLastRelativeGeometryTimer->start (200/*ms*/); } else { m_updatePreviewDialogLastRelativeGeometryTimer->stop (); KConfigGroup cfg (KSharedConfig::openConfig (), kpSettingsGroupPreviewSave); cfg.writeEntry (kpSettingPreviewSaveGeometry, m_previewDialogLastRelativeGeometry); cfg.sync (); #if DEBUG_KP_DOCUMENT_SAVE_OPTIONS_WIDGET qCDebug(kpLogWidgets) << "\tsaving preview geometry " << m_previewDialogLastRelativeGeometry << " (Qt would have us believe " << kpWidgetMapper::fromGlobal (m_visualParent, QRect (m_previewDialog->x (), m_previewDialog->y (), m_previewDialog->width (), m_previewDialog->height ())) << ")" << endl; #endif m_previewDialog->deleteLater (); m_previewDialog = nullptr; } } // protected slot void kpDocumentSaveOptionsWidget::hidePreview () { if (m_previewButton->isChecked ()) { m_previewButton->toggle (); } } // protected slot void kpDocumentSaveOptionsWidget::updatePreviewDelayed () { // (single shot) m_updatePreviewTimer->start (m_updatePreviewDelay); } // protected slot void kpDocumentSaveOptionsWidget::updatePreview () { if (!m_previewDialog || !m_documentPixmap) { return; } m_updatePreviewTimer->stop (); QApplication::setOverrideCursor (Qt::WaitCursor); QByteArray data; QBuffer buffer (&data); buffer.open (QIODevice::WriteOnly); bool savedOK = kpDocument::savePixmapToDevice (*m_documentPixmap, &buffer, documentSaveOptions (), m_documentMetaInfo, false/*no lossy prompt*/, this); buffer.close (); QImage image; // Ignore any failed saves. // // Failed saves might literally have written half a file. The final // save (when the user clicks OK), _will_ fail so we shouldn't have a // preview even if this "half a file" is actually loadable by // QImage::loadFormData(). if (savedOK) { image.loadFromData(data); } else { // Leave as invalid. // TODO: This code path has not been well tested. // Will we trigger divide by zero errors in "m_previewDialog"? } // REFACTOR: merge with kpDocument::getPixmapFromFile() m_previewDialog->setFilePixmapAndSize (image, data.size ()); QApplication::restoreOverrideCursor (); } // protected slot void kpDocumentSaveOptionsWidget::updatePreviewDialogLastRelativeGeometry () { #if DEBUG_KP_DOCUMENT_SAVE_OPTIONS_WIDGET qCDebug(kpLogWidgets) << "kpDocumentSaveOptionsWidget::" << "updatePreviewDialogLastRelativeGeometry()" << endl; #endif if (m_previewDialog && m_previewDialog->isVisible ()) { m_previewDialogLastRelativeGeometry = kpWidgetMapper::fromGlobal (m_visualParent, QRect (m_previewDialog->x (), m_previewDialog->y (), m_previewDialog->width (), m_previewDialog->height ())); #if DEBUG_KP_DOCUMENT_SAVE_OPTIONS_WIDGET qCDebug(kpLogWidgets) << "\tcaching pos = " << m_previewDialogLastRelativeGeometry; #endif } else { #if DEBUG_KP_DOCUMENT_SAVE_OPTIONS_WIDGET qCDebug(kpLogWidgets) << "\tnot visible - ignoring geometry"; #endif } } diff --git a/widgets/kpDualColorButton.cpp b/widgets/kpDualColorButton.cpp index 1e8c6c8a..bb311dc6 100644 --- a/widgets/kpDualColorButton.cpp +++ b/widgets/kpDualColorButton.cpp @@ -1,470 +1,470 @@ /* 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_DUAL_COLOR_BUTTON 0 #include "kpDualColorButton.h" #include "views/kpView.h" #include #include "kpLogCategories.h" #include #include #include #include #include #include #include #include //--------------------------------------------------------------------- kpDualColorButton::kpDualColorButton (QWidget *parent) : QFrame (parent), m_dragStartPoint (KP_INVALID_POINT) { setSizePolicy (QSizePolicy::Fixed/*horizontal*/, QSizePolicy::Fixed/*vertical*/); setFrameStyle (QFrame::Panel | QFrame::Sunken); m_color [0] = kpColor (0, 0, 0); // black m_color [1] = kpColor (255, 255, 255); // white setAcceptDrops (true); } //--------------------------------------------------------------------- kpColor kpDualColorButton::color (int which) const { Q_ASSERT (which == 0 || which == 1); return m_color [which]; } //--------------------------------------------------------------------- kpColor kpDualColorButton::foregroundColor () const { return color (0); } //--------------------------------------------------------------------- kpColor kpDualColorButton::backgroundColor () const { return color (1); } //--------------------------------------------------------------------- void kpDualColorButton::setColor (int which, const kpColor &color) { Q_ASSERT (which == 0 || which == 1); if (m_color [which] == color) { return; } m_oldColor [which] = m_color [which]; m_color [which] = color; update (); if (which == 0) { emit foregroundColorChanged (color); } else { emit backgroundColorChanged (color); } } //--------------------------------------------------------------------- void kpDualColorButton::setForegroundColor (const kpColor &color) { setColor (0, color); } //--------------------------------------------------------------------- void kpDualColorButton::setBackgroundColor (const kpColor &color) { setColor (1, color); } //--------------------------------------------------------------------- // public kpColor kpDualColorButton::oldForegroundColor () const { return m_oldColor [0]; } //--------------------------------------------------------------------- // public kpColor kpDualColorButton::oldBackgroundColor () const { return m_oldColor [1]; } //--------------------------------------------------------------------- // public virtual [base QWidget] QSize kpDualColorButton::sizeHint () const { return {52, 52}; } //--------------------------------------------------------------------- // protected QRect kpDualColorButton::swapPixmapRect () const { - QPixmap swapPixmap = UserIcon ("colorbutton_swap_16x16"); + QPixmap swapPixmap = UserIcon (QStringLiteral("colorbutton_swap_16x16")); return {contentsRect ().width () - swapPixmap.width (), 0, swapPixmap.width (), swapPixmap.height ()}; } //--------------------------------------------------------------------- // protected QRect kpDualColorButton::foregroundBackgroundRect () const { QRect cr (contentsRect ()); return {cr.width () / 8, cr.height () / 8, cr.width () * 6 / 8, cr.height () * 6 / 8}; } //--------------------------------------------------------------------- // protected QRect kpDualColorButton::foregroundRect () const { QRect fbr (foregroundBackgroundRect ()); return {fbr.x (), fbr.y (), fbr.width () * 3 / 4, fbr.height () * 3 / 4}; } //--------------------------------------------------------------------- // protected QRect kpDualColorButton::backgroundRect () const { QRect fbr (foregroundBackgroundRect ()); return {fbr.x () + fbr.width () / 4, fbr.y () + fbr.height () / 4, fbr.width () * 3 / 4, fbr.height () * 3 / 4}; } //--------------------------------------------------------------------- // protected virtual void kpDualColorButton::dragEnterEvent (QDragEnterEvent *e) { #if DEBUG_KP_DUAL_COLOR_BUTTON qCDebug(kpLogWidgets) << "kpDualColorButton::dragEnterEvent() canDecode=" << KColorMimeData::canDecode (e->mimeData ()); #endif e->accept (); } //--------------------------------------------------------------------- // protected virtual [base QWidget] void kpDualColorButton::dragMoveEvent (QDragMoveEvent *e) { #if DEBUG_KP_DUAL_COLOR_BUTTON qCDebug(kpLogWidgets) << "kpDualColorButton::dragMoveEvent() canDecode=" << KColorMimeData::canDecode (e->mimeData ()); #endif e->setAccepted ( (foregroundRect ().contains (e->pos ()) || backgroundRect ().contains (e->pos ())) && KColorMimeData::canDecode (e->mimeData ())); } //--------------------------------------------------------------------- // protected virtual [base QWidget] void kpDualColorButton::dropEvent (QDropEvent *e) { QColor col = KColorMimeData::fromMimeData (e->mimeData ()); #if DEBUG_KP_DUAL_COLOR_BUTTON qCDebug(kpLogWidgets) << "kpDualColorButton::dropEvent() col=" << (int *) col.rgba() << " (with alpha=" << (int *) col.rgba () << ")"; #endif if (col.isValid ()) { if (foregroundRect ().contains (e->pos ())) { setForegroundColor (kpColor (col.rgba())); } else if (backgroundRect ().contains (e->pos ())) { setBackgroundColor (kpColor (col.rgba())); } } } //--------------------------------------------------------------------- // protected virtual [base QWidget] void kpDualColorButton::mousePressEvent (QMouseEvent *e) { #if DEBUG_KP_DUAL_COLOR_BUTTON qCDebug(kpLogWidgets) << "kpDualColorButton::mousePressEvent() pos=" << e->pos (); #endif m_dragStartPoint = KP_INVALID_POINT; if (e->button () == Qt::LeftButton) { m_dragStartPoint = e->pos (); } } //--------------------------------------------------------------------- void kpDualColorButton::mouseMoveEvent (QMouseEvent *e) { #if DEBUG_KP_DUAL_COLOR_BUTTON qCDebug(kpLogWidgets) << "kpDualColorButton::mouseMoveEvent() pos=" << e->pos () << " buttons=" << e->buttons () << " dragStartPoint=" << m_dragStartPoint << endl; #endif if (m_dragStartPoint == KP_INVALID_POINT) { return; } if (!(e->buttons () & Qt::LeftButton)) { m_dragStartPoint = KP_INVALID_POINT; return; } const int delay = QApplication::startDragDistance (); if (e->x () < m_dragStartPoint.x () - delay || e->x () > m_dragStartPoint.x () + delay || e->y () < m_dragStartPoint.y () - delay || e->y () > m_dragStartPoint.y () + delay) { #if DEBUG_KP_DUAL_COLOR_BUTTON qCDebug(kpLogWidgets) << "\tstarting drag as long as it's in a rectangle"; #endif kpColor color; if (foregroundRect ().contains (m_dragStartPoint)) { color = foregroundColor (); } else if (backgroundRect ().contains (m_dragStartPoint)) { color = backgroundColor (); } #if DEBUG_KP_DUAL_COLOR_BUTTON qCDebug(kpLogWidgets) << "\tcolor.isValid=" << color.isValid () << " rgb=" << (color.isValid () ? (int *) color.toQRgb () : 0) << endl; #endif if (color.isValid ()) { if (!color.isTransparent ()) { KColorMimeData::createDrag (color.toQColor (), this)->exec (); } } m_dragStartPoint = KP_INVALID_POINT; } } //--------------------------------------------------------------------- // protected virtual [base QWidget] void kpDualColorButton::mouseReleaseEvent (QMouseEvent *e) { m_dragStartPoint = KP_INVALID_POINT; if (swapPixmapRect ().contains (e->pos ()) && m_color [0] != m_color [1]) { #if DEBUG_KP_DUAL_COLOR_BUTTON && 1 qCDebug(kpLogWidgets) << "kpDualColorButton::mouseReleaseEvent() swap colors:"; #endif m_oldColor [0] = m_color [0]; m_oldColor [1] = m_color [1]; kpColor temp = m_color [0]; m_color [0] = m_color [1]; m_color [1] = temp; update (); emit colorsSwapped (m_color [0], m_color [1]); emit foregroundColorChanged (m_color [0]); emit backgroundColorChanged (m_color [1]); } } //--------------------------------------------------------------------- // protected virtual [base QWidget] void kpDualColorButton::mouseDoubleClickEvent (QMouseEvent *e) { int whichColor = -1; if (foregroundRect ().contains (e->pos ())) { whichColor = 0; } else if (backgroundRect ().contains (e->pos ())) { whichColor = 1; } if (whichColor == 0 || whichColor == 1) { QColorDialog dialog(this); dialog.setCurrentColor(color(whichColor).toQColor()); dialog.setOptions(QColorDialog::ShowAlphaChannel); if ( dialog.exec() == QDialog::Accepted ) { setColor(whichColor, kpColor(dialog.currentColor().rgba())); } } } //--------------------------------------------------------------------- // protected virtual [base QWidget] void kpDualColorButton::paintEvent (QPaintEvent *e) { #if DEBUG_KP_DUAL_COLOR_BUTTON && 1 qCDebug(kpLogWidgets) << "kpDualColorButton::draw() rect=" << rect () << " contentsRect=" << contentsRect () << endl; #endif // Draw frame first. QFrame::paintEvent (e); QPainter painter (this); // Fill with background. if (isEnabled ()) { kpView::drawTransparentBackground (&painter, contentsRect ().topLeft ()/*checkerboard top-left*/, contentsRect (), true/*preview*/); } else { // Use default widget background. } painter.translate (contentsRect ().x (), contentsRect ().y ()); // Draw "Swap Colours" button (top-right). - QPixmap swapPixmap = UserIcon ("colorbutton_swap_16x16"); + QPixmap swapPixmap = UserIcon (QStringLiteral("colorbutton_swap_16x16")); if (!isEnabled ()) { // Don't let the fill() touch the mask. QBitmap swapBitmapMask = swapPixmap.mask (); swapPixmap.setMask (QBitmap ()); // Grey out the opaque parts of "swapPixmap". swapPixmap.fill (palette ().color (QPalette::Dark)); swapPixmap.setMask (swapBitmapMask); } painter.drawPixmap (swapPixmapRect ().topLeft (), swapPixmap); // Draw background colour patch. QRect bgRect = backgroundRect (); QRect bgRectInside = QRect (bgRect.x () + 2, bgRect.y () + 2, bgRect.width () - 4, bgRect.height () - 4); if (isEnabled ()) { #if DEBUG_KP_DUAL_COLOR_BUTTON && 1 qCDebug(kpLogWidgets) << "\tbackgroundColor=" << (int *) m_color [1].toQRgb () << endl; #endif if (m_color [1].isTransparent ()) { // only if fully transparent - painter.drawPixmap (bgRectInside, UserIcon ("color_transparent_26x26")); + painter.drawPixmap (bgRectInside, UserIcon (QStringLiteral("color_transparent_26x26"))); } else { painter.fillRect (bgRectInside, m_color [1].toQColor ()); } } else { painter.fillRect (bgRectInside, palette().color (QPalette::Button)); } qDrawShadePanel (&painter, bgRect, palette(), false/*not sunken*/, 2/*lineWidth*/, nullptr/*never fill*/); // Draw foreground colour patch. // Must be drawn after background patch since we're on top. QRect fgRect = foregroundRect (); QRect fgRectInside = QRect (fgRect.x () + 2, fgRect.y () + 2, fgRect.width () - 4, fgRect.height () - 4); if (isEnabled ()) { #if DEBUG_KP_DUAL_COLOR_BUTTON && 1 qCDebug(kpLogWidgets) << "\tforegroundColor=" << (int *) m_color [0].toQRgb () << endl; #endif if (m_color [0].isTransparent ()) { // only if fully transparent - painter.drawPixmap (fgRectInside, UserIcon ("color_transparent_26x26")); + painter.drawPixmap (fgRectInside, UserIcon (QStringLiteral("color_transparent_26x26"))); } else { painter.fillRect (fgRectInside, m_color [0].toQColor ()); } } else { painter.fillRect (fgRectInside, palette ().color (QPalette::Button)); } qDrawShadePanel (&painter, fgRect, palette (), false/*not sunken*/, 2/*lineWidth*/, nullptr/*never fill*/); } diff --git a/widgets/kpTransparentColorCell.cpp b/widgets/kpTransparentColorCell.cpp index 6c8dffe4..aca42db8 100644 --- a/widgets/kpTransparentColorCell.cpp +++ b/widgets/kpTransparentColorCell.cpp @@ -1,128 +1,128 @@ /* 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_TRANSPARENT_COLOR_CELL 0 #include "kpTransparentColorCell.h" #include "imagelib/kpColor.h" #include #include #include #include #include //--------------------------------------------------------------------- kpTransparentColorCell::kpTransparentColorCell (QWidget *parent) : QFrame (parent) { setSizePolicy (QSizePolicy::Fixed/*horizontal*/, QSizePolicy::Fixed/*vertical*/); setFrameStyle (QFrame::Panel | QFrame::Sunken); - m_pixmap = UserIcon ("color_transparent_26x26"); + m_pixmap = UserIcon (QStringLiteral("color_transparent_26x26")); this->setToolTip( i18n ("Transparent")); } //--------------------------------------------------------------------- // public virtual [base QWidget] QSize kpTransparentColorCell::sizeHint () const { return {m_pixmap.width () + frameWidth () * 2, m_pixmap.height () + frameWidth () * 2}; } //--------------------------------------------------------------------- // protected virtual [base QWidget] void kpTransparentColorCell::mousePressEvent (QMouseEvent * /*e*/) { // Eat press so that we own the mouseReleaseEvent(). // [http://blogs.qtdeveloper.net/archives/2006/05/27/mouse-event-propagation/] // // However, contrary to that blog, it doesn't seem to be needed? } //--------------------------------------------------------------------- // protected virtual [base QWidget] void kpTransparentColorCell::contextMenuEvent (QContextMenuEvent *e) { // Eat right-mouse press to prevent it from getting to the toolbar. e->accept (); } //--------------------------------------------------------------------- // protected virtual [base QWidget] void kpTransparentColorCell::mouseReleaseEvent (QMouseEvent *e) { if (rect ().contains (e->pos ())) { if (e->button () == Qt::LeftButton) { emit transparentColorSelected (0); emit foregroundColorChanged (kpColor::Transparent); } else if (e->button () == Qt::RightButton) { emit transparentColorSelected (1); emit backgroundColorChanged (kpColor::Transparent); } } } //--------------------------------------------------------------------- // protected virtual [base QWidget] void kpTransparentColorCell::paintEvent (QPaintEvent *e) { // Draw frame first. QFrame::paintEvent (e); if (isEnabled ()) { #if DEBUG_KP_TRANSPARENT_COLOR_CELL qCDebug(kpLogWidgets) << "kpTransparentColorCell::paintEvent() contentsRect=" << contentsRect () << endl; #endif QPainter p (this); p.drawPixmap (contentsRect (), m_pixmap); } } //--------------------------------------------------------------------- diff --git a/widgets/toolbars/kpToolToolBar.cpp b/widgets/toolbars/kpToolToolBar.cpp index f0cf1fd7..6a584fbd 100644 --- a/widgets/toolbars/kpToolToolBar.cpp +++ b/widgets/toolbars/kpToolToolBar.cpp @@ -1,471 +1,471 @@ /* 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_TOOL_BAR 0 #include "widgets/toolbars/kpToolToolBar.h" #include #include #include #include #include #include "kpLogCategories.h" #include "kpDefs.h" #include "tools/kpTool.h" #include "tools/kpToolAction.h" #include "widgets/toolbars/options/kpToolWidgetBrush.h" #include "widgets/toolbars/options/kpToolWidgetEraserSize.h" #include "widgets/toolbars/options/kpToolWidgetFillStyle.h" #include "widgets/toolbars/options/kpToolWidgetLineWidth.h" #include "widgets/toolbars/options/kpToolWidgetOpaqueOrTransparent.h" #include "widgets/toolbars/options/kpToolWidgetSpraycanSize.h" //--------------------------------------------------------------------- class kpToolButton : public QToolButton { public: kpToolButton (kpTool *tool, QWidget *parent) : QToolButton (parent), m_tool (tool) { } kpTool *tool() const { return m_tool; } protected: void mouseDoubleClickEvent(QMouseEvent *e) override { if (e->button () == Qt::LeftButton && m_tool) { m_tool->globalDraw (); } } kpTool *m_tool; }; //--------------------------------------------------------------------- kpToolToolBar::kpToolToolBar(const QString &name, int colsOrRows, QMainWindow *parent) : KToolBar(name, parent, Qt::LeftToolBarArea), m_vertCols (colsOrRows), m_buttonGroup (nullptr), m_baseWidget (nullptr), m_baseLayout (nullptr), m_toolLayout (nullptr), m_previousTool (nullptr), m_currentTool (nullptr) { m_baseWidget = new QWidget(this); m_toolWidgets.append (m_toolWidgetBrush = - new kpToolWidgetBrush (m_baseWidget, "Tool Widget Brush")); + new kpToolWidgetBrush (m_baseWidget, QStringLiteral("Tool Widget Brush"))); m_toolWidgets.append (m_toolWidgetEraserSize = - new kpToolWidgetEraserSize (m_baseWidget, "Tool Widget Eraser Size")); + new kpToolWidgetEraserSize (m_baseWidget, QStringLiteral("Tool Widget Eraser Size"))); m_toolWidgets.append (m_toolWidgetFillStyle = - new kpToolWidgetFillStyle (m_baseWidget, "Tool Widget Fill Style")); + new kpToolWidgetFillStyle (m_baseWidget, QStringLiteral("Tool Widget Fill Style"))); m_toolWidgets.append (m_toolWidgetLineWidth = - new kpToolWidgetLineWidth (m_baseWidget, "Tool Widget Line Width")); + new kpToolWidgetLineWidth (m_baseWidget, QStringLiteral("Tool Widget Line Width"))); m_toolWidgets.append (m_toolWidgetOpaqueOrTransparent = - new kpToolWidgetOpaqueOrTransparent (m_baseWidget, "Tool Widget Opaque/Transparent")); + new kpToolWidgetOpaqueOrTransparent (m_baseWidget, QStringLiteral("Tool Widget Opaque/Transparent"))); m_toolWidgets.append (m_toolWidgetSpraycanSize = - new kpToolWidgetSpraycanSize (m_baseWidget, "Tool Widget Spraycan Size")); + new kpToolWidgetSpraycanSize (m_baseWidget, QStringLiteral("Tool Widget Spraycan Size"))); for (auto *w : m_toolWidgets) { connect (w, &kpToolWidgetBase::optionSelected, this, &kpToolToolBar::toolWidgetOptionSelected); } adjustToOrientation(orientation()); connect (this, &kpToolToolBar::orientationChanged, this, &kpToolToolBar::adjustToOrientation); m_buttonGroup = new QButtonGroup (this); connect (m_buttonGroup, static_cast(&QButtonGroup::buttonClicked), this, &kpToolToolBar::slotToolButtonClicked); hideAllToolWidgets (); addWidget(m_baseWidget); connect (this, &kpToolToolBar::iconSizeChanged, this, &kpToolToolBar::slotIconSizeChanged); connect (this, &kpToolToolBar::toolButtonStyleChanged, this, &kpToolToolBar::slotToolButtonStyleChanged); } //--------------------------------------------------------------------- kpToolToolBar::~kpToolToolBar() { while ( !m_toolButtons.isEmpty() ) { delete m_toolButtons.takeFirst(); } } //--------------------------------------------------------------------- // public void kpToolToolBar::registerTool (kpTool *tool) { for (const auto *b : m_toolButtons) { if ( b->tool() == tool ) { // already given return; } } auto *b = new kpToolButton(tool, m_baseWidget); b->setToolButtonStyle(toolButtonStyle()); b->setIconSize(iconSize()); b->setAutoRaise(true); // tell layout to make all with equal width (much better when text-below-icon) b->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Preferred); b->setDefaultAction(tool->action()); m_buttonGroup->addButton(b); addButton(b, orientation(), m_toolButtons.count()); m_toolButtons.append(b); connect (tool, &kpTool::actionActivated, this, &kpToolToolBar::slotToolActionActivated); adjustSizeConstraint(); } //--------------------------------------------------------------------- // public void kpToolToolBar::unregisterTool(kpTool *tool) { for (int i = 0; i < m_toolButtons.count(); i++) { if ( m_toolButtons[i]->tool() == tool ) { delete m_toolButtons.takeAt(i); disconnect (tool, &kpTool::actionActivated, this, &kpToolToolBar::slotToolActionActivated); return; } } } //--------------------------------------------------------------------- // public kpTool *kpToolToolBar::tool () const { return m_currentTool; } //--------------------------------------------------------------------- // public void kpToolToolBar::selectTool (const kpTool *tool, bool reselectIfSameTool) { #if DEBUG_KP_TOOL_TOOL_BAR qCDebug(kpLogWidgets) << "kpToolToolBar::selectTool (tool=" << tool << ") currentTool=" << m_currentTool << endl; #endif if (!reselectIfSameTool && tool == m_currentTool) { return; } if (tool) { tool->action()->setChecked(true); slotToolButtonClicked(); } else { QAbstractButton *b = m_buttonGroup->checkedButton(); if (b) { // HACK: qbuttongroup.html says the following about exclusive // button groups: // // "to untoggle a button you must click on another button // in the group" // // But we don't want any button to be selected. // So don't be an exclusive button group temporarily. m_buttonGroup->setExclusive (false); b->setChecked (false); m_buttonGroup->setExclusive (true); slotToolButtonClicked (); } } } //--------------------------------------------------------------------- // public kpTool *kpToolToolBar::previousTool () const { return m_previousTool; } //--------------------------------------------------------------------- // public void kpToolToolBar::selectPreviousTool () { selectTool (m_previousTool); } //--------------------------------------------------------------------- // public void kpToolToolBar::hideAllToolWidgets () { for (auto *w : m_toolWidgets) { w->hide (); } } //--------------------------------------------------------------------- // public kpToolWidgetBase *kpToolToolBar::shownToolWidget (int which) const { int uptoVisibleWidget = 0; for(auto *w : m_toolWidgets) { if ( !w->isHidden() ) { if (which == uptoVisibleWidget) { return w; } uptoVisibleWidget++; } } return nullptr; } //--------------------------------------------------------------------- // private slot void kpToolToolBar::slotToolButtonClicked () { QAbstractButton *b = m_buttonGroup->checkedButton(); #if DEBUG_KP_TOOL_TOOL_BAR qCDebug(kpLogWidgets) << "kpToolToolBar::slotToolButtonClicked() button=" << b; #endif kpTool *tool = nullptr; for (const auto *button : m_toolButtons) { if ( button == b ) { tool = button->tool(); break; } } #if DEBUG_KP_TOOL_TOOL_BAR qCDebug(kpLogWidgets) << "\ttool=" << tool << " currentTool=" << m_currentTool << endl; #endif if (tool == m_currentTool) { if (m_currentTool) { m_currentTool->reselect (); } return; } if (m_currentTool) { m_currentTool->endInternal (); } m_previousTool = m_currentTool; m_currentTool = tool; if (m_currentTool) { kpToolAction *action = m_currentTool->action (); if (action) { action->setChecked (true); } m_currentTool->beginInternal (); } emit sigToolSelected (m_currentTool); m_baseLayout->activate(); adjustSizeConstraint(); } //--------------------------------------------------------------------- // private slot void kpToolToolBar::slotToolActionActivated () { const auto *tool = dynamic_cast(sender()); #if DEBUG_KP_TOOL_TOOL_BAR qCDebug(kpLogWidgets) << "kpToolToolBar::slotToolActionActivated() tool=" << (tool ? tool->objectName () : "null") << endl; #endif selectTool (tool, true/*reselect if same tool*/); } //--------------------------------------------------------------------- // public void kpToolToolBar::adjustToOrientation(Qt::Orientation o) { #if DEBUG_KP_TOOL_TOOL_BAR qCDebug(kpLogWidgets) << "kpToolToolBar::adjustToOrientation(" << (o == Qt::Vertical ? "vertical" : "horizontal") << ") called!" << endl; #endif delete m_baseLayout; if (o == Qt::Vertical) { m_baseLayout = new QBoxLayout (QBoxLayout::TopToBottom, m_baseWidget); } else // if (o == Qt::Horizontal) { m_baseLayout = new QBoxLayout (QBoxLayout::LeftToRight, m_baseWidget); } m_baseLayout->setSizeConstraint(QLayout::SetFixedSize); m_baseLayout->setContentsMargins(0, 0, 0, 0); m_toolLayout = new QGridLayout(); m_toolLayout->setContentsMargins(0, 0, 0, 0); // (ownership is transferred to m_baseLayout) m_baseLayout->addItem (m_toolLayout); auto num = 0; for (auto *b : m_toolButtons) { addButton(b, o, num); num++; } for (auto *w : m_toolWidgets) { m_baseLayout->addWidget(w, 0/*stretch*/, o == Qt::Vertical ? Qt::AlignHCenter : Qt::AlignVCenter); } adjustSizeConstraint(); } //--------------------------------------------------------------------- // this makes the size handled correctly during dragging/undocking the toolbar void kpToolToolBar::adjustSizeConstraint() { // remove constraints setFixedSize(QSize(QWIDGETSIZE_MAX, QWIDGETSIZE_MAX)); if ( orientation() == Qt::Vertical ) { setFixedWidth(m_baseLayout->sizeHint().width() + layout()->contentsMargins().left() + layout()->contentsMargins().right()); } else { setFixedHeight(m_baseLayout->sizeHint().height() + layout()->contentsMargins().top() + layout()->contentsMargins().bottom()); } } //--------------------------------------------------------------------- // private void kpToolToolBar::addButton(QAbstractButton *button, Qt::Orientation o, int num) { if (o == Qt::Vertical) { m_toolLayout->addWidget (button, num / m_vertCols, num % m_vertCols); } else { // maps Left (o = vertical) to Bottom (o = horizontal) int row = (m_vertCols - 1) - (num % m_vertCols); m_toolLayout->addWidget (button, row, num / m_vertCols); } } //--------------------------------------------------------------------- void kpToolToolBar::slotIconSizeChanged(const QSize &size) { for (auto *b : m_toolButtons) { b->setIconSize(size); } m_baseLayout->activate(); adjustSizeConstraint(); } //--------------------------------------------------------------------- void kpToolToolBar::slotToolButtonStyleChanged(Qt::ToolButtonStyle style) { for (auto *b : m_toolButtons) { b->setToolButtonStyle(style); } m_baseLayout->activate(); adjustSizeConstraint(); } //--------------------------------------------------------------------- diff --git a/widgets/toolbars/options/kpToolWidgetOpaqueOrTransparent.cpp b/widgets/toolbars/options/kpToolWidgetOpaqueOrTransparent.cpp index ef107afb..c164ae54 100644 --- a/widgets/toolbars/options/kpToolWidgetOpaqueOrTransparent.cpp +++ b/widgets/toolbars/options/kpToolWidgetOpaqueOrTransparent.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_TOOL_WIDGET_OPAQUE_OR_TRANSPARENT 0 #include "widgets/toolbars/options/kpToolWidgetOpaqueOrTransparent.h" #include "kpLogCategories.h" #include #include //--------------------------------------------------------------------- kpToolWidgetOpaqueOrTransparent::kpToolWidgetOpaqueOrTransparent (QWidget *parent, const QString &name) : kpToolWidgetBase (parent, name) { - addOption (UserIcon ("option_opaque"), i18n ("Opaque")/*tooltip*/); + addOption (UserIcon (QStringLiteral("option_opaque")), i18n ("Opaque")/*tooltip*/); startNewOptionRow (); - addOption (UserIcon ("option_transparent"), i18n ("Transparent")/*tooltip*/); + addOption (UserIcon (QStringLiteral("option_transparent")), i18n ("Transparent")/*tooltip*/); finishConstruction (0, 0); } //--------------------------------------------------------------------- kpToolWidgetOpaqueOrTransparent::~kpToolWidgetOpaqueOrTransparent () = default; //--------------------------------------------------------------------- // public bool kpToolWidgetOpaqueOrTransparent::isOpaque () const { return (selected () == 0); } // public bool kpToolWidgetOpaqueOrTransparent::isTransparent () const { return (!isOpaque ()); } // public void kpToolWidgetOpaqueOrTransparent::setOpaque (bool yes) { #if DEBUG_KP_TOOL_WIDGET_OPAQUE_OR_TRANSPARENT && 1 qCDebug(kpLogWidgets) << "kpToolWidgetOpaqueOrTransparent::setOpaque(" << yes << ")"; #endif setSelected (yes ? 0 : 1, 0, false/*don't save*/); } // public void kpToolWidgetOpaqueOrTransparent::setTransparent (bool yes) { #if DEBUG_KP_TOOL_WIDGET_OPAQUE_OR_TRANSPARENT && 1 qCDebug(kpLogWidgets) << "kpToolWidgetOpaqueOrTransparent::setTransparent(" << yes << ")"; #endif setSelected (yes ? 1 : 0, 0, false/*don't save*/); } // protected slot virtual [base kpToolWidgetBase] bool kpToolWidgetOpaqueOrTransparent::setSelected (int row, int col, bool saveAsDefault) { #if DEBUG_KP_TOOL_WIDGET_OPAQUE_OR_TRANSPARENT && 1 qCDebug(kpLogWidgets) << "kpToolWidgetOpaqueOrTransparent::setSelected(" << row << "," << col << ")"; #endif const bool ret = kpToolWidgetBase::setSelected (row, col, saveAsDefault); if (ret) { emit isOpaqueChanged (isOpaque ()); } return ret; } diff --git a/widgets/toolbars/options/kpToolWidgetSpraycanSize.cpp b/widgets/toolbars/options/kpToolWidgetSpraycanSize.cpp index e0f648bd..c5c03797 100644 --- a/widgets/toolbars/options/kpToolWidgetSpraycanSize.cpp +++ b/widgets/toolbars/options/kpToolWidgetSpraycanSize.cpp @@ -1,120 +1,120 @@ /* 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_SPRAYCAN_SIZE 0 #include "kpToolWidgetSpraycanSize.h" #include "pixmapfx/kpPixmapFX.h" #include "kpLogCategories.h" #include #include #include #include #include #include static int spraycanSizes [] = {9, 17, 29}; kpToolWidgetSpraycanSize::kpToolWidgetSpraycanSize (QWidget *parent, const QString &name) : kpToolWidgetBase (parent, name) { #if DEBUG_KP_TOOL_WIDGET_SPRAYCAN_SIZE qCDebug(kpLogWidgets) << "kpToolWidgetSpraycanSize::kpToolWidgetSpraycanSize() CALLED!"; #endif for (int i = 0; i < int (sizeof (spraycanSizes) / sizeof (spraycanSizes [0])); i++) { int s = spraycanSizes [i]; - QString iconName = QString ("tool_spraycan_%1x%2").arg (s).arg(s); + QString iconName = QStringLiteral ("tool_spraycan_%1x%2").arg (s).arg(s); #if DEBUG_KP_TOOL_WIDGET_SPRAYCAN_SIZE qCDebug(kpLogWidgets) << "\ticonName=" << iconName; #endif QPixmap pixmap (s, s); pixmap.fill (Qt::white); QPainter painter (&pixmap); painter.drawPixmap (0, 0, UserIcon (iconName)); painter.end (); QImage image = pixmap.toImage(); QBitmap mask (pixmap.width (), pixmap.height ()); mask.fill (Qt::color0); painter.begin (&mask); painter.setPen (Qt::color1); for (int y = 0; y < image.height (); y++) { for (int x = 0; x < image.width (); x++) { if ((image.pixel (x, y) & RGB_MASK) == 0/*black*/) { painter.drawPoint (x, y); // mark as opaque } } } painter.end (); pixmap.setMask (mask); addOption (pixmap, i18n ("%1x%2", s, s)/*tooltip*/); if (i == 1) { startNewOptionRow (); } } finishConstruction (0, 0); } kpToolWidgetSpraycanSize::~kpToolWidgetSpraycanSize () = default; // public int kpToolWidgetSpraycanSize::spraycanSize () const { return spraycanSizes[selected() < 0 ? 0 : selected()]; } // protected slot virtual [base kpToolWidgetBase] bool kpToolWidgetSpraycanSize::setSelected (int row, int col, bool saveAsDefault) { const bool ret = kpToolWidgetBase::setSelected (row, col, saveAsDefault); if (ret) { emit spraycanSizeChanged (spraycanSize ()); } return ret; }