00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020 #include "toolbutton.h"
00021
00022 #include <QStyleOptionGraphicsItem>
00023 #include <QPainter>
00024 #include <QDir>
00025 #include <QToolButton>
00026 #include <QApplication>
00027
00028 #include <kicon.h>
00029 #include <kiconeffect.h>
00030 #include <kmimetype.h>
00031 #include <kcolorutils.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 ToolButtonPrivate : public ActionWidgetInterface<ToolButton>
00044 {
00045 public:
00046 ToolButtonPrivate(ToolButton *toolButton)
00047 : ActionWidgetInterface<ToolButton>(toolButton),
00048 q(toolButton),
00049 background(0),
00050 animId(0),
00051 fadeIn(false),
00052 svg(0)
00053 {
00054 }
00055
00056 ~ToolButtonPrivate()
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 pm.fill(Qt::transparent);
00072
00073 if (mime->is("image/svg+xml") || mime->is("image/svg+xml-compressed")) {
00074 if (!svg || svg->imagePath() != absImagePath) {
00075 delete svg;
00076 svg = new Svg();
00077 svg->setImagePath(imagePath);
00078 QObject::connect(svg, SIGNAL(repaintNeeded()), q, SLOT(setPixmap()));
00079 }
00080
00081 QPainter p(&pm);
00082 svg->paint(&p, pm.rect());
00083 } else {
00084 delete svg;
00085 svg = 0;
00086 pm = QPixmap(absImagePath);
00087 }
00088
00089 static_cast<QToolButton*>(q->widget())->setIcon(KIcon(pm));
00090 }
00091
00092 void syncActiveRect();
00093 void syncBorders();
00094 void animationUpdate(qreal progress);
00095
00096 ToolButton *q;
00097
00098 FrameSvg *background;
00099 int animId;
00100 bool fadeIn;
00101 qreal opacity;
00102 QRectF activeRect;
00103
00104 QString imagePath;
00105 QString absImagePath;
00106 Svg *svg;
00107 };
00108
00109 void ToolButtonPrivate::syncActiveRect()
00110 {
00111 background->setElementPrefix("normal");
00112
00113 qreal left, top, right, bottom;
00114 background->getMargins(left, top, right, bottom);
00115
00116 background->setElementPrefix("active");
00117 qreal activeLeft, activeTop, activeRight, activeBottom;
00118 background->getMargins(activeLeft, activeTop, activeRight, activeBottom);
00119
00120 activeRect = QRectF(QPointF(0, 0), q->size());
00121 activeRect.adjust(left - activeLeft, top - activeTop,
00122 -(right - activeRight), -(bottom - activeBottom));
00123
00124 background->setElementPrefix("normal");
00125 }
00126
00127 void ToolButtonPrivate::syncBorders()
00128 {
00129
00130 qreal left, top, right, bottom;
00131
00132 background->setElementPrefix("normal");
00133 background->getMargins(left, top, right, bottom);
00134 q->setContentsMargins(left, top, right, bottom);
00135
00136
00137 syncActiveRect();
00138 }
00139
00140 void ToolButtonPrivate::animationUpdate(qreal progress)
00141 {
00142 if (progress == 1) {
00143 animId = 0;
00144 fadeIn = true;
00145 }
00146
00147 opacity = fadeIn ? progress : 1 - progress;
00148
00149
00150 q->update();
00151 }
00152
00153 ToolButton::ToolButton(QGraphicsWidget *parent)
00154 : QGraphicsProxyWidget(parent),
00155 d(new ToolButtonPrivate(this))
00156 {
00157 QToolButton *native = new QToolButton;
00158 connect(native, SIGNAL(clicked()), this, SIGNAL(clicked()));
00159 setWidget(native);
00160 native->setAttribute(Qt::WA_NoSystemBackground);
00161 native->setAutoRaise(true);
00162
00163 d->background = new FrameSvg(this);
00164 d->background->setImagePath("widgets/button");
00165 d->background->setCacheAllRenderedFrames(true);
00166 d->background->setElementPrefix("normal");
00167 d->syncBorders();
00168 setAcceptHoverEvents(true);
00169 connect(Plasma::Theme::defaultTheme(), SIGNAL(themeChanged()), SLOT(syncBorders()));
00170 }
00171
00172 ToolButton::~ToolButton()
00173 {
00174 delete d;
00175 }
00176
00177 void ToolButton::setAction(QAction *action)
00178 {
00179 d->setAction(action);
00180 }
00181
00182 QAction *ToolButton::action() const
00183 {
00184 return d->action;
00185 }
00186
00187 void ToolButton::setAutoRaise(bool raise)
00188 {
00189 nativeWidget()->setAutoRaise(raise);
00190 }
00191
00192 bool ToolButton::autoRaise() const
00193 {
00194 return nativeWidget()->autoRaise();
00195 }
00196
00197 void ToolButton::setText(const QString &text)
00198 {
00199 static_cast<QToolButton*>(widget())->setText(text);
00200 }
00201
00202 QString ToolButton::text() const
00203 {
00204 return static_cast<QToolButton*>(widget())->text();
00205 }
00206
00207 void ToolButton::setImage(const QString &path)
00208 {
00209 if (d->imagePath == path) {
00210 return;
00211 }
00212
00213 delete d->svg;
00214 d->svg = 0;
00215 d->imagePath = path;
00216
00217 bool absolutePath = !path.isEmpty() &&
00218 #ifdef Q_WS_WIN
00219 !QDir::isRelativePath(path)
00220 #else
00221 (path[0] == '/' || path.startsWith(":/"))
00222 #endif
00223 ;
00224
00225 if (absolutePath) {
00226 d->absImagePath = path;
00227 } else {
00228
00229 d->absImagePath = Theme::defaultTheme()->imagePath(path);
00230 }
00231
00232 d->setPixmap();
00233 }
00234
00235 void ToolButton::setIcon(const QIcon &icon)
00236 {
00237 nativeWidget()->setIcon(icon);
00238 }
00239
00240 QIcon ToolButton::icon() const
00241 {
00242 return nativeWidget()->icon();
00243 }
00244
00245 QString ToolButton::image() const
00246 {
00247 return d->imagePath;
00248 }
00249
00250 void ToolButton::setStyleSheet(const QString &stylesheet)
00251 {
00252 widget()->setStyleSheet(stylesheet);
00253 }
00254
00255 QString ToolButton::styleSheet()
00256 {
00257 return widget()->styleSheet();
00258 }
00259
00260 QToolButton *ToolButton::nativeWidget() const
00261 {
00262 return static_cast<QToolButton*>(widget());
00263 }
00264
00265 void ToolButton::resizeEvent(QGraphicsSceneResizeEvent *event)
00266 {
00267 d->setPixmap();
00268
00269 if (d->background) {
00270
00271 d->background->setElementPrefix("pressed");
00272 d->background->resizeFrame(size());
00273 d->background->setElementPrefix("focus");
00274 d->background->resizeFrame(size());
00275
00276 d->syncActiveRect();
00277
00278 d->background->setElementPrefix("active");
00279 d->background->resizeFrame(d->activeRect.size());
00280
00281 d->background->setElementPrefix("normal");
00282 d->background->resizeFrame(size());
00283 }
00284
00285 QGraphicsProxyWidget::resizeEvent(event);
00286 }
00287
00288 void ToolButton::paint(QPainter *painter,
00289 const QStyleOptionGraphicsItem *option,
00290 QWidget *widget)
00291 {
00292 if (!styleSheet().isNull()) {
00293 QGraphicsProxyWidget::paint(painter, option, widget);
00294 return;
00295 }
00296
00297 QToolButton *button = nativeWidget();
00298
00299 QStyleOptionToolButton buttonOpt;
00300 buttonOpt.initFrom(button);
00301 buttonOpt.icon = button->icon();
00302 buttonOpt.text = button->text();
00303 buttonOpt.iconSize = button->iconSize();
00304 buttonOpt.toolButtonStyle = button->toolButtonStyle();
00305
00306
00307 if (button->isEnabled() && (d->animId || !button->autoRaise() || (buttonOpt.state & QStyle::State_MouseOver) || (buttonOpt.state & QStyle::State_On))) {
00308 if (button->isDown() || (buttonOpt.state & QStyle::State_On)) {
00309 d->background->setElementPrefix("pressed");
00310 } else {
00311 d->background->setElementPrefix("normal");
00312 }
00313 d->background->resizeFrame(size());
00314
00315 if (d->animId) {
00316 QPixmap buffer = d->background->framePixmap();
00317
00318 QPainter bufferPainter(&buffer);
00319 bufferPainter.setCompositionMode(QPainter::CompositionMode_DestinationIn);
00320 QColor alphaColor(Qt::black);
00321 alphaColor.setAlphaF(qMin(qreal(0.95), d->opacity));
00322 bufferPainter.fillRect(buffer.rect(), alphaColor);
00323 bufferPainter.end();
00324
00325 painter->drawPixmap(QPoint(0,0), buffer);
00326
00327 buttonOpt.palette.setColor(QPalette::ButtonText, KColorUtils::mix(Plasma::Theme::defaultTheme()->color(Plasma::Theme::ButtonTextColor), Plasma::Theme::defaultTheme()->color(Plasma::Theme::TextColor), 1-d->opacity));
00328 } else {
00329 d->background->paintFrame(painter);
00330 buttonOpt.palette.setColor(QPalette::ButtonText, Plasma::Theme::defaultTheme()->color(Plasma::Theme::ButtonTextColor));
00331 }
00332
00333 } else {
00334 buttonOpt.palette.setColor(QPalette::ButtonText, Plasma::Theme::defaultTheme()->color(Plasma::Theme::TextColor));
00335 }
00336
00337 painter->setFont(Plasma::Theme::defaultTheme()->font(Plasma::Theme::DefaultFont));
00338 button->style()->drawControl(QStyle::CE_ToolButtonLabel, &buttonOpt, painter, button);
00339 }
00340
00341 void ToolButton::hoverEnterEvent(QGraphicsSceneHoverEvent *event)
00342 {
00343 if (nativeWidget()->isDown() || !nativeWidget()->autoRaise()) {
00344 return;
00345 }
00346
00347 const int FadeInDuration = 75;
00348
00349 if (d->animId) {
00350 Plasma::Animator::self()->stopCustomAnimation(d->animId);
00351 }
00352 d->animId = Plasma::Animator::self()->customAnimation(
00353 40 / (1000 / FadeInDuration), FadeInDuration,
00354 Plasma::Animator::LinearCurve, this, "animationUpdate");
00355
00356 d->background->setElementPrefix("active");
00357
00358 QGraphicsProxyWidget::hoverEnterEvent(event);
00359 }
00360
00361 void ToolButton::hoverLeaveEvent(QGraphicsSceneHoverEvent *event)
00362 {
00363 if (nativeWidget()->isDown() || !nativeWidget()->autoRaise()) {
00364 return;
00365 }
00366
00367 const int FadeOutDuration = 150;
00368
00369 if (d->animId) {
00370 Plasma::Animator::self()->stopCustomAnimation(d->animId);
00371 }
00372
00373 d->fadeIn = false;
00374 d->animId = Plasma::Animator::self()->customAnimation(
00375 40 / (1000 / FadeOutDuration), FadeOutDuration,
00376 Plasma::Animator::LinearCurve, this, "animationUpdate");
00377
00378 d->background->setElementPrefix("active");
00379
00380 QGraphicsProxyWidget::hoverLeaveEvent(event);
00381 }
00382
00383 }
00384
00385 #include <toolbutton.moc>
00386