00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
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
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
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
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
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
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
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
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
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
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
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 }
00458
00459 #include <pushbutton.moc>
00460