• Skip to content
  • Skip to link menu
KDE 4.3 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 #include "private/actionwidgetinterface_p.h"
00039 
00040 namespace Plasma
00041 {
00042 
00043 class PushButtonPrivate : public ActionWidgetInterface<PushButton>
00044 {
00045 public:
00046     PushButtonPrivate(PushButton *pushButton)
00047         : ActionWidgetInterface<PushButton>(pushButton),
00048           q(pushButton),
00049           background(0),
00050           animId(-1),
00051           fadeIn(false),
00052           svg(0)
00053     {
00054     }
00055 
00056     ~PushButtonPrivate()
00057     {
00058         delete svg;
00059     }
00060 
00061     void setPixmap()
00062     {
00063         if (imagePath.isEmpty()) {
00064             delete svg;
00065             svg = 0;
00066             return;
00067         }
00068 
00069         KMimeType::Ptr mime = KMimeType::findByPath(absImagePath);
00070         QPixmap pm(q->size().toSize());
00071 
00072         if (mime->is("image/svg+xml") || mime->is("image/svg+xml-compressed")) {
00073             if (!svg || svg->imagePath() != imagePath) {
00074                 delete svg;
00075                 svg = new Svg();
00076                 svg->setImagePath(imagePath);
00077                 QObject::connect(svg, SIGNAL(repaintNeeded()), q, SLOT(setPixmap()));
00078             }
00079 
00080             QPainter p(&pm);
00081             svg->paint(&p, pm.rect());
00082         } else {
00083             delete svg;
00084             svg = 0;
00085             pm = QPixmap(absImagePath);
00086         }
00087 
00088         static_cast<KPushButton*>(q->widget())->setIcon(KIcon(pm));
00089     }
00090 
00091     void syncActiveRect();
00092     void syncBorders();
00093     void animationUpdate(qreal progress);
00094 
00095     PushButton *q;
00096 
00097     FrameSvg *background;
00098     int animId;
00099     bool fadeIn;
00100     qreal opacity;
00101     QRectF activeRect;
00102 
00103     QString imagePath;
00104     QString absImagePath;
00105     Svg *svg;
00106 };
00107 
00108 void PushButtonPrivate::syncActiveRect()
00109 {
00110     background->setElementPrefix("normal");
00111 
00112     qreal left, top, right, bottom;
00113     background->getMargins(left, top, right, bottom);
00114 
00115     background->setElementPrefix("active");
00116     qreal activeLeft, activeTop, activeRight, activeBottom;
00117     background->getMargins(activeLeft, activeTop, activeRight, activeBottom);
00118 
00119     activeRect = QRectF(QPointF(0, 0), q->size());
00120     activeRect.adjust(left - activeLeft, top - activeTop,
00121                       -(right - activeRight), -(bottom - activeBottom));
00122 
00123     background->setElementPrefix("normal");
00124 }
00125 
00126 void PushButtonPrivate::syncBorders()
00127 {
00128     //set margins from the normal element
00129     qreal left, top, right, bottom;
00130 
00131     background->setElementPrefix("normal");
00132     background->getMargins(left, top, right, bottom);
00133     q->setContentsMargins(left, top, right, bottom);
00134 
00135     //calc the rect for the over effect
00136     syncActiveRect();
00137 }
00138 
00139 void PushButtonPrivate::animationUpdate(qreal progress)
00140 {
00141     if (progress == 1) {
00142         animId = -1;
00143         fadeIn = true;
00144     }
00145 
00146     opacity = fadeIn ? progress : 1 - progress;
00147 
00148     // explicit update
00149     q->update();
00150 }
00151 
00152 PushButton::PushButton(QGraphicsWidget *parent)
00153     : QGraphicsProxyWidget(parent),
00154       d(new PushButtonPrivate(this))
00155 {
00156     KPushButton *native = new KPushButton;
00157     connect(native, SIGNAL(clicked()), this, SIGNAL(clicked()));
00158     connect(native, SIGNAL(toggled(bool)), this, SIGNAL(toggled(bool)));
00159     setWidget(native);
00160     native->setAttribute(Qt::WA_NoSystemBackground);
00161 
00162     setSizePolicy(QSizePolicy::Minimum, QSizePolicy::Minimum);
00163 
00164     d->background = new FrameSvg(this);
00165     d->background->setImagePath("widgets/button");
00166     d->background->setCacheAllRenderedFrames(true);
00167     d->background->setElementPrefix("normal");
00168     d->syncBorders();
00169     setAcceptHoverEvents(true);
00170     connect(Plasma::Theme::defaultTheme(), SIGNAL(themeChanged()), SLOT(syncBorders()));
00171 }
00172 
00173 PushButton::~PushButton()
00174 {
00175     delete d;
00176 }
00177 
00178 void PushButton::setText(const QString &text)
00179 {
00180     static_cast<KPushButton*>(widget())->setText(text);
00181 }
00182 
00183 QString PushButton::text() const
00184 {
00185     return static_cast<KPushButton*>(widget())->text();
00186 }
00187 
00188 void PushButton::setImage(const QString &path)
00189 {
00190     if (d->imagePath == path) {
00191         return;
00192     }
00193 
00194     delete d->svg;
00195     d->svg = 0;
00196     d->imagePath = path;
00197 
00198     bool absolutePath = !path.isEmpty() &&
00199                         #ifdef Q_WS_WIN
00200                             !QDir::isRelativePath(path)
00201                         #else
00202                             (path[0] == '/' || path.startsWith(":/"))
00203                         #endif
00204         ;
00205 
00206     if (absolutePath) {
00207         d->absImagePath = path;
00208     } else {
00209         //TODO: package support
00210         d->absImagePath = Theme::defaultTheme()->imagePath(path);
00211     }
00212 
00213     d->setPixmap();
00214 }
00215 
00216 QString PushButton::image() const
00217 {
00218     return d->imagePath;
00219 }
00220 
00221 void PushButton::setStyleSheet(const QString &stylesheet)
00222 {
00223     widget()->setStyleSheet(stylesheet);
00224 }
00225 
00226 QString PushButton::styleSheet()
00227 {
00228     return widget()->styleSheet();
00229 }
00230 
00231 void PushButton::setAction(QAction *action)
00232 {
00233     d->setAction(action);
00234 }
00235 
00236 QAction *PushButton::action() const
00237 {
00238     return d->action;
00239 }
00240 
00241 void PushButton::setIcon(const QIcon &icon)
00242 {
00243     nativeWidget()->setIcon(icon);
00244 }
00245 
00246 QIcon PushButton::icon() const
00247 {
00248     return nativeWidget()->icon();
00249 }
00250 
00251 void PushButton::setCheckable(bool checkable)
00252 {
00253     nativeWidget()->setCheckable(checkable);
00254 }
00255 
00256 void PushButton::setChecked(bool checked)
00257 {
00258     nativeWidget()->setChecked(checked);
00259 }
00260 
00261 bool PushButton::isChecked() const
00262 {
00263     return nativeWidget()->isChecked();
00264 }
00265 
00266 KPushButton *PushButton::nativeWidget() const
00267 {
00268     return static_cast<KPushButton*>(widget());
00269 }
00270 
00271 void PushButton::resizeEvent(QGraphicsSceneResizeEvent *event)
00272 {
00273     d->setPixmap();
00274 
00275    if (d->background) {
00276         //resize all four panels
00277         d->background->setElementPrefix("pressed");
00278         d->background->resizeFrame(size());
00279         d->background->setElementPrefix("focus");
00280         d->background->resizeFrame(size());
00281 
00282         d->syncActiveRect();
00283 
00284         d->background->setElementPrefix("active");
00285         d->background->resizeFrame(d->activeRect.size());
00286 
00287         d->background->setElementPrefix("normal");
00288         d->background->resizeFrame(size());
00289    }
00290 
00291    QGraphicsProxyWidget::resizeEvent(event);
00292 }
00293 
00294 void PushButton::paint(QPainter *painter,
00295                        const QStyleOptionGraphicsItem *option,
00296                        QWidget *widget)
00297 {
00298     if (!styleSheet().isNull() || Theme::defaultTheme()->useNativeWidgetStyle()) {
00299         QGraphicsProxyWidget::paint(painter, option, widget);
00300         return;
00301     }
00302 
00303     QPixmap bufferPixmap;
00304 
00305     //Normal button, pressed or not
00306     if (isEnabled()) {
00307         if (nativeWidget()->isDown() || nativeWidget()->isChecked()) {
00308             d->background->setElementPrefix("pressed");
00309         } else {
00310             d->background->setElementPrefix("normal");
00311         }
00312         if (d->animId == -1) {
00313             d->background->paintFrame(painter);
00314         }
00315     //flat or disabled
00316     } else if (!isEnabled() || nativeWidget()->isFlat()) {
00317         bufferPixmap = QPixmap(rect().size().toSize());
00318         bufferPixmap.fill(Qt::transparent);
00319 
00320         QPainter buffPainter(&bufferPixmap);
00321         d->background->paintFrame(&buffPainter);
00322         buffPainter.setCompositionMode(QPainter::CompositionMode_DestinationIn);
00323         buffPainter.fillRect(bufferPixmap.rect(), QColor(0, 0, 0, 128));
00324 
00325         painter->drawPixmap(0, 0, bufferPixmap);
00326     }
00327 
00328     //if is under mouse draw the animated glow overlay
00329     if (!nativeWidget()->isDown() && !nativeWidget()->isChecked() && isEnabled() && acceptHoverEvents()) {
00330         if (d->animId != -1) {
00331             QPixmap normalPix = d->background->framePixmap();
00332             d->background->setElementPrefix("active");
00333             painter->drawPixmap(
00334                 d->activeRect.topLeft(),
00335                 PaintUtils::transition(d->background->framePixmap(), normalPix, 1 - d->opacity));
00336         } else if (isUnderMouse() || nativeWidget()->isDefault()) {
00337             d->background->setElementPrefix("active");
00338             d->background->paintFrame(painter, d->activeRect.topLeft());
00339         }
00340     }
00341 
00342     if (nativeWidget()->hasFocus()) {
00343         d->background->setElementPrefix("focus");
00344         d->background->paintFrame(painter);
00345     }
00346 
00347     painter->setPen(Plasma::Theme::defaultTheme()->color(Theme::ButtonTextColor));
00348 
00349     if (nativeWidget()->isDown()) {
00350         painter->translate(QPoint(1, 1));
00351     }
00352 
00353     QRectF rect = contentsRect();
00354 
00355     if (!nativeWidget()->icon().isNull()) {
00356         const qreal iconSize = qMin(rect.width(), rect.height());
00357         QPixmap iconPix = nativeWidget()->icon().pixmap(iconSize);
00358         if (!isEnabled()) {
00359             KIconEffect *effect = KIconLoader::global()->iconEffect();
00360             iconPix = effect->apply(iconPix, KIconLoader::Toolbar, KIconLoader::DisabledState);
00361         }
00362 
00363         QRect pixmapRect;
00364         if (nativeWidget()->text().isEmpty()) {
00365             pixmapRect = nativeWidget()->style()->alignedRect(option->direction, Qt::AlignCenter, iconPix.size(), rect.toRect());
00366         } else {
00367             pixmapRect = nativeWidget()->style()->alignedRect(option->direction, Qt::AlignLeft|Qt::AlignVCenter, iconPix.size(), rect.toRect());
00368         }
00369         painter->drawPixmap(pixmapRect.topLeft(), iconPix);
00370 
00371         if (option->direction == Qt::LeftToRight) {
00372             rect.adjust(rect.height(), 0, 0, 0);
00373         } else {
00374             rect.adjust(0, 0, -rect.height(), 0);
00375         }
00376     }
00377 
00378     //if there is not enough room for the text make it to fade out
00379     QFontMetricsF fm(QApplication::font());
00380     if (rect.width() < fm.width(nativeWidget()->text())) {
00381         if (bufferPixmap.isNull()) {
00382             bufferPixmap = QPixmap(rect.size().toSize());
00383         }
00384         bufferPixmap.fill(Qt::transparent);
00385 
00386         QPainter p(&bufferPixmap);
00387         p.setPen(painter->pen());
00388         p.setFont(Plasma::Theme::defaultTheme()->font(Plasma::Theme::DefaultFont));
00389 
00390         // Create the alpha gradient for the fade out effect
00391         QLinearGradient alphaGradient(0, 0, 1, 0);
00392         alphaGradient.setCoordinateMode(QGradient::ObjectBoundingMode);
00393         if (option->direction == Qt::LeftToRight) {
00394             alphaGradient.setColorAt(0, QColor(0, 0, 0, 255));
00395             alphaGradient.setColorAt(1, QColor(0, 0, 0, 0));
00396             p.drawText(bufferPixmap.rect(), Qt::AlignLeft|Qt::AlignVCenter,
00397                        nativeWidget()->text());
00398         } else {
00399             alphaGradient.setColorAt(0, QColor(0, 0, 0, 0));
00400             alphaGradient.setColorAt(1, QColor(0, 0, 0, 255));
00401             p.drawText(bufferPixmap.rect(), Qt::AlignRight|Qt::AlignVCenter,
00402                        nativeWidget()->text());
00403         }
00404 
00405         p.setCompositionMode(QPainter::CompositionMode_DestinationIn);
00406         p.fillRect(bufferPixmap.rect(), alphaGradient);
00407 
00408         painter->drawPixmap(rect.topLeft(), bufferPixmap);
00409     } else {
00410         painter->setFont(Plasma::Theme::defaultTheme()->font(Plasma::Theme::DefaultFont));
00411         painter->drawText(rect, Qt::AlignCenter, nativeWidget()->text());
00412     }
00413 }
00414 
00415 void PushButton::hoverEnterEvent(QGraphicsSceneHoverEvent *event)
00416 {
00417     if (nativeWidget()->isDown()) {
00418         return;
00419     }
00420 
00421     const int FadeInDuration = 75;
00422 
00423     if (d->animId != -1) {
00424         Plasma::Animator::self()->stopCustomAnimation(d->animId);
00425     }
00426     d->animId = Plasma::Animator::self()->customAnimation(
00427         40 / (1000 / FadeInDuration), FadeInDuration,
00428         Plasma::Animator::LinearCurve, this, "animationUpdate");
00429 
00430     d->background->setElementPrefix("active");
00431 
00432     QGraphicsProxyWidget::hoverEnterEvent(event);
00433 }
00434 
00435 void PushButton::hoverLeaveEvent(QGraphicsSceneHoverEvent *event)
00436 {
00437     if (nativeWidget()->isDown()) {
00438         return;
00439     }
00440 
00441     const int FadeOutDuration = 150;
00442 
00443     if (d->animId != -1) {
00444         Plasma::Animator::self()->stopCustomAnimation(d->animId != -1);
00445     }
00446 
00447     d->fadeIn = false;
00448     d->animId = Plasma::Animator::self()->customAnimation(
00449         40 / (1000 / FadeOutDuration), FadeOutDuration,
00450         Plasma::Animator::LinearCurve, this, "animationUpdate");
00451 
00452     d->background->setElementPrefix("active");
00453 
00454     QGraphicsProxyWidget::hoverLeaveEvent(event);
00455 }
00456 
00457 } // namespace Plasma
00458 
00459 #include <pushbutton.moc>
00460 

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
  • KPty
  • Kross
  • KUtils
  • Nepomuk
  • Plasma
  • Solid
  • Sonnet
  • ThreadWeaver
Generated for kdelibs by doxygen 1.6.1
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