• Skip to content
  • Skip to link menu
KDE 4.2 API Reference
  • KDE API Reference
  • kdelibs
  • Sitemap
  • Contact Us
 

Plasma

pushbutton.cpp

Go to the documentation of this file.
00001 /*
00002  *   Copyright 2008 Aaron Seigo <aseigo@kde.org>
00003  *   Copyright 2008 Marco Martin <notmart@gmail.com>
00004  *
00005  *   This program is free software; you can redistribute it and/or modify
00006  *   it under the terms of the GNU Library General Public License as
00007  *   published by the Free Software Foundation; either version 2, or
00008  *   (at your option) any later version.
00009  *
00010  *   This program is distributed in the hope that it will be useful,
00011  *   but WITHOUT ANY WARRANTY; without even the implied warranty of
00012  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00013  *   GNU General Public License for more details
00014  *
00015  *   You should have received a copy of the GNU Library General Public
00016  *   License along with this program; if not, write to the
00017  *   Free Software Foundation, Inc.,
00018  *   51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
00019  */
00020 
00021 #include "pushbutton.h"
00022 
00023 #include <QStyleOptionGraphicsItem>
00024 #include <QPainter>
00025 #include <QDir>
00026 #include <QApplication>
00027 
00028 #include <kicon.h>
00029 #include <kiconeffect.h>
00030 #include <kmimetype.h>
00031 #include <kpushbutton.h>
00032 
00033 #include "theme.h"
00034 #include "svg.h"
00035 #include "framesvg.h"
00036 #include "animator.h"
00037 #include "paintutils.h"
00038 
00039 namespace Plasma
00040 {
00041 
00042 class PushButtonPrivate
00043 {
00044 public:
00045     PushButtonPrivate(PushButton *pushButton)
00046         : q(pushButton),
00047           background(0),
00048           animId(-1),
00049           fadeIn(false),
00050           svg(0)
00051     {
00052     }
00053 
00054     ~PushButtonPrivate()
00055     {
00056         delete svg;
00057     }
00058 
00059     void setPixmap(PushButton *q)
00060     {
00061         if (imagePath.isEmpty()) {
00062             return;
00063         }
00064 
00065         KMimeType::Ptr mime = KMimeType::findByPath(absImagePath);
00066         QPixmap pm(q->size().toSize());
00067 
00068         if (mime->is("image/svg+xml")) {
00069             svg = new Svg();
00070             QPainter p(&pm);
00071             svg->paint(&p, pm.rect());
00072         } else {
00073             pm = QPixmap(absImagePath);
00074         }
00075 
00076         static_cast<KPushButton*>(q->widget())->setIcon(KIcon(pm));
00077     }
00078 
00079     void syncActiveRect();
00080     void syncBorders();
00081     void animationUpdate(qreal progress);
00082 
00083     PushButton *q;
00084 
00085     FrameSvg *background;
00086     int animId;
00087     bool fadeIn;
00088     qreal opacity;
00089     QRectF activeRect;
00090 
00091     QString imagePath;
00092     QString absImagePath;
00093     Svg *svg;
00094 };
00095 
00096 void PushButtonPrivate::syncActiveRect()
00097 {
00098     background->setElementPrefix("normal");
00099 
00100     qreal left, top, right, bottom;
00101     background->getMargins(left, top, right, bottom);
00102 
00103     background->setElementPrefix("active");
00104     qreal activeLeft, activeTop, activeRight, activeBottom;
00105     background->getMargins(activeLeft, activeTop, activeRight, activeBottom);
00106 
00107     activeRect = QRectF(QPointF(0, 0), q->size());
00108     activeRect.adjust(left - activeLeft, top - activeTop,
00109                       -(right - activeRight), -(bottom - activeBottom));
00110 
00111     background->setElementPrefix("normal");
00112 }
00113 
00114 void PushButtonPrivate::syncBorders()
00115 {
00116     //set margins from the normal element
00117     qreal left, top, right, bottom;
00118 
00119     background->setElementPrefix("normal");
00120     background->getMargins(left, top, right, bottom);
00121     q->setContentsMargins(left, top, right, bottom);
00122 
00123     //calc the rect for the over effect
00124     syncActiveRect();
00125 }
00126 
00127 void PushButtonPrivate::animationUpdate(qreal progress)
00128 {
00129     if (progress == 1) {
00130         animId = -1;
00131         fadeIn = true;
00132     }
00133 
00134     opacity = fadeIn ? progress : 1 - progress;
00135 
00136     // explicit update
00137     q->update();
00138 }
00139 
00140 PushButton::PushButton(QGraphicsWidget *parent)
00141     : QGraphicsProxyWidget(parent),
00142       d(new PushButtonPrivate(this))
00143 {
00144     KPushButton *native = new KPushButton;
00145     connect(native, SIGNAL(clicked()), this, SIGNAL(clicked()));
00146     setWidget(native);
00147     native->setAttribute(Qt::WA_NoSystemBackground);
00148 
00149     d->background = new FrameSvg(this);
00150     d->background->setImagePath("widgets/button");
00151     d->background->setCacheAllRenderedFrames(true);
00152     d->background->setElementPrefix("normal");
00153     d->syncBorders();
00154     setAcceptHoverEvents(true);
00155     connect(Plasma::Theme::defaultTheme(), SIGNAL(themeChanged()), SLOT(syncBorders()));
00156 }
00157 
00158 PushButton::~PushButton()
00159 {
00160     delete d;
00161 }
00162 
00163 void PushButton::setText(const QString &text)
00164 {
00165     static_cast<KPushButton*>(widget())->setText(text);
00166 }
00167 
00168 QString PushButton::text() const
00169 {
00170     return static_cast<KPushButton*>(widget())->text();
00171 }
00172 
00173 void PushButton::setImage(const QString &path)
00174 {
00175     if (d->imagePath == path) {
00176         return;
00177     }
00178 
00179     delete d->svg;
00180     d->svg = 0;
00181     d->imagePath = path;
00182 
00183     bool absolutePath = !path.isEmpty() &&
00184                         #ifdef Q_WS_WIN
00185                             !QDir::isRelativePath(path)
00186                         #else
00187                             (path[0] == '/' || path.startsWith(":/"))
00188                         #endif
00189         ;
00190 
00191     if (absolutePath) {
00192         d->absImagePath = path;
00193     } else {
00194         //TODO: package support
00195         d->absImagePath = Theme::defaultTheme()->imagePath(path);
00196     }
00197 
00198     d->setPixmap(this);
00199 }
00200 
00201 QString PushButton::image() const
00202 {
00203     return d->imagePath;
00204 }
00205 
00206 void PushButton::setStyleSheet(const QString &stylesheet)
00207 {
00208     widget()->setStyleSheet(stylesheet);
00209 }
00210 
00211 QString PushButton::styleSheet()
00212 {
00213     return widget()->styleSheet();
00214 }
00215 
00216 KPushButton *PushButton::nativeWidget() const
00217 {
00218     return static_cast<KPushButton*>(widget());
00219 }
00220 
00221 void PushButton::resizeEvent(QGraphicsSceneResizeEvent *event)
00222 {
00223     d->setPixmap(this);
00224 
00225    if (d->background) {
00226         //resize all four panels
00227         d->background->setElementPrefix("pressed");
00228         d->background->resizeFrame(size());
00229         d->background->setElementPrefix("focus");
00230         d->background->resizeFrame(size());
00231 
00232         d->syncActiveRect();
00233 
00234         d->background->setElementPrefix("active");
00235         d->background->resizeFrame(d->activeRect.size());
00236 
00237         d->background->setElementPrefix("normal");
00238         d->background->resizeFrame(size());
00239    }
00240 
00241    QGraphicsProxyWidget::resizeEvent(event);
00242 }
00243 
00244 void PushButton::paint(QPainter *painter,
00245                        const QStyleOptionGraphicsItem *option,
00246                        QWidget *widget)
00247 {
00248     if (!styleSheet().isNull()) {
00249         QGraphicsProxyWidget::paint(painter, option, widget);
00250         return;
00251     }
00252 
00253     QPixmap bufferPixmap;
00254 
00255     //Normal button, pressed or not
00256     if (isEnabled()) {
00257         if (nativeWidget()->isDown()) {
00258             d->background->setElementPrefix("pressed");
00259         } else {
00260             d->background->setElementPrefix("normal");
00261         }
00262         if (d->animId == -1) {
00263             d->background->paintFrame(painter);
00264         }
00265     //flat or disabled
00266     } else if (!isEnabled() || nativeWidget()->isFlat()) {
00267         bufferPixmap = QPixmap(rect().size().toSize());
00268         bufferPixmap.fill(Qt::transparent);
00269 
00270         QPainter buffPainter(&bufferPixmap);
00271         d->background->paintFrame(&buffPainter);
00272         buffPainter.setCompositionMode(QPainter::CompositionMode_DestinationIn);
00273         buffPainter.fillRect(bufferPixmap.rect(), QColor(0, 0, 0, 128));
00274 
00275         painter->drawPixmap(0, 0, bufferPixmap);
00276     }
00277 
00278     //if is under mouse draw the animated glow overlay
00279     if (!nativeWidget()->isDown() && isEnabled() && acceptHoverEvents()) {
00280         if (d->animId != -1) {
00281             QPixmap normalPix = d->background->framePixmap();
00282             d->background->setElementPrefix("active");
00283             painter->drawPixmap(
00284                 d->activeRect.topLeft(),
00285                 PaintUtils::transition(d->background->framePixmap(), normalPix, 1 - d->opacity));
00286         } else if (isUnderMouse() || nativeWidget()->isDefault()) {
00287             d->background->setElementPrefix("active");
00288             d->background->paintFrame(painter, d->activeRect.topLeft());
00289         }
00290     }
00291 
00292     if (nativeWidget()->hasFocus()) {
00293         d->background->setElementPrefix("focus");
00294         d->background->paintFrame(painter);
00295     }
00296 
00297     painter->setPen(Plasma::Theme::defaultTheme()->color(Theme::ButtonTextColor));
00298 
00299     if (nativeWidget()->isDown()) {
00300         painter->translate(QPoint(1, 1));
00301     }
00302 
00303     QRectF rect = contentsRect();
00304 
00305     if (!nativeWidget()->icon().isNull()) {
00306         QPixmap iconPix = nativeWidget()->icon().pixmap(rect.height(), rect.height());
00307         if (!isEnabled()) {
00308             KIconEffect *effect = KIconLoader::global()->iconEffect();
00309             iconPix = effect->apply(iconPix, KIconLoader::Toolbar, KIconLoader::DisabledState);
00310         }
00311 
00312         if (option->direction == Qt::LeftToRight) {
00313             painter->drawPixmap(rect.topLeft(), iconPix);
00314             rect.adjust(rect.height(), 0, 0, 0);
00315         } else {
00316             painter->drawPixmap(rect.topRight() - QPoint(rect.height(), 0), iconPix);
00317             rect.adjust(0, 0, -rect.height(), 0);
00318         }
00319     }
00320 
00321     //if there is not enough room for the text make it to fade out
00322     QFontMetricsF fm(QApplication::font());
00323     if (rect.width() < fm.width(nativeWidget()->text())) {
00324         if (bufferPixmap.isNull()) {
00325             bufferPixmap = QPixmap(rect.size().toSize());
00326         }
00327         bufferPixmap.fill(Qt::transparent);
00328 
00329         QPainter p(&bufferPixmap);
00330         p.setPen(painter->pen());
00331         p.setFont(Plasma::Theme::defaultTheme()->font(Plasma::Theme::DefaultFont));
00332 
00333         // Create the alpha gradient for the fade out effect
00334         QLinearGradient alphaGradient(0, 0, 1, 0);
00335         alphaGradient.setCoordinateMode(QGradient::ObjectBoundingMode);
00336         if (option->direction == Qt::LeftToRight) {
00337             alphaGradient.setColorAt(0, QColor(0, 0, 0, 255));
00338             alphaGradient.setColorAt(1, QColor(0, 0, 0, 0));
00339             p.drawText(bufferPixmap.rect(), Qt::AlignLeft|Qt::AlignVCenter,
00340                        nativeWidget()->text());
00341         } else {
00342             alphaGradient.setColorAt(0, QColor(0, 0, 0, 0));
00343             alphaGradient.setColorAt(1, QColor(0, 0, 0, 255));
00344             p.drawText(bufferPixmap.rect(), Qt::AlignRight|Qt::AlignVCenter,
00345                        nativeWidget()->text());
00346         }
00347 
00348         p.setCompositionMode(QPainter::CompositionMode_DestinationIn);
00349         p.fillRect(bufferPixmap.rect(), alphaGradient);
00350 
00351         painter->drawPixmap(rect.topLeft(), bufferPixmap);
00352     } else {
00353         painter->setFont(Plasma::Theme::defaultTheme()->font(Plasma::Theme::DefaultFont));
00354         painter->drawText(rect, Qt::AlignCenter, nativeWidget()->text());
00355     }
00356 }
00357 
00358 void PushButton::hoverEnterEvent(QGraphicsSceneHoverEvent *event)
00359 {
00360     if (nativeWidget()->isDown()) {
00361         return;
00362     }
00363 
00364     const int FadeInDuration = 75;
00365 
00366     if (d->animId != -1) {
00367         Plasma::Animator::self()->stopCustomAnimation(d->animId);
00368     }
00369     d->animId = Plasma::Animator::self()->customAnimation(
00370         40 / (1000 / FadeInDuration), FadeInDuration,
00371         Plasma::Animator::LinearCurve, this, "animationUpdate");
00372 
00373     d->background->setElementPrefix("active");
00374 
00375     QGraphicsProxyWidget::hoverEnterEvent(event);
00376 }
00377 
00378 void PushButton::hoverLeaveEvent(QGraphicsSceneHoverEvent *event)
00379 {
00380     if (nativeWidget()->isDown()) {
00381         return;
00382     }
00383 
00384     const int FadeOutDuration = 150;
00385 
00386     if (d->animId != -1) {
00387         Plasma::Animator::self()->stopCustomAnimation(d->animId != -1);
00388     }
00389 
00390     d->fadeIn = false;
00391     d->animId = Plasma::Animator::self()->customAnimation(
00392         40 / (1000 / FadeOutDuration), FadeOutDuration,
00393         Plasma::Animator::LinearCurve, this, "animationUpdate");
00394 
00395     d->background->setElementPrefix("active");
00396 
00397     QGraphicsProxyWidget::hoverLeaveEvent(event);
00398 }
00399 
00400 } // namespace Plasma
00401 
00402 #include <pushbutton.moc>
00403 

Plasma

Skip menu "Plasma"
  • Main Page
  • Namespace List
  • Class Hierarchy
  • Alphabetical List
  • Class List
  • File List
  • Namespace Members
  • Class Members
  • Related Pages

kdelibs

Skip menu "kdelibs"
  • DNSSD
  • Interfaces
  •   KHexEdit
  •   KMediaPlayer
  •   KSpeech
  •   KTextEditor
  • Kate
  • kconf_update
  • KDE3Support
  •   KUnitTest
  • KDECore
  • KDED
  • KDEsu
  • KDEUI
  • KDocTools
  • KFile
  • KHTML
  • KImgIO
  • KInit
  • kio
  • KIOSlave
  • KJS
  •   KJS-API
  •   WTF
  • kjsembed
  • KNewStuff
  • KParts
  • Kross
  • KUtils
  • Nepomuk
  • Plasma
  • Solid
  • Sonnet
  • ThreadWeaver
Generated for kdelibs by doxygen 1.5.7
This website is maintained by Adriaan de Groot and Allen Winter.
KDE® and the K Desktop Environment® logo are registered trademarks of KDE e.V. | Legal