diff --git a/ui/pageviewutils.cpp b/ui/pageviewutils.cpp index 3f992484c..96e5f0b7f 100644 --- a/ui/pageviewutils.cpp +++ b/ui/pageviewutils.cpp @@ -231,6 +231,7 @@ PageViewMessage::PageViewMessage( QWidget * parent ) void PageViewMessage::display( const QString & message, const QString & details, Icon icon, int durationMs ) // give Caesar what belongs to Caesar: code taken from Amarok's osd.h/.cpp // "redde (reddite, pl.) cesari quae sunt cesaris", just btw. :) +// The code has been heavily modified since then. { if ( !Okular::Settings::showOSD() ) { @@ -244,28 +245,7 @@ void PageViewMessage::display( const QString & message, const QString & details, // reset vars m_lineSpacing = 0; - // determine text rectangle - QRect textRect = fontMetrics().boundingRect( m_message ); - textRect.translate( -textRect.left(), -textRect.top() ); - textRect.adjust( 0, 0, 2, 2 ); - int width = textRect.width(), - height = textRect.height(); - - if ( !m_details.isEmpty() ) - { - // determine details text rectangle - QRect detailsRect = fontMetrics().boundingRect( m_details ); - detailsRect.translate( -detailsRect.left(), -detailsRect.top() ); - detailsRect.adjust( 0, 0, 2, 2 ); - width = qMax( width, detailsRect.width() ); - height += detailsRect.height(); - - // plus add a ~60% line spacing - m_lineSpacing = static_cast< int >( fontMetrics().height() * 0.6 ); - height += m_lineSpacing; - } - - // load icon (if set) and update geometry + // load icon (if set) m_symbol = QPixmap(); if ( icon != None ) { @@ -288,18 +268,9 @@ void PageViewMessage::display( const QString & message, const QString & details, break; } - width += 2 + m_symbol.width(); - height = qMax( height, m_symbol.height() ); } - // resize widget - resize( QRect( 0, 0, width + 10, height + 8 ).size() ); - - // if the layout is RtL, we can move it to the right place only after we - // know how much size it will take - if ( layoutDirection() == Qt::RightToLeft ) - move( parentWidget()->width() - geometry().width() - 10 - 1, 10 ); - + computeSizeAndResize(); // show widget and schedule a repaint show(); update(); @@ -316,24 +287,94 @@ void PageViewMessage::display( const QString & message, const QString & details, m_timer->start( durationMs ); } else if ( m_timer ) m_timer->stop(); + + qobject_cast(parentWidget())->viewport()->installEventFilter(this); + } -void PageViewMessage::paintEvent( QPaintEvent * /* e */ ) +QRect PageViewMessage::computeTextRect( const QString & message, int extra_width ) const +// Return the QRect which embeds the text { - QRect textRect = fontMetrics().boundingRect( m_message ); + int charSize = fontMetrics().averageCharWidth(); + /* width of the viewport, minus 20 (~ size removed by further resizing), + minus the extra size (usually the icon width), minus (a bit empirical) + twice the mean width of a character to ensure that the bounding box is + really smaller than the container. + */ + const int boundingWidth = qobject_cast(parentWidget())->viewport()->width() - 20 - ( extra_width > 0 ? 2 + extra_width : 0 ) - 2*charSize; + QRect textRect = fontMetrics().boundingRect( 0, 0, boundingWidth, 0, + Qt::AlignLeft | Qt::AlignTop | Qt::TextWordWrap, message ); textRect.translate( -textRect.left(), -textRect.top() ); textRect.adjust( 0, 0, 2, 2 ); + return textRect; +} + +void PageViewMessage::computeSizeAndResize() +{ + // determine text rectangle + const QRect textRect = computeTextRect( m_message, m_symbol.width() ); + int width = textRect.width(), + height = textRect.height(); + + if ( !m_details.isEmpty() ) + { + // determine details text rectangle + const QRect detailsRect = computeTextRect( m_details, m_symbol.width() ); + width = qMax( width, detailsRect.width() ); + height += detailsRect.height(); + + // plus add a ~60% line spacing + m_lineSpacing = static_cast< int >( fontMetrics().height() * 0.6 ); + height += m_lineSpacing; + } + + // update geometry with icon information + if ( ! m_symbol.isNull() ) + { + width += 2 + m_symbol.width(); + height = qMax( height, m_symbol.height() ); + } + + // resize widget + resize( QRect( 0, 0, width + 10, height + 8 ).size() ); + + // if the layout is RtL, we can move it to the right place only after we + // know how much size it will take + if ( layoutDirection() == Qt::RightToLeft ) + move( parentWidget()->width() - geometry().width() - 10 - 1, 10 ); +} + + +bool PageViewMessage::eventFilter(QObject * obj, QEvent * event ) +{ + /* if the parent object (scroll area) resizes, the message should + resize as well */ + if (event->type() == QEvent::Resize) + { + QResizeEvent *resizeEvent = static_cast(event); + if ( resizeEvent->oldSize() != resizeEvent->size() ) + { + computeSizeAndResize(); + } + } + // standard event processing + return QObject::eventFilter(obj, event); +} + +void PageViewMessage::paintEvent( QPaintEvent * /* e */ ) +{ + const QRect textRect = computeTextRect( m_message, m_symbol.width() ); + QRect detailsRect; if ( !m_details.isEmpty() ) { - detailsRect = fontMetrics().boundingRect( m_details ); - detailsRect.translate( -detailsRect.left(), -detailsRect.top() ); - detailsRect.adjust( 0, 0, 2, 2 ); + detailsRect = computeTextRect( m_details, m_symbol.width() ); } int textXOffset = 0, - textYOffset = geometry().height() - textRect.height() / 2 - detailsRect.height() - m_lineSpacing, + // add 2 to account for the reduced drawRoundRect later + textYOffset = ( geometry().height() - textRect.height() - detailsRect.height() - m_lineSpacing + 2 ) / 2, iconXOffset = 0, iconYOffset = !m_symbol.isNull() ? ( geometry().height() - m_symbol.height() ) / 2 : 0, shadowOffset = 1; @@ -355,15 +396,19 @@ void PageViewMessage::paintEvent( QPaintEvent * /* e */ ) if ( !m_symbol.isNull() ) painter.drawPixmap( 5 + iconXOffset, iconYOffset, m_symbol, 0, 0, m_symbol.width(), m_symbol.height() ); + const int xStartPoint = 5 + textXOffset; + const int yStartPoint = textYOffset; + const int textDrawingFlags = Qt::AlignLeft | Qt::AlignTop | Qt::TextWordWrap; + // draw shadow and text painter.setPen( palette().color( QPalette::Window ).dark( 115 ) ); - painter.drawText( 5 + textXOffset + shadowOffset, textYOffset + shadowOffset, m_message ); + painter.drawText( xStartPoint + shadowOffset, yStartPoint + shadowOffset, textRect.width(), textRect.height(), textDrawingFlags, m_message ); if ( !m_details.isEmpty() ) - painter.drawText( 5 + textXOffset + shadowOffset, textYOffset + textRect.height() + m_lineSpacing + shadowOffset, m_details ); + painter.drawText( xStartPoint + shadowOffset, yStartPoint + textRect.height() + m_lineSpacing + shadowOffset, textRect.width(), detailsRect.height(), textDrawingFlags, m_details ); painter.setPen( palette().color( QPalette::WindowText ) ); - painter.drawText( 5 + textXOffset, textYOffset, m_message ); + painter.drawText( xStartPoint, yStartPoint, textRect.width(), textRect.height(), textDrawingFlags, m_message ); if ( !m_details.isEmpty() ) - painter.drawText( 5 + textXOffset + shadowOffset, textYOffset + textRect.height() + m_lineSpacing, m_details ); + painter.drawText( xStartPoint + shadowOffset, yStartPoint + textRect.height() + m_lineSpacing, textRect.width(), detailsRect.height(), textDrawingFlags, m_details ); } void PageViewMessage::mousePressEvent( QMouseEvent * /*e*/ ) diff --git a/ui/pageviewutils.h b/ui/pageviewutils.h index bc77cc9aa..0772d368b 100644 --- a/ui/pageviewutils.h +++ b/ui/pageviewutils.h @@ -108,10 +108,13 @@ class PageViewMessage : public QWidget void display( const QString & message, const QString & details = QString(), Icon icon = Info, int durationMs = 4000 ); protected: + bool eventFilter(QObject * obj, QEvent * event ); void paintEvent( QPaintEvent * e ); void mousePressEvent( QMouseEvent * e ); private: + QRect computeTextRect( const QString & message, int extra_width ) const; + void computeSizeAndResize(); QString m_message; QString m_details; QPixmap m_symbol;