diff --git a/ui/annotationwidgets.h b/ui/annotationwidgets.h --- a/ui/annotationwidgets.h +++ b/ui/annotationwidgets.h @@ -19,6 +19,7 @@ class QDoubleSpinBox; class QFormLayout; class QLabel; +class QPushButton; class QWidget; class KColorButton; class QSpinBox; @@ -31,7 +32,9 @@ Q_OBJECT public: - explicit PixmapPreviewSelector( QWidget * parent = nullptr ); + enum PreviewPosition{ Side, Below }; + + explicit PixmapPreviewSelector( QWidget * parent = nullptr, PreviewPosition position = Side ); virtual ~PixmapPreviewSelector(); void setIcon( const QString& icon ); @@ -49,12 +52,15 @@ private Q_SLOTS: void iconComboChanged( const QString& icon ); + void selectCustomStamp(); private: QString m_icon; + QPushButton * m_stampPushButton; QLabel * m_iconLabel; QComboBox * m_comboItems; int m_previewSize; + PreviewPosition m_previewPosition; }; diff --git a/ui/annotationwidgets.cpp b/ui/annotationwidgets.cpp --- a/ui/annotationwidgets.cpp +++ b/ui/annotationwidgets.cpp @@ -19,7 +19,9 @@ #include #include #include +#include #include +#include #include #include #include @@ -37,16 +39,31 @@ #define FILEATTACH_ICONSIZE 48 -PixmapPreviewSelector::PixmapPreviewSelector( QWidget * parent ) +PixmapPreviewSelector::PixmapPreviewSelector( QWidget * parent, PreviewPosition position ) : QWidget( parent ) { - QHBoxLayout * mainlay = new QHBoxLayout( this ); + m_previewPosition = position; + QVBoxLayout * mainlay = new QVBoxLayout( this ); mainlay->setMargin( 0 ); + QHBoxLayout * toplay = new QHBoxLayout( this ); + toplay->setMargin( 0 ); + mainlay->addLayout( toplay ); m_comboItems = new KComboBox( this ); - mainlay->addWidget( m_comboItems ); - mainlay->setAlignment( m_comboItems, Qt::AlignTop ); + toplay->addWidget( m_comboItems ); + m_stampPushButton = new QPushButton(QIcon::fromTheme( "document-open" ), "", this ); + m_stampPushButton->setVisible( false ); + toplay->addWidget(m_stampPushButton); m_iconLabel = new QLabel( this ); - mainlay->addWidget( m_iconLabel ); + switch ( m_previewPosition ) + { + case Side: + toplay->addWidget( m_iconLabel ); + break; + case Below: + mainlay->addWidget( m_iconLabel ); + mainlay->setAlignment( m_iconLabel, Qt::AlignHCenter ); + break; + } m_iconLabel->setSizePolicy( QSizePolicy::Fixed, QSizePolicy::Fixed ); m_iconLabel->setAlignment( Qt::AlignCenter ); m_iconLabel->setFrameStyle( QFrame::StyledPanel ); @@ -57,6 +74,7 @@ connect( m_comboItems, SIGNAL(currentIndexChanged(QString)), this, SLOT(iconComboChanged(QString)) ); connect( m_comboItems, &QComboBox::editTextChanged, this, &PixmapPreviewSelector::iconComboChanged ); + connect( m_stampPushButton, SIGNAL(clicked()), this, SLOT(selectCustomStamp()) ); } PixmapPreviewSelector::~PixmapPreviewSelector() @@ -93,7 +111,15 @@ void PixmapPreviewSelector::setPreviewSize( int size ) { m_previewSize = size; - m_iconLabel->setFixedSize( m_previewSize + 8, m_previewSize + 8 ); + switch( m_previewPosition ) + { + case Side: + m_iconLabel->setFixedSize( m_previewSize + 8, m_previewSize + 8 ); + break; + case Below: + m_iconLabel->setFixedSize( 3 * m_previewSize + 8, m_previewSize + 8 ); + break; + } iconComboChanged( m_icon ); } @@ -105,6 +131,7 @@ void PixmapPreviewSelector::setEditable( bool editable ) { m_comboItems->setEditable( editable ); + m_stampPushButton->setVisible( editable ); } void PixmapPreviewSelector::iconComboChanged( const QString& icon ) @@ -119,15 +146,29 @@ m_icon = icon; } - QPixmap pixmap = GuiUtils::loadStamp( m_icon, QSize(), m_previewSize ); + QPixmap pixmap = GuiUtils::loadStamp( m_icon, m_previewSize ); const QRect cr = m_iconLabel->contentsRect(); if ( pixmap.width() > cr.width() || pixmap.height() > cr.height() ) pixmap = pixmap.scaled( cr.size(), Qt::KeepAspectRatio, Qt::SmoothTransformation ); m_iconLabel->setPixmap( pixmap ); emit iconChanged( m_icon ); } +void PixmapPreviewSelector::selectCustomStamp() +{ + const QString customStampFile = QFileDialog::getOpenFileName(this, i18n("Select custom stamp symbol"), + QString(), i18n("*.ico *.png *.xpm *.svg *.svgz | Icon Files (*.ico *.png *.xpm *.svg *.svgz)") ); + if ( !customStampFile.isEmpty() ) + { + QPixmap pixmap = GuiUtils::loadStamp( customStampFile, m_previewSize ); + if( pixmap.isNull() ) { + KMessageBox::sorry( this, i18n( "Could not load the file %1", customStampFile ), "Invalid file" ); + } else { + m_comboItems->setEditText(customStampFile); + } + } +} AnnotationWidget * AnnotationWidgetFactory::widgetFor( Okular::Annotation * ann ) { @@ -389,7 +430,7 @@ addOpacitySpinBox( widget, formlayout ); addVerticalSpacer( formlayout ); - m_pixmapSelector = new PixmapPreviewSelector( widget ); + m_pixmapSelector = new PixmapPreviewSelector( widget, PixmapPreviewSelector::Below ); formlayout->addRow( i18n( "Stamp symbol:" ), m_pixmapSelector ); m_pixmapSelector->setEditable( true ); diff --git a/ui/guiutils.h b/ui/guiutils.h --- a/ui/guiutils.h +++ b/ui/guiutils.h @@ -39,7 +39,14 @@ QString prettyToolTip( const Okular::Annotation * annotation ); - QPixmap loadStamp( const QString& name, const QSize& size, int iconSize = 0 ); + /** + * Returns a pixmap for a stamp symbol + * + * @p name Name of a Okular stamp symbol, icon or path to an image + * @p size Size of the pixmap (ignore aspect ratio). Takes precedence over @p iconSize + * @p iconSize Maximum size of the pixmap (keep aspect ratio) + */ + QPixmap loadStamp( const QString& nameOrPath, int size, bool keepAspectRatio = true ); void addIconLoader( KIconLoader * loader ); void removeIconLoader( KIconLoader * loader ); diff --git a/ui/guiutils.cpp b/ui/guiutils.cpp --- a/ui/guiutils.cpp +++ b/ui/guiutils.cpp @@ -169,29 +169,45 @@ return tooltip; } -QPixmap loadStamp( const QString& _name, const QSize& size, int iconSize ) +QPixmap loadStamp( const QString& nameOrPath, int size, bool keepAspectRatio ) { - const QString name = _name.toLower(); + const QString name = nameOrPath.toLower(); + + // _name is the name of an Okular stamp symbols ( multiple symbols in a single *.svg file) QSvgRenderer * r = nullptr; if ( ( r = s_data->svgStamps() ) && r->elementExists( name ) ) { - const QRectF stampElemRect = r->boundsOnElement( name ); - const QRectF stampRect( size.isValid() ? QRectF( QPointF( 0, 0 ), size ) : stampElemRect ); - QPixmap pixmap( stampRect.size().toSize() ); + const QSize stampSize = r->boundsOnElement( name ).size().toSize(); + const QSize pixmapSize = stampSize.scaled( size, size, + keepAspectRatio ? Qt::KeepAspectRatioByExpanding + : Qt::IgnoreAspectRatio ); + QPixmap pixmap( pixmapSize ); pixmap.fill( Qt::transparent ); QPainter p( &pixmap ); r->render( &p, name ); p.end(); return pixmap; } + + // _name is a path (do this before loading as icon name to avoid some rare weirdness ) QPixmap pixmap; + pixmap.load( nameOrPath ); + if ( !pixmap.isNull() ) { + pixmap = pixmap.scaled( size, size, + keepAspectRatio ? Qt::KeepAspectRatioByExpanding + : Qt::IgnoreAspectRatio, + Qt::SmoothTransformation ); + return pixmap; + } + + // _name is an icon name const KIconLoader * il = iconLoader(); QString path; - const int minSize = iconSize > 0 ? iconSize : qMin( size.width(), size.height() ); - pixmap = il->loadIcon( name, KIconLoader::User, minSize, KIconLoader::DefaultState, QStringList(), &path, true ); + pixmap = il->loadIcon( name, KIconLoader::User, size, KIconLoader::DefaultState, QStringList(), &path, true ); if ( path.isEmpty() ) - pixmap = il->loadIcon( name, KIconLoader::NoGroup, minSize ); - return pixmap; + pixmap = il->loadIcon( name, KIconLoader::NoGroup, size ); + + return pixmap; // can be a null pixmap } void addIconLoader( KIconLoader * loader ) diff --git a/ui/pagepainter.cpp b/ui/pagepainter.cpp --- a/ui/pagepainter.cpp +++ b/ui/pagepainter.cpp @@ -680,7 +680,7 @@ Okular::StampAnnotation * stamp = (Okular::StampAnnotation *)a; // get pixmap and alpha blend it if needed - QPixmap pixmap = GuiUtils::loadStamp( stamp->stampIconName(), annotBoundary.size() ); + QPixmap pixmap = GuiUtils::loadStamp( stamp->stampIconName(), annotBoundary.width() ); if ( !pixmap.isNull() ) // should never happen but can happen on huge sizes { const QRect dInnerRect(QRectF(innerRect.x() * dpr, innerRect.y() * dpr, innerRect.width() * dpr, innerRect.height() * dpr).toAlignedRect()); diff --git a/ui/pageviewannotator.cpp b/ui/pageviewannotator.cpp --- a/ui/pageviewannotator.cpp +++ b/ui/pageviewannotator.cpp @@ -65,7 +65,7 @@ // create engine objects if ( !hoverIconName.simplified().isEmpty() ) - pixmap = GuiUtils::loadStamp( hoverIconName, QSize( size, size ) ); + pixmap = GuiUtils::loadStamp( hoverIconName, size ); } QRect event( EventType type, Button button, double nX, double nY, double xScale, double yScale, const Okular::Page * page ) override @@ -244,8 +244,8 @@ const int ml = ( rcf.bottomRight() - rcf.topLeft() ).toPoint().manhattanLength(); if ( ml <= QApplication::startDragDistance() ) { - const double stampxscale = size / xscale; - const double stampyscale = size / yscale; + const double stampxscale = pixmap.width() / xscale; + const double stampyscale = pixmap.height() / yscale; if ( center ) { rect.left = point.x - stampxscale / 2; @@ -1235,7 +1235,7 @@ } else if ( annotType == QLatin1String("stamp") ) { - QPixmap stamp = GuiUtils::loadStamp( icon, QSize( 16, 16 ) ); + QPixmap stamp = GuiUtils::loadStamp( icon, 16, false /* keepAspectRatio */ ); p.setRenderHint( QPainter::Antialiasing ); p.drawPixmap( 16, 14, stamp ); }