Plasma
toolbutton.cpp
Go to the documentation of this file.
00001 /* 00002 * Copyright 2008 Marco Martin <notmart@gmail.com> 00003 * 00004 * This program is free software; you can redistribute it and/or modify 00005 * it under the terms of the GNU Library General Public License as 00006 * published by the Free Software Foundation; either version 2, or 00007 * (at your option) any later version. 00008 * 00009 * This program is distributed in the hope that it will be useful, 00010 * but WITHOUT ANY WARRANTY; without even the implied warranty of 00011 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 00012 * GNU General Public License for more details 00013 * 00014 * You should have received a copy of the GNU Library General Public 00015 * License along with this program; if not, write to the 00016 * Free Software Foundation, Inc., 00017 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. 00018 */ 00019 00020 #include "toolbutton.h" 00021 00022 #include <QDir> 00023 #include <QPainter> 00024 #include <QPropertyAnimation> 00025 #include <QStyleOptionGraphicsItem> 00026 #include <QToolButton> 00027 00028 #include <kcolorutils.h> 00029 #include <kicon.h> 00030 #include <kiconeffect.h> 00031 #include <kmimetype.h> 00032 00033 #include "animator.h" 00034 #include "framesvg.h" 00035 #include "paintutils.h" 00036 #include "private/actionwidgetinterface_p.h" 00037 #include "private/themedwidgetinterface_p.h" 00038 #include "theme.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 background(0), 00049 svg(0), 00050 underMouse(false) 00051 { 00052 } 00053 00054 ~ToolButtonPrivate() 00055 { 00056 delete svg; 00057 } 00058 00059 void setPixmap() 00060 { 00061 if (imagePath.isEmpty()) { 00062 delete svg; 00063 svg = 0; 00064 return; 00065 } 00066 00067 KMimeType::Ptr mime = KMimeType::findByPath(absImagePath); 00068 QPixmap pm; 00069 00070 if (mime->is("image/svg+xml") || mime->is("image/svg+xml-compressed")) { 00071 if (!svg || svg->imagePath() != absImagePath) { 00072 delete svg; 00073 svg = new Svg(); 00074 svg->setImagePath(imagePath); 00075 QObject::connect(svg, SIGNAL(repaintNeeded()), q, SLOT(setPixmap())); 00076 if (!svgElement.isNull()) { 00077 svg->setContainsMultipleImages(true); 00078 } 00079 } 00080 00081 //QPainter p(&pm); 00082 if (!svgElement.isNull() && svg->hasElement(svgElement)) { 00083 QSizeF elementSize = svg->elementSize(svgElement); 00084 float scale = pm.width() / qMax(elementSize.width(), elementSize.height()); 00085 00086 svg->resize(svg->size() * scale); 00087 pm = svg->pixmap(svgElement); 00088 } else { 00089 svg->resize(pm.size()); 00090 pm = svg->pixmap(); 00091 } 00092 } else { 00093 delete svg; 00094 svg = 0; 00095 pm = QPixmap(absImagePath); 00096 } 00097 00098 static_cast<QToolButton*>(q->widget())->setIcon(KIcon(pm)); 00099 } 00100 00101 void syncActiveRect(); 00102 void syncBorders(); 00103 void animationUpdate(qreal progress); 00104 00105 FrameSvg *background; 00106 QPropertyAnimation *animation; 00107 qreal opacity; 00108 QRectF activeRect; 00109 00110 QString imagePath; 00111 QString absImagePath; 00112 Svg *svg; 00113 QString svgElement; 00114 bool underMouse; 00115 }; 00116 00117 void ToolButtonPrivate::syncActiveRect() 00118 { 00119 background->setElementPrefix("normal"); 00120 00121 qreal left, top, right, bottom; 00122 background->getMargins(left, top, right, bottom); 00123 00124 background->setElementPrefix("active"); 00125 qreal activeLeft, activeTop, activeRight, activeBottom; 00126 background->getMargins(activeLeft, activeTop, activeRight, activeBottom); 00127 00128 activeRect = QRectF(QPointF(0, 0), q->size()); 00129 activeRect.adjust(left - activeLeft, top - activeTop, 00130 -(right - activeRight), -(bottom - activeBottom)); 00131 00132 background->setElementPrefix("normal"); 00133 } 00134 00135 void ToolButtonPrivate::syncBorders() 00136 { 00137 //set margins from the normal element 00138 qreal left, top, right, bottom; 00139 00140 background->setElementPrefix("normal"); 00141 background->getMargins(left, top, right, bottom); 00142 q->setContentsMargins(left, top, right, bottom); 00143 00144 //calc the rect for the over effect 00145 syncActiveRect(); 00146 } 00147 00148 void ToolButtonPrivate::animationUpdate(qreal progress) 00149 { 00150 opacity = progress; 00151 00152 // explicit update 00153 q->update(); 00154 } 00155 00156 ToolButton::ToolButton(QGraphicsWidget *parent) 00157 : QGraphicsProxyWidget(parent), 00158 d(new ToolButtonPrivate(this)) 00159 { 00160 d->background = new FrameSvg(this); 00161 d->background->setImagePath("widgets/button"); 00162 d->background->setCacheAllRenderedFrames(true); 00163 d->background->setElementPrefix("normal"); 00164 00165 QToolButton *native = new QToolButton; 00166 connect(native, SIGNAL(clicked()), this, SIGNAL(clicked())); 00167 connect(native, SIGNAL(pressed()), this, SIGNAL(pressed())); 00168 connect(native, SIGNAL(released()), this, SIGNAL(released())); 00169 setWidget(native); 00170 native->setWindowIcon(QIcon()); 00171 native->setAttribute(Qt::WA_NoSystemBackground); 00172 native->setAutoRaise(true); 00173 00174 d->syncBorders(); 00175 setAcceptHoverEvents(true); 00176 connect(d->background, SIGNAL(repaintNeeded()), SLOT(syncBorders())); 00177 00178 d->animation = new QPropertyAnimation(this, "animationUpdate"); 00179 d->animation->setStartValue(0); 00180 d->animation->setEndValue(1); 00181 00182 d->initTheming(); 00183 } 00184 00185 ToolButton::~ToolButton() 00186 { 00187 delete d->animation; 00188 delete d; 00189 } 00190 00191 void ToolButton::setAnimationUpdate(qreal progress) 00192 { 00193 d->animationUpdate(progress); 00194 } 00195 00196 qreal ToolButton::animationUpdate() const 00197 { 00198 return d->opacity; 00199 } 00200 00201 void ToolButton::setAction(QAction *action) 00202 { 00203 d->setAction(action); 00204 } 00205 00206 QAction *ToolButton::action() const 00207 { 00208 return d->action; 00209 } 00210 00211 void ToolButton::setAutoRaise(bool raise) 00212 { 00213 nativeWidget()->setAutoRaise(raise); 00214 } 00215 00216 bool ToolButton::autoRaise() const 00217 { 00218 return nativeWidget()->autoRaise(); 00219 } 00220 00221 void ToolButton::setText(const QString &text) 00222 { 00223 static_cast<QToolButton*>(widget())->setText(text); 00224 updateGeometry(); 00225 } 00226 00227 QString ToolButton::text() const 00228 { 00229 return static_cast<QToolButton*>(widget())->text(); 00230 } 00231 00232 void ToolButton::setImage(const QString &path) 00233 { 00234 if (d->imagePath == path) { 00235 return; 00236 } 00237 00238 delete d->svg; 00239 d->svg = 0; 00240 d->imagePath = path; 00241 00242 bool absolutePath = !path.isEmpty() && 00243 #ifdef Q_WS_WIN 00244 !QDir::isRelativePath(path) 00245 #else 00246 (path[0] == '/' || path.startsWith(QLatin1String(":/"))) 00247 #endif 00248 ; 00249 00250 if (absolutePath) { 00251 d->absImagePath = path; 00252 } else { 00253 //TODO: package support 00254 d->absImagePath = Theme::defaultTheme()->imagePath(path); 00255 } 00256 00257 d->setPixmap(); 00258 } 00259 00260 void ToolButton::setImage(const QString &path, const QString &elementid) 00261 { 00262 d->svgElement = elementid; 00263 setImage(path); 00264 } 00265 00266 void ToolButton::setIcon(const QIcon &icon) 00267 { 00268 nativeWidget()->setIcon(icon); 00269 } 00270 00271 QIcon ToolButton::icon() const 00272 { 00273 return nativeWidget()->icon(); 00274 } 00275 00276 QString ToolButton::image() const 00277 { 00278 return d->imagePath; 00279 } 00280 00281 void ToolButton::setDown(bool down) 00282 { 00283 nativeWidget()->setDown(down); 00284 } 00285 00286 bool ToolButton::isDown() const 00287 { 00288 return nativeWidget()->isDown(); 00289 } 00290 00291 void ToolButton::setStyleSheet(const QString &stylesheet) 00292 { 00293 widget()->setStyleSheet(stylesheet); 00294 } 00295 00296 QString ToolButton::styleSheet() 00297 { 00298 return widget()->styleSheet(); 00299 } 00300 00301 QToolButton *ToolButton::nativeWidget() const 00302 { 00303 return static_cast<QToolButton*>(widget()); 00304 } 00305 00306 void ToolButton::resizeEvent(QGraphicsSceneResizeEvent *event) 00307 { 00308 d->setPixmap(); 00309 00310 if (d->background) { 00311 //resize all four panels 00312 d->background->setElementPrefix("pressed"); 00313 d->background->resizeFrame(size()); 00314 d->background->setElementPrefix("focus"); 00315 d->background->resizeFrame(size()); 00316 00317 d->syncActiveRect(); 00318 00319 d->background->setElementPrefix("active"); 00320 d->background->resizeFrame(d->activeRect.size()); 00321 00322 d->background->setElementPrefix("normal"); 00323 d->background->resizeFrame(size()); 00324 } 00325 00326 QGraphicsProxyWidget::resizeEvent(event); 00327 } 00328 00329 void ToolButton::paint(QPainter *painter, 00330 const QStyleOptionGraphicsItem *option, 00331 QWidget *widget) 00332 { 00333 if (!styleSheet().isNull() || Theme::defaultTheme()->useNativeWidgetStyle()) { 00334 QGraphicsProxyWidget::paint(painter, option, widget); 00335 return; 00336 } 00337 00338 QToolButton *button = nativeWidget(); 00339 00340 QStyleOptionToolButton buttonOpt; 00341 buttonOpt.initFrom(button); 00342 buttonOpt.icon = button->icon(); 00343 buttonOpt.text = button->text(); 00344 buttonOpt.iconSize = button->iconSize(); 00345 buttonOpt.toolButtonStyle = button->toolButtonStyle(); 00346 00347 bool animationState = (d->animation->state() == QAbstractAnimation::Running)? \ 00348 1:0; 00349 if (button->isEnabled() && (animationState || !button->autoRaise() || d->underMouse || (buttonOpt.state & QStyle::State_On) || button->isChecked() || button->isDown())) { 00350 if (button->isDown() || (buttonOpt.state & QStyle::State_On) || button->isChecked()) { 00351 d->background->setElementPrefix("pressed"); 00352 } else { 00353 d->background->setElementPrefix("normal"); 00354 } 00355 d->background->resizeFrame(size()); 00356 00357 if (animationState) { 00358 QPixmap buffer = d->background->framePixmap(); 00359 00360 QPainter bufferPainter(&buffer); 00361 bufferPainter.setCompositionMode(QPainter::CompositionMode_DestinationIn); 00362 QColor alphaColor(Qt::black); 00363 alphaColor.setAlphaF(qMin(qreal(0.95), d->opacity)); 00364 bufferPainter.fillRect(buffer.rect(), alphaColor); 00365 bufferPainter.end(); 00366 00367 painter->drawPixmap(QPoint(0,0), buffer); 00368 00369 buttonOpt.palette.setColor(QPalette::ButtonText, KColorUtils::mix(Plasma::Theme::defaultTheme()->color(Plasma::Theme::ButtonTextColor), Plasma::Theme::defaultTheme()->color(Plasma::Theme::TextColor), 1-d->opacity)); 00370 } else { 00371 d->background->paintFrame(painter); 00372 buttonOpt.palette.setColor(QPalette::ButtonText, Plasma::Theme::defaultTheme()->color(Plasma::Theme::ButtonTextColor)); 00373 } 00374 00375 } else { 00376 buttonOpt.palette.setColor(QPalette::ButtonText, Plasma::Theme::defaultTheme()->color(Plasma::Theme::TextColor)); 00377 } 00378 00379 buttonOpt.font = font(); 00380 00381 painter->setFont(buttonOpt.font); 00382 button->style()->drawControl(QStyle::CE_ToolButtonLabel, &buttonOpt, painter, button); 00383 } 00384 00385 void ToolButton::hoverEnterEvent(QGraphicsSceneHoverEvent *event) 00386 { 00387 d->underMouse = true; 00388 if (nativeWidget()->isDown() || !nativeWidget()->autoRaise()) { 00389 return; 00390 } 00391 00392 const int FadeInDuration = 75; 00393 00394 if (d->animation->state() != QAbstractAnimation::Stopped) { 00395 d->animation->stop(); 00396 } 00397 d->animation->setDuration(FadeInDuration); 00398 d->animation->setDirection(QAbstractAnimation::Forward); 00399 d->animation->start(); 00400 00401 d->background->setElementPrefix("active"); 00402 00403 QGraphicsProxyWidget::hoverEnterEvent(event); 00404 } 00405 00406 void ToolButton::hoverLeaveEvent(QGraphicsSceneHoverEvent *event) 00407 { 00408 d->underMouse = false; 00409 if (nativeWidget()->isDown() || !nativeWidget()->autoRaise()) { 00410 return; 00411 } 00412 00413 const int FadeOutDuration = 150; 00414 00415 if (d->animation->state() != QAbstractAnimation::Stopped) { 00416 d->animation->stop(); 00417 } 00418 00419 d->animation->setDuration(FadeOutDuration); 00420 d->animation->setDirection(QAbstractAnimation::Backward); 00421 d->animation->start(); 00422 00423 d->background->setElementPrefix("active"); 00424 00425 QGraphicsProxyWidget::hoverLeaveEvent(event); 00426 } 00427 00428 void ToolButton::changeEvent(QEvent *event) 00429 { 00430 d->changeEvent(event); 00431 00432 if (event->type() == QEvent::EnabledChange && !isEnabled()) { 00433 d->underMouse = false; 00434 } 00435 00436 QGraphicsProxyWidget::changeEvent(event); 00437 } 00438 00439 QVariant ToolButton::itemChange(GraphicsItemChange change, const QVariant &value) 00440 { 00441 //If the widget is hidden while it's hovered and then we show it again 00442 //we have to disable the hover otherwise it will remain hovered. 00443 if (change == ItemVisibleHasChanged){ 00444 d->underMouse = false; 00445 } 00446 00447 return QGraphicsProxyWidget::itemChange(change, value); 00448 } 00449 00450 QSizeF ToolButton::sizeHint(Qt::SizeHint which, const QSizeF & constraint) const 00451 { 00452 QSizeF hint = QGraphicsProxyWidget::sizeHint(which, constraint); 00453 00454 return hint; 00455 } 00456 00457 } // namespace Plasma 00458 00459 #include <toolbutton.moc> 00460
KDE 4.6 API Reference