/*************************************************************************** chatstatusbar.cpp - description ------------------- begin : Wed Okt 8 2008 copyright : (C) 2008 by Ruben Vandamme email : ruben@kmess.org ***************************************************************************/ /*************************************************************************** * * * 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 "chatstatusbar.h" #include <KColorScheme> #include <KIconLoader> #include <KLocale> #include <QFontMetrics> #include <QPainter> #include <QPushButton> #include <QPixmap> #include <QTimer> // The constructor ChatStatusBar::ChatStatusBar( QWidget* parent ) : QWidget( parent ), type_( DefaultType ), state_( DefaultState ), illumination_( 0 ), minTextHeight_( -1 ), timer_( 0 ), button_( 0 ) { setMinimumHeight( KIconLoader::SizeSmall ); timer_ = new QTimer( this ); connect( timer_, SIGNAL( timeout() ), this, SLOT( timerDone() ) ); button_ = new QPushButton(i18nc("@action:button", "Reconnect"), this); button_->hide(); connect(button_, SIGNAL(clicked()), this, SLOT(buttonClicked())); setMinimumTextHeight(KIconLoader::SizeSmall + 8); } // The destructor ChatStatusBar::~ChatStatusBar() { } // Shows a message in the status label. void ChatStatusBar::setMessage( MessageType type, const QString& text ) { if ( ( text == text_ ) && ( type == type_ ) ) { return; } text_ = text; type_ = type; timer_->stop(); illumination_ = 0; state_ = DefaultState; const char* iconName = 0; switch ( type ) { case Disconnected: iconName = "network-disconnect"; timer_->start( 100 ); state_ = Illuminate; updateCloseButtonPosition(); button_->setEnabled( true ); button_->show(); break; case ContactTyping: iconName = "input-keyboard"; button_->hide(); break; case DefaultType: default: button_->hide(); break; } pixmap_ = ( iconName == 0 ) ? QPixmap() : SmallIcon( iconName ); QTimer::singleShot( GeometryTimeout, this, SLOT( assureVisibleText() ) ); update(); } // Set the minimum text height. void ChatStatusBar::setMinimumTextHeight( int min ) { if ( min != minTextHeight_ ) { minTextHeight_ = min; setMinimumHeight( min ); if ( button_->height() > min ) { button_->setFixedHeight( min ); } } } // Enable or disable the button for the specified message type. void ChatStatusBar::setButtonEnabled ( MessageType type, bool enable ) { if( type == type_ ) { button_->setEnabled( enable ); } } // Paint the statusbar. void ChatStatusBar::paintEvent( QPaintEvent* /* event */ ) { QPainter painter( this ); if ( illumination_ > 0 ) { // At this point, a: we are a second label being drawn over the already // painted status area, so we can be translucent, and b: our palette's // window color (bg only) seems to be wrong (always black) KColorScheme scheme( palette().currentColorGroup(), KColorScheme::Window ); QColor backgroundColor( scheme.background( KColorScheme::NegativeBackground ).color() ); backgroundColor.setAlpha( qMin( 255, illumination_ * 2 ) ); painter.setBrush( backgroundColor ); painter.setPen ( Qt::NoPen ); painter.drawRect( QRect( 0, 0, width(), height() ) ); } // Draw pixmap int x = BorderGap; const int y = ( minTextHeight_ - pixmap_.height() ) / 2; if ( !pixmap_.isNull() ) { painter.drawPixmap( x, y, pixmap_ ); x += pixmap_.width() + BorderGap; } // Draw text painter.setPen( palette().windowText().color() ); int flags = Qt::AlignVCenter; if ( height() > minTextHeight_ ) { flags = flags | Qt::TextWordWrap; } painter.drawText( QRect( x, 0, availableTextWidth(), height() ), flags, text_ ); painter.end(); } // Statusbar is resized, update it. void ChatStatusBar::resizeEvent( QResizeEvent* event ) { QWidget::resizeEvent( event ); updateCloseButtonPosition(); QTimer::singleShot( GeometryTimeout, this, SLOT( assureVisibleText() ) ); } // Update the background color. void ChatStatusBar::timerDone() { switch ( state_ ) { case Illuminate: { // increase the illumination const int illumination_max = 128; if ( illumination_ < illumination_max ) { illumination_ += 32; if ( illumination_ > illumination_max ) { illumination_ = illumination_max; } update(); } else { state_ = Illuminated; timer_->start( 5000 ); } break; } case Illuminated: // start desaturation state_ = Desaturate; timer_->start( 100 ); break; case Desaturate: // desaturate if ( illumination_ > 0 ) { illumination_ -= 5; update(); } else { state_ = DefaultState; timer_->stop(); } break; default: break; } } // Increases the height of the message label so that the given text fits into given area. void ChatStatusBar::assureVisibleText() { if ( text_.isEmpty() ) { return; } int requiredHeight = minTextHeight_; if ( type_ != DefaultType && type_ != ContactTyping ) { // Calculate the required height of the widget thats // needed for having a fully visible text. Note that for certain // statusbar types increasing the text height is not wanted, // as this might rearrange the layout of items. const QFontMetrics& fontMetrics( font() ); const QRect bounds( fontMetrics.boundingRect( 0, 0, availableTextWidth(), height(), Qt::AlignVCenter | Qt::TextWordWrap, text_ ) ); requiredHeight = bounds.height(); if ( requiredHeight < minTextHeight_ ) { requiredHeight = minTextHeight_; } } // Increase/decrease the current height of the widget to the // required height. The increasing/decreasing is done in several // steps to have an animation if the height is modified // (see ChatStatusBar::resizeEvent()) const int gap = minTextHeight_ / 2; int minHeight = minimumHeight(); if ( minHeight < requiredHeight ) { minHeight += gap; if ( minHeight > requiredHeight ) { minHeight = requiredHeight; } setMinimumHeight(minHeight); updateGeometry(); } else if ( minHeight > requiredHeight ) { minHeight -= gap; if ( minHeight < requiredHeight ) { minHeight = requiredHeight; } setMinimumHeight( minHeight ); updateGeometry(); } updateCloseButtonPosition(); } // Returns the available width in pixels for the text. int ChatStatusBar::availableTextWidth() const { const int buttonWidth = ( button_->isVisible() ) ? button_->width() + BorderGap : 0; return width() - pixmap_.width() - ( BorderGap * 4 ) - buttonWidth; } // Moves the close button to the upper right corner of the message label. void ChatStatusBar::updateCloseButtonPosition() { const int x = width() - button_->width() - BorderGap; const int y = ( height() - button_->height() ) / 2; button_->move( x, y ); } // User requested an action. void ChatStatusBar::buttonClicked() { emit reconnect(); } // Resets the message label properties. void ChatStatusBar::reset() { text_.clear(); button_->setEnabled( true ); type_ = DefaultType; } // Returns the type of the status message. inline ChatStatusBar::MessageType ChatStatusBar::type() const { return type_; } // Returns the text in the statusbar. inline const QString& ChatStatusBar::text() const { return text_; } // Returns the minimum text height. inline int ChatStatusBar::minimumTextHeight() const { return minTextHeight_; } #include "chatstatusbar.moc"