Commit f15e8568 authored by Simone Gaiarin's avatar Simone Gaiarin

General improvements to stamp annotation

Summary:
Configuration:
- Add push button to select custom stamp image
- Check if loaded image is usable as stamp or throw error
- Keep image proportions in previewer
- Move previewer below the combobox to display larger preview

Annotation tool:
- Keep stamp image proportion in annotation preview (while left mouse button is down)
- Adding the annotation with one-click (without holding the left mouse button and dragging) adds the stamp with original proportions

BUG: 370381
BUG: 383652
CCBUG: 383651
FIXED-IN: 1.9.0

Closes T8074

TODO:
- [ ] Check if filters in file chooser make sense / propose better alternative
- [x] Update doc ( @yurchor will do it after we merge this)

Test Plan:
From stamp annotation configuration dialog:
- Show a warning regarding limitations of the feature's current implementation
- Click push button next to combo box opens a file selector
- Selecting a corrupted image file should throw an error
- Selecting a good image file shows the preview of the image
- Select a horizontal image shows a large clear preview
- Select a vertical image file shows a smaller preview without messing up the visual of the config dialog
- Input a valid icon name in the combobox and the preview of the icon is shown

From page view, select the stamp annotation with horizontal image file (not squared):
- Click and hold. The preview maintains proportions
- Single click. The stamp image in the pdf maintains proportions and has the same size of the click and hold preview.
- Add an annotation of the Okular custom stamps (internal SVG so treated slightly differently) do not create problems

Reviewers: #okular, ngraham

Reviewed By: ngraham

Subscribers: pino, aacid, yurchor, ngraham, okular-devel

Tags: #okular

Maniphest Tasks: T8074

Differential Revision: https://phabricator.kde.org/D22064
parent 8e01c0fd
......@@ -19,7 +19,10 @@
#include <kcolorbutton.h>
#include <kcombobox.h>
#include <kfontrequester.h>
#include <KMessageBox>
#include <KMessageWidget>
#include <QIcon>
#include <QFileDialog>
#include <kiconloader.h>
#include <KLocalizedString>
#include <QDebug>
......@@ -37,16 +40,31 @@
#define FILEATTACH_ICONSIZE 48
PixmapPreviewSelector::PixmapPreviewSelector( QWidget * parent )
: QWidget( parent )
PixmapPreviewSelector::PixmapPreviewSelector( QWidget * parent, PreviewPosition position )
: QWidget( parent ), m_previewPosition( position )
{
QHBoxLayout * mainlay = new QHBoxLayout( this );
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" ), QString(), this );
m_stampPushButton->setVisible( false );
m_stampPushButton->setToolTip( i18nc( "@info:tooltip", "Select a custom stamp symbol from file") );
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 +75,7 @@ PixmapPreviewSelector::PixmapPreviewSelector( QWidget * parent )
connect( m_comboItems, SIGNAL(currentIndexChanged(QString)), this, SLOT(iconComboChanged(QString)) );
connect( m_comboItems, &QComboBox::editTextChanged, this, &PixmapPreviewSelector::iconComboChanged );
connect( m_stampPushButton, &QPushButton::clicked, this, &PixmapPreviewSelector::selectCustomStamp );
}
PixmapPreviewSelector::~PixmapPreviewSelector()
......@@ -93,7 +112,15 @@ void PixmapPreviewSelector::addItem( const QString& item, const QString& id )
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 +132,7 @@ int PixmapPreviewSelector::previewSize() const
void PixmapPreviewSelector::setEditable( bool editable )
{
m_comboItems->setEditable( editable );
m_stampPushButton->setVisible( editable );
}
void PixmapPreviewSelector::iconComboChanged( const QString& icon )
......@@ -119,7 +147,7 @@ void PixmapPreviewSelector::iconComboChanged( const QString& icon )
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 );
......@@ -128,6 +156,23 @@ void PixmapPreviewSelector::iconComboChanged( const QString& icon )
emit iconChanged( m_icon );
}
void PixmapPreviewSelector::selectCustomStamp()
{
const QString customStampFile = QFileDialog::getOpenFileName(this, i18nc("@title:window file chooser", "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,
xi18nc("@info", "Could not load the file <filename>%1</filename>", customStampFile ),
i18nc("@title:window", "Invalid file")
);
} else {
m_comboItems->setEditText(customStampFile);
}
}
}
AnnotationWidget * AnnotationWidgetFactory::widgetFor( Okular::Annotation * ann )
{
......@@ -386,10 +431,18 @@ void StampAnnotationWidget::createStyleWidget( QFormLayout * formlayout )
{
QWidget * widget = qobject_cast<QWidget *>( formlayout->parent() );
KMessageWidget * brokenStampSupportWarning = new KMessageWidget( widget );
brokenStampSupportWarning->setText( xi18nc("@info", "<warning>experimental feature.<nl/>"
"Stamps inserted in PDF documents are not visible in PDF readers other than Okular.</warning>") );
brokenStampSupportWarning->setMessageType( KMessageWidget::Warning );
brokenStampSupportWarning->setWordWrap( true );
brokenStampSupportWarning->setCloseButtonVisible( false );
formlayout->insertRow( 0, brokenStampSupportWarning );
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 );
......
......@@ -19,6 +19,7 @@ class QComboBox;
class QDoubleSpinBox;
class QFormLayout;
class QLabel;
class QPushButton;
class QWidget;
class KColorButton;
class QSpinBox;
......@@ -31,7 +32,9 @@ class PixmapPreviewSelector
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 @@ Q_SIGNALS:
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;
};
......
......@@ -169,29 +169,45 @@ QString prettyToolTip( const Okular::Annotation * ann )
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 )
......
......@@ -39,7 +39,14 @@ namespace GuiUtils
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 );
......
......@@ -680,7 +680,7 @@ void PagePainter::paintCroppedPageOnPainter( QPainter * destPainter, const Okula
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());
......
......@@ -65,7 +65,7 @@ class PickPointEngine : public AnnotatorEngine
// 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 @@ class PickPointEngine : public AnnotatorEngine
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 @@ QPixmap PageViewAnnotator::makeToolPixmap( const QDomElement &toolElement )
}
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 );
}
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment