diff --git a/keduvocdocument/CMakeLists.txt b/keduvocdocument/CMakeLists.txt index e582b6e..8ea9bc0 100644 --- a/keduvocdocument/CMakeLists.txt +++ b/keduvocdocument/CMakeLists.txt @@ -1,207 +1,212 @@ if (BUILD_TESTING) add_subdirectory(autotests) add_subdirectory(tests) endif() ########### next target ############### include(ECMSetupVersion) ecm_setup_version(5.0.0 VARIABLE_PREFIX KDEEDU VERSION_HEADER "${CMAKE_BINARY_DIR}/keduvocdocument/keduvocdocument_version.h" PACKAGE_VERSION_FILE "${CMAKE_BINARY_DIR}/KEduVocDocumentVersion.cmake") include_directories( ${CMAKE_CURRENT_BINARY_DIR} ) set(keduvocdocument_LIB_SRCS keduvocdocument.cpp keduvocidentifier.cpp keduvocexpression.cpp keduvoctranslation.cpp keduvoccontainer.cpp keduvoclesson.cpp keduvocleitnerbox.cpp keduvoctext.cpp keduvocarticle.cpp keduvocconjugation.cpp keduvocpersonalpronoun.cpp keduvocdeclension.cpp keduvocwordtype.cpp keduvockvtmlcompability.cpp keduvockvtml2writer.cpp keduvoccsvwriter.cpp keduvoccontainermodel.cpp keduvoclessonmodel.cpp keduvocreadonlycontainermodel.cpp keduvocvocabularymodel.cpp keduvocwordclassmodel.cpp keduvoccontainermimedata.cpp keduvocvocabularymimedata.cpp keduvocvocabularyfilter.cpp keduvoctranslator.cpp keduvocvocabularydelegate.cpp keduvocvocabularyheaderview.cpp keduvocvocabularycolumnsdialog.cpp keduvoccontainerview.cpp keduvocvocabularyview.cpp keduvocwordtypeview.cpp keduvoclessonview.cpp keduvocaudiowidget.cpp keduvocmultiplechoicewidget.cpp keduvoccomparisonwidget.cpp keduvocdeclensionwidget.cpp keduvocconjugationwidget.cpp keduvocinflectionwidget.cpp + keduvocimagewidget.cpp + keduvocimagechooserwidget.cpp readerwriters/dummyreader.cpp readerwriters/failedreader.cpp readerwriters/keduvockvtmlreader.cpp readerwriters/keduvockvtml2reader.cpp readerwriters/keduvoccsvreader.cpp readerwriters/keduvocpaukerreader.cpp readerwriters/keduvocvokabelnreader.cpp readerwriters/keduvocwqlreader.cpp readerwriters/keduvocxdxfreader.cpp readerwriters/readermanager.cpp sharedkvtmlfiles.cpp ) ki18n_wrap_ui(keduvocdocument_LIB_SRCS keduvocaudiowidget.ui keduvocmultiplechoicewidget.ui keduvoccomparisonwidget.ui keduvocdeclensionwidget.ui keduvocconjugationwidget.ui + keduvocimagechooserwidget.ui ) include(ECMGenerateHeaders) ecm_generate_headers( KdeEdu_HEADERS HEADER_NAMES KEduVocDocument KEduVocIdentifier KEduVocExpression KEduVocText KEduVocArticle KEduVocConjugation KEduVocLesson KEduVocLeitnerBox KEduVocContainer KEduVocWordFlags KEduVocMultipleChoice KEduVocTranslation KEduVocWordtype KEduVocPersonalPronoun SharedKVTMLFiles KEduVocDeclension KEduVocKVTML2Writer KEduVocContainerModel KEduVocLessonModel KEduVocReadOnlyContainerModel KEduVocVocabularyModel KEduVocWordClassModel KEduVocContainerMimeData KEduVocVocabularyMimeData KEduVocVocabularyFilter KEduVocTranslator KEduVocVocabularyDelegate KEduVocVocabularyHeaderView KEduVocVocabularyColumnsDialog KEduVocContainerView KEduVocVocabularyView KEduVocWordTypeView KEduVocLessonView KEduVocAudioWidget KEduVocMultipleChoiceWidget KEduVocComparisonWidget KEduVocDeclensionWidget KEduVocConjugationWidget KEduVocInflectionWidget + KEduVocImageWidget + KEduVocImageChooserWidget REQUIRED_HEADERS KdeEdu_HEADERS ) add_library(KEduVocDocument SHARED ${keduvocdocument_LIB_SRCS}) generate_export_header(KEduVocDocument BASE_NAME KEduVocDocument) # vHanda: Add library alias? target_link_libraries(KEduVocDocument PUBLIC Qt5::Xml Qt5::Gui Qt5::Core Qt5::Widgets Qt5::DBus Qt5::Multimedia PRIVATE KF5::I18n KF5::KIOCore KF5::KIOFileWidgets KF5::KIOWidgets KF5::KIONTLM KF5::Archive KF5::Completion KF5::WidgetsAddons KF5::SonnetCore KF5::SonnetUi KF5::Notifications KF5::XmlGui ) # vHanda: Add Export Name? set_target_properties(KEduVocDocument PROPERTIES VERSION ${KDEEDU_VERSION_STRING} SOVERSION ${KDEEDU_SOVERSION} ) target_include_directories(KEduVocDocument INTERFACE "$") #Library for non-api unittests add_library(keduvocdocument_static STATIC ${keduvocdocument_LIB_SRCS}) set_target_properties(keduvocdocument_static PROPERTIES COMPILE_FLAGS -DKEDUVOCDOCUMENT_STATIC_DEFINE) target_link_libraries(keduvocdocument_static PUBLIC KF5::KIOCore Qt5::Xml Qt5::Core Qt5::Gui Qt5::Widgets Qt5::DBus Qt5::Multimedia PRIVATE KF5::I18n KF5::KIOCore KF5::KIOFileWidgets KF5::KIOWidgets KF5::KIONTLM KF5::Archive KF5::Completion KF5::WidgetsAddons KF5::SonnetCore KF5::SonnetUi KF5::Notifications KF5::XmlGui ) # if we want to set our own version instead of following kde generic #set(LIB_KEDUVOCDOCUMENT_VERSION "5.0.0") #set(LIB_KEDUVOCDOCUMENT_SOVERSION "5") #set_target_properties(keduvocdocument # PROPERTIES VERSION ${LIB_KEDUVOCDOCUMENT_VERSION} # SOVERSION ${LIB_KEDUVOCDOCUMENT_SOVERSION} #) install(TARGETS KEduVocDocument EXPORT LibKEduVocDocumentTargets ${INSTALL_TARGETS_DEFAULT_ARGS}) ########### install files ############### install(FILES ${CMAKE_CURRENT_BINARY_DIR}/keduvocdocument_export.h ${KdeEdu_HEADERS} DESTINATION ${INCLUDE_INSTALL_DIR}/libkeduvocdocument COMPONENT Devel ) diff --git a/keduvocdocument/keduvocimagechooserwidget.cpp b/keduvocdocument/keduvocimagechooserwidget.cpp new file mode 100644 index 0000000..ab46449 --- /dev/null +++ b/keduvocdocument/keduvocimagechooserwidget.cpp @@ -0,0 +1,149 @@ +/*************************************************************************** + + Copyright 2007 Frederik Gladhorn + + ***************************************************************************/ + +/*************************************************************************** + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + ***************************************************************************/ + +#include "keduvocimagechooserwidget.h" + +#include "ui_keduvocimagechooserwidget.h" + +#include +#include + +#include +#include + +using namespace Editor; + +class KEduVocImageChooserWidget::Private +{ +public: + Private(); + + /// Column in the document - corresponds to the language (-KV_COL_TRANS) + int m_currentTranslation; + /// Selection in the doc - if more than one row is selected behavior is different + KEduVocExpression * m_entry; + + Ui::KEduVocImageChooserWidget * m_ui; +}; + +KEduVocImageChooserWidget::Private::Private() +{ + m_currentTranslation = -1; + m_entry = 0; + m_ui = new Ui::KEduVocImageChooserWidget(); +} + +KEduVocImageChooserWidget::KEduVocImageChooserWidget( QWidget *parent ) + : QWidget(parent) + , d( new Private ) +{ + d->m_ui->setupUi( this ); + + connect( d->m_ui->imageUrlRequester, &KUrlRequester::textChanged, this, &KEduVocImageChooserWidget::slotImageChanged ); + + d->m_ui->imageWidget->setAcceptDrops( true ); + d->m_ui->imageWidget->installEventFilter( this ); + setEnabled(false); +} + +KEduVocImageChooserWidget::~KEduVocImageChooserWidget() +{ + delete d; +} + +void KEduVocImageChooserWidget::setTranslation( KEduVocExpression* entry, int translation ) +{ + d->m_currentTranslation = translation; + d->m_entry = entry; + + if( d->m_entry ) { + setEnabled( true ); + d->m_ui->imageUrlRequester->setUrl( QUrl::fromLocalFile( d->m_entry->translation( d->m_currentTranslation )->imageUrl().toLocalFile() ) ); +// slotImageChanged( m_entry->translation(m_currentTranslation)->imageUrl().toLocalFile() ); + } else { + setEnabled( false ); + d->m_ui->imageUrlRequester->clear(); +// imageLabel->setText(i18nc("@label image preview is empty", "No Preview")); + d->m_ui->imageWidget->setPixmap( QPixmap() ); + } +} + +void KEduVocImageChooserWidget::slotImageChanged( const QString & url ) +{ + if( !url.isEmpty() ) { + QPixmap pixmap( url ); + d->m_ui->imageWidget->setPixmap( pixmap ); + } else { +// imageLabel->setText(i18nc("@label image preview is empty", "No Image")); + d->m_ui->imageWidget->setPixmap( QPixmap() ); + } + + if( d->m_entry ) { + d->m_entry->translation( d->m_currentTranslation )->setImageUrl( QUrl::fromLocalFile( url ) ); + foreach( int j, d->m_entry->translationIndices() ) { + if( d->m_entry->translation( j )->imageUrl().isEmpty() ) { + d->m_entry->translation( j )->setImageUrl( d->m_ui->imageUrlRequester->url() ); + } + } + } +} + +bool KEduVocImageChooserWidget::eventFilter( QObject * obj, QEvent * event ) +{ + if( obj == d->m_ui->imageWidget ) { +// if (event->type() == QEvent::KeyPress) { +// QKeyEvent *keyEvent = static_cast(event); +// qDebug() << "Ate key press " << keyEvent->key(); +// return true; +// } +// if (event->type() == QEvent::Resize) { +// QPixmap pixmap(imageUrlRequester->url().toLocalFile()); +// imageLabel->setPixmap(pixmap.scaled(imageLabel->size(), Qt::KeepAspectRatio)); +// return false; +// } + + + if( event->type() == QEvent::DragMove ) { + event->accept(); + return true; + } + + //Events with drop data + if( event->type() == QEvent::DragEnter || event->type() == QEvent::Drop ) { + if( !d->m_entry ) { + return true; + } + QDropEvent *dropEvent = dynamic_cast ( event ); + if( ( dropEvent!= NULL ) && ( dropEvent->mimeData()!= NULL ) ) { + const QMimeData * mimeData( dropEvent->mimeData() ); + if( mimeData->hasUrls() && mimeData->hasUrls() && ( mimeData->urls().size() == 1 ) ) { + switch( event->type() ) { + case QEvent::DragEnter: + event->accept(); + return true; + case QEvent::Drop: + d->m_ui->imageUrlRequester->setUrl( mimeData->urls().first() ); + return true; + break; + default: + break; + } + } + } + } + } + + return QObject::eventFilter( obj, event ); +} diff --git a/keduvocdocument/keduvocimagechooserwidget.h b/keduvocdocument/keduvocimagechooserwidget.h new file mode 100644 index 0000000..51cce37 --- /dev/null +++ b/keduvocdocument/keduvocimagechooserwidget.h @@ -0,0 +1,61 @@ +/*************************************************************************** + + Copyright 2007 Frederik Gladhorn + + ***************************************************************************/ + +/*************************************************************************** + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + ***************************************************************************/ + +#ifndef KEDUVOCIMAGECHOOSERWIDGET_H +#define KEDUVOCIMAGECHOOSERWIDGET_H + +#include +#include + +class KEduVocExpression; + +namespace Editor +{ + +class KEDUVOCDOCUMENT_EXPORT KEduVocImageChooserWidget : public QWidget +{ + Q_OBJECT +public: + explicit KEduVocImageChooserWidget( QWidget* parent = 0 ); + ~KEduVocImageChooserWidget(); + +public slots: + /** + * Update the word + * @param entry + * @param translation + */ + void setTranslation( KEduVocExpression* entry, int translation ); + +// signals: +// /** +// * Important to let other widgets know that a certain word type is edited (might make conjugations/comparison/declension appear) +// * @param +// */ +// void imageChanged(const QString&); + +private slots: + void slotImageChanged( const QString & url ); + +protected: + bool eventFilter( QObject * obj, QEvent * event ); + +private: + class Private; + Private * const d; +}; + +} +#endif diff --git a/keduvocdocument/keduvocimagechooserwidget.ui b/keduvocdocument/keduvocimagechooserwidget.ui new file mode 100644 index 0000000..1dafa33 --- /dev/null +++ b/keduvocdocument/keduvocimagechooserwidget.ui @@ -0,0 +1,50 @@ + + + KEduVocImageChooserWidget + + + + 0 + 0 + 142 + 130 + + + + + + + + 0 + 0 + + + + + 20 + 20 + + + + + + + + + + + + KUrlRequester + QFrame +
kurlrequester.h
+
+ + Practice::KEduVocImageWidget + QWidget +
keduvocimagewidget.h
+ 1 +
+
+ + +
diff --git a/keduvocdocument/keduvocimagewidget.cpp b/keduvocdocument/keduvocimagewidget.cpp new file mode 100644 index 0000000..4f20ae8 --- /dev/null +++ b/keduvocdocument/keduvocimagewidget.cpp @@ -0,0 +1,369 @@ +/*************************************************************************** + Copyright 2009 Daniel Laidig + ***************************************************************************/ + +/*************************************************************************** + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + ***************************************************************************/ + +#include "keduvocimagewidget.h" + +#include +#include +#include +#include + +#include +#include + +#if defined(Q_WS_X11) +#include +#include +#include +#undef KeyPress +#undef FocusOut +#endif + +using namespace Practice; + +// The functions centerPixmaps() and transition() are copied from kdelibs/plasma/paintutils.cpp, revision 1133527 +// License: LGPLv2+ +// Copyright 2005 by Aaron Seigo +// Copyright 2008 by Andrew Lake +// Don't just modify the code here, if there are issues they should probably also be fixed in libplasma. + +void centerPixmaps( QPixmap &from, QPixmap &to ) +{ + if( from.size() == to.size() && from.hasAlphaChannel() && to.hasAlphaChannel() ) { + return; + } + QRect fromRect( from.rect() ); + QRect toRect( to.rect() ); + + QRect actualRect = QRect( QPoint( 0, 0 ), fromRect.size().expandedTo( toRect.size() ) ); + fromRect.moveCenter( actualRect.center() ); + toRect.moveCenter( actualRect.center() ); + + if( from.size() != actualRect.size() || !from.hasAlphaChannel() ) { + QPixmap result( actualRect.size() ); + result.fill( Qt::transparent ); + QPainter p( &result ); + p.setCompositionMode( QPainter::CompositionMode_Source ); + p.drawPixmap( fromRect.topLeft(), from ); + p.end(); + from = result; + } + + if( to.size() != actualRect.size() || !to.hasAlphaChannel() ) { + QPixmap result( actualRect.size() ); + result.fill( Qt::transparent ); + QPainter p( &result ); + p.setCompositionMode( QPainter::CompositionMode_Source ); + p.drawPixmap( toRect.topLeft(), to ); + p.end(); + to = result; + } +} + +QPixmap transition( const QPixmap &from, const QPixmap &to, qreal amount ) +{ + if ( from.isNull() && to.isNull() ) { + return from; + } + + QPixmap startPixmap( from ); + QPixmap targetPixmap( to ); + + if( from.size() != to.size() || !from.hasAlphaChannel() || !to.hasAlphaChannel() ) { + centerPixmaps( startPixmap, targetPixmap ); + } + + //paint to in the center of from + QRect toRect = to.rect(); + + QColor color; + color.setAlphaF( amount ); + + + // If the native paint engine supports Porter/Duff compositing and CompositionMode_Plus + QPaintEngine *paintEngine = from.paintEngine(); + if( paintEngine && + paintEngine->hasFeature( QPaintEngine::PorterDuff ) && + paintEngine->hasFeature( QPaintEngine::BlendModes ) ) { + + QPainter p; + p.begin( &targetPixmap ); + p.setCompositionMode( QPainter::CompositionMode_DestinationIn ); + p.fillRect( targetPixmap.rect(), color ); + p.end(); + + p.begin( &startPixmap ); + p.setCompositionMode( QPainter::CompositionMode_DestinationOut ); + p.fillRect( startPixmap.rect(), color ); + p.setCompositionMode( QPainter::CompositionMode_Plus ); + p.drawPixmap( toRect.topLeft(), targetPixmap ); + p.end(); + + return startPixmap; + } +#if defined(Q_WS_X11) + // We have Xrender support + else if( paintEngine && paintEngine->hasFeature( QPaintEngine::PorterDuff ) ) { + // QX11PaintEngine doesn't implement CompositionMode_Plus in Qt 4.3, + // which we need to be able to do a transition from one pixmap to + // another. + // + // In order to avoid the overhead of converting the pixmaps to images + // and doing the operation entirely in software, this function has a + // specialized path for X11 that uses Xrender directly to do the + // transition. This operation can be fully accelerated in HW. + // + // This specialization can be removed when QX11PaintEngine supports + // CompositionMode_Plus. + QPixmap source( targetPixmap ), destination( startPixmap ); + + source.detach(); + destination.detach(); + + Display *dpy = QX11Info::display(); + + XRenderPictFormat *format = XRenderFindStandardFormat( dpy, PictStandardA8 ); + XRenderPictureAttributes pa; + pa.repeat = 1; // RepeatNormal + + // Create a 1x1 8 bit repeating alpha picture + Pixmap pixmap = XCreatePixmap( dpy, destination.handle(), 1, 1, 8 ); + Picture alpha = XRenderCreatePicture( dpy, pixmap, format, CPRepeat, &pa ); + XFreePixmap( dpy, pixmap ); + + // Fill the alpha picture with the opacity value + XRenderColor xcolor; + xcolor.alpha = quint16( 0xffff * amount ); + XRenderFillRectangle( dpy, PictOpSrc, alpha, &xcolor, 0, 0, 1, 1 ); + + // Reduce the alpha of the destination with 1 - opacity + XRenderComposite( dpy, PictOpOutReverse, alpha, None, destination.x11PictureHandle(), + 0, 0, 0, 0, 0, 0, destination.width(), destination.height() ); + + // Add source * opacity to the destination + XRenderComposite( dpy, PictOpAdd, source.x11PictureHandle(), alpha, + destination.x11PictureHandle(), + toRect.x(), toRect.y(), 0, 0, 0, 0, destination.width(), destination.height() ); + + XRenderFreePicture( dpy, alpha ); + return destination; + } +#endif + else { + // Fall back to using QRasterPaintEngine to do the transition. + QImage under = startPixmap.toImage(); + QImage over = targetPixmap.toImage(); + + QPainter p; + p.begin( &over ); + p.setCompositionMode( QPainter::CompositionMode_DestinationIn ); + p.fillRect( over.rect(), color ); + p.end(); + + p.begin( &under ); + p.setCompositionMode( QPainter::CompositionMode_DestinationOut ); + p.fillRect( under.rect(), color ); + p.setCompositionMode( QPainter::CompositionMode_Plus ); + p.drawImage( toRect.topLeft(), over ); + p.end(); + + return QPixmap::fromImage( under ); + } +} + +class KEduVocImageWidget::KEduVocImageWidget::Private +{ +public: + Private(); + + bool m_fading; + bool m_scaling; + bool m_onlyDownscaling; + Qt::AspectRatioMode m_keepAspectRatio; + Qt::Alignment m_alignment; + QPixmap m_originalPixmap; + QPixmap m_scaledPixmap; + QPixmap m_scaledBackupPixmap; + QPixmap m_animationPixmap; + bool m_scaledPixmapOutOfDate; + /// Timer used to delay the smooth scaling + QTimer *m_scaleTimer; + QTimeLine *m_animation; +}; + +KEduVocImageWidget::Private::Private() + : m_fading( true ) + , m_scaling( true ) + , m_onlyDownscaling( true ) + , m_keepAspectRatio( Qt::KeepAspectRatio ) + , m_alignment( Qt::AlignCenter ) +{ +} + +KEduVocImageWidget::KEduVocImageWidget( QWidget *parent ) + : QWidget(parent) + , d( new Private ) +{ + d->m_scaleTimer = new QTimer( this ); + d->m_scaleTimer->setSingleShot( true ); + d->m_scaleTimer->setInterval( 500 ); + + d->m_animation = new QTimeLine( 300, this ); + d->m_scaledPixmapOutOfDate = false; + + connect( d->m_scaleTimer, SIGNAL( timeout() ), this, SLOT( scalePixmap() ) ); + connect( d->m_animation, SIGNAL( valueChanged( qreal ) ), this, SLOT( update() ) ); + connect( d->m_animation, SIGNAL( finished() ), this, SLOT( animationFinished() ) ); +} + +KEduVocImageWidget::~KEduVocImageWidget() +{ + delete d; +} + +void KEduVocImageWidget::setPixmap( const QPixmap& pixmap ) +{ + //qDebug() << "set new pixmap, size:" << pixmap.size(); + if( d->m_animation->state() == QTimeLine::Running ) { + d->m_scaledPixmap = transition( d->m_animationPixmap, d->m_scaledPixmap, d->m_animation->currentValue() ); + d->m_animation->stop(); + animationFinished(); + } + + d->m_animationPixmap = d->m_scaledPixmap; + d->m_originalPixmap = pixmap; + d->m_scaledPixmap = QPixmap(); + d->m_scaledBackupPixmap = QPixmap(); + d->m_scaledPixmapOutOfDate = true; + if( !d->m_scaling ) { + d->m_scaledPixmap = pixmap; + } + scalePixmap( true ); + if( d->m_fading ) { + d->m_animation->start(); + } + update(); +} + +void KEduVocImageWidget::setScalingEnabled( bool scaling, bool onlyDownscaling ) +{ + d->m_scaling = scaling; + d->m_onlyDownscaling = onlyDownscaling; +} + +void KEduVocImageWidget::setKeepAspectRatio( Qt::AspectRatioMode mode ) +{ + d->m_keepAspectRatio = mode; +} + +void KEduVocImageWidget::setFadingEnabled( bool fading ) +{ + d->m_fading = fading; +} + +void KEduVocImageWidget::setAlignment( Qt::Alignment alignment ) +{ + d->m_alignment = alignment; +} + +void KEduVocImageWidget::paintEvent( QPaintEvent* e ) +{ + QWidget::paintEvent( e ); + QPainter painter( this ); + if( d->m_scaling && d->m_scaledPixmapOutOfDate ) { + d->m_scaleTimer->start(); + scalePixmap( false ); + } + QPixmap pm = d->m_scaledPixmap; + if( d->m_animation->state() == QTimeLine::Running ) { + pm = transition( d->m_animationPixmap, d->m_scaledPixmap, d->m_animation->currentValue() ); + } + + int x =( size().width() - pm.width() ) / 2; + if( d->m_alignment.testFlag( Qt::AlignLeft ) ) { + x = 0; + } else if( d->m_alignment.testFlag( Qt::AlignRight ) ) { + x = size().width() - pm.width(); + } + int y = ( size().height() - pm.height() ) / 2; + if( d->m_alignment.testFlag( Qt::AlignTop ) ) { + y = 0; + } else if( d->m_alignment.testFlag( Qt::AlignBottom ) ) { + y = size().height() - pm.height(); + } + painter.drawPixmap( x, y, pm ); +} + +void KEduVocImageWidget::resizeEvent( QResizeEvent* e ) +{ + if( !d->m_scaledPixmapOutOfDate ) { + d->m_scaledBackupPixmap = d->m_scaledPixmap; + } + // stop animations when resizing + if( d->m_animation->state() == QTimeLine::Running ) { + d->m_animation->stop(); + animationFinished(); + } + d->m_scaledPixmapOutOfDate = true; + QWidget::resizeEvent( e ); + emit sizeChanged(); +} + +void KEduVocImageWidget::scalePixmap( bool smooth ) +{ + bool scaleUp = d->m_originalPixmap.width() <= size().width() && d->m_originalPixmap.height() <= size().height(); + if( ( d->m_onlyDownscaling && scaleUp ) || d->m_originalPixmap.size() == size() ) { + //qDebug() << "no need to scale pixmap"; + d->m_scaledPixmapOutOfDate = false; + d->m_scaledPixmap = d->m_originalPixmap; + d->m_scaledBackupPixmap = QPixmap(); + } else if( smooth ) { + //qDebug() << "smooth scaling to" << size(); + if( d->m_originalPixmap.isNull() || size().isEmpty() ) { + d->m_scaledPixmapOutOfDate = false; + d->m_scaledPixmap = QPixmap(); + update(); + return; + } + d->m_scaledPixmap = d->m_originalPixmap.scaled( size(), d->m_keepAspectRatio, Qt::SmoothTransformation ); + d->m_scaledBackupPixmap = QPixmap(); + d->m_scaledPixmapOutOfDate = false; + update(); + } else { + //qDebug() << "fast scaling to" << size(); + // Try to find out if it makes sense to use the scaled backup pixmap. + // If the scaled backup gets too small, we use the original image. + float ratio = 0; + if( !size().isEmpty() ) { + ratio = qMin( float( d->m_scaledBackupPixmap.width() ) / size().width(), + float( d->m_scaledBackupPixmap.height() ) / size().height()); + } + if( ratio > 0.4 && !d->m_scaledBackupPixmap.isNull() ) { + d->m_scaledPixmap = d->m_scaledBackupPixmap.scaled( size(), d->m_keepAspectRatio, Qt::FastTransformation ); + } else { + if( d->m_originalPixmap.isNull() || size().isEmpty() ) { + d->m_scaledPixmap = QPixmap(); + return; + } + // use the original pixmap + d->m_scaledPixmap = d->m_originalPixmap.scaled( size(), d->m_keepAspectRatio, Qt::FastTransformation ); + d->m_scaledBackupPixmap = d->m_scaledPixmap; + } + d->m_scaledPixmapOutOfDate = true; + } +} + +void KEduVocImageWidget::animationFinished() +{ + d->m_animationPixmap = QPixmap(); +} diff --git a/keduvocdocument/keduvocimagewidget.h b/keduvocdocument/keduvocimagewidget.h new file mode 100644 index 0000000..f57561e --- /dev/null +++ b/keduvocdocument/keduvocimagewidget.h @@ -0,0 +1,58 @@ +/*************************************************************************** + Copyright 2009 Daniel Laidig + ***************************************************************************/ + +/*************************************************************************** + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + ***************************************************************************/ + +#ifndef KEDUVOCIMAGEWIDGET_H +#define KEDUVOCIMAGEWIDGET_H + +#include + +#include + +class QTimeLine; + +namespace Practice +{ + +class KEDUVOCDOCUMENT_EXPORT KEduVocImageWidget : public QWidget +{ + Q_OBJECT + +public: + KEduVocImageWidget( QWidget *parent = 0 ); + ~KEduVocImageWidget(); + + void setPixmap( const QPixmap& pixmap ); + void setScalingEnabled( bool scaling, bool onlyDownscaling = true ); + void setKeepAspectRatio( Qt::AspectRatioMode mode ); + void setFadingEnabled( bool fading ); + void setAlignment( Qt::Alignment alignment ); + +protected: + virtual void paintEvent( QPaintEvent *e ); + virtual void resizeEvent( QResizeEvent *e ); + +signals: + void sizeChanged(); + +private Q_SLOTS: + void scalePixmap( bool smooth = true ); + void animationFinished(); + +private: + class Private; + Private * const d; +}; + +} + +#endif // PRACTICE_IMAGEWIDGET_H