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

Plasma

  • sources
  • kde-4.12
  • kdelibs
  • plasma
  • widgets
pushbutton.cpp
Go to the documentation of this file.
1 /*
2  * Copyright 2008 Aaron Seigo <aseigo@kde.org>
3  * Copyright 2008 Marco Martin <notmart@gmail.com>
4  *
5  * This program is free software; you can redistribute it and/or modify
6  * it under the terms of the GNU Library General Public License as
7  * published by the Free Software Foundation; either version 2, or
8  * (at your option) any later version.
9  *
10  * This program is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13  * GNU General Public License for more details
14  *
15  * You should have received a copy of the GNU Library General Public
16  * License along with this program; if not, write to the
17  * Free Software Foundation, Inc.,
18  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
19  */
20 
21 #include "pushbutton.h"
22 
23 #include <QDir>
24 #include <QPainter>
25 #include <QStyleOptionGraphicsItem>
26 #include <QWeakPointer>
27 
28 #include <kicon.h>
29 #include <kiconeffect.h>
30 #include <kmimetype.h>
31 #include <kpushbutton.h>
32 
33 #include "animator.h"
34 #include "animations/animation.h"
35 #include "framesvg.h"
36 #include "paintutils.h"
37 #include "private/actionwidgetinterface_p.h"
38 #include "private/focusindicator_p.h"
39 #include "private/themedwidgetinterface_p.h"
40 #include "theme.h"
41 
42 namespace Plasma
43 {
44 
45 class PushButtonPrivate : public ActionWidgetInterface<PushButton>
46 {
47 public:
48  PushButtonPrivate(PushButton *pushButton)
49  : ActionWidgetInterface<PushButton>(pushButton),
50  background(0),
51  fadeIn(false),
52  svg(0)
53  {
54  }
55 
56  ~PushButtonPrivate()
57  {
58  delete svg;
59  }
60 
61  void setPixmap()
62  {
63  if (imagePath.isEmpty()) {
64  delete svg;
65  svg = 0;
66  return;
67  }
68 
69  KMimeType::Ptr mime = KMimeType::findByPath(absImagePath);
70  QPixmap pm;
71 
72  if (mime->is("image/svg+xml") || mime->is("image/svg+xml-compressed")) {
73  if (!svg || svg->imagePath() != absImagePath) {
74  delete svg;
75  svg = new Svg();
76  svg->setImagePath(imagePath);
77  QObject::connect(svg, SIGNAL(repaintNeeded()), q, SLOT(setPixmap()));
78  if (!svgElement.isNull()) {
79  svg->setContainsMultipleImages(true);
80  }
81  }
82 
83  //QPainter p(&pm);
84 
85  if (!svgElement.isEmpty() && svg->hasElement(svgElement)) {
86  svg->resize();
87  QSizeF elementSize = svg->elementSize(svgElement);
88  float scale = q->nativeWidget()->iconSize().width() / qMax(elementSize.width(), elementSize.height());
89 
90  svg->resize(elementSize * scale);
91  pm = svg->pixmap(svgElement);
92  } else {
93  svg->resize(q->nativeWidget()->iconSize());
94  pm = svg->pixmap();
95  }
96  } else {
97  delete svg;
98  svg = 0;
99  pm = QPixmap(absImagePath);
100  }
101 
102  static_cast<KPushButton*>(q->widget())->setIcon(KIcon(pm));
103  }
104 
105  void pressedChanged()
106  {
107  if (q->nativeWidget()->isDown() || q->nativeWidget()->isChecked()) {
108  focusIndicator->animateVisibility(false);
109  } else {
110  focusIndicator->animateVisibility(true);
111  }
112  }
113 
114  void syncFrame()
115  {
116  if (background) {
117  //resize all panels
118  background->setElementPrefix("pressed");
119  background->resizeFrame(q->size());
120 
121  syncActiveRect();
122 
123  background->setElementPrefix("normal");
124  background->resizeFrame(q->size());
125  hoverAnimation->setProperty("startPixmap", background->framePixmap());
126 
127  background->setElementPrefix("active");
128  background->resizeFrame(activeRect.size());
129  hoverAnimation->setProperty("targetPixmap", background->framePixmap());
130  }
131  }
132 
133  void syncActiveRect();
134  void syncBorders();
135 
136  FrameSvg *background;
137  bool fadeIn;
138  qreal opacity;
139  QRectF activeRect;
140 
141  Animation *hoverAnimation;
142 
143  FocusIndicator *focusIndicator;
144  QString imagePath;
145  QString absImagePath;
146  Svg *svg;
147  QString svgElement;
148 };
149 
150 void PushButtonPrivate::syncActiveRect()
151 {
152  background->setElementPrefix("normal");
153 
154  qreal left, top, right, bottom;
155  background->getMargins(left, top, right, bottom);
156 
157  background->setElementPrefix("active");
158  qreal activeLeft, activeTop, activeRight, activeBottom;
159  background->getMargins(activeLeft, activeTop, activeRight, activeBottom);
160 
161  activeRect = QRectF(QPointF(0, 0), q->size());
162  activeRect.adjust(left - activeLeft, top - activeTop,
163  -(right - activeRight), -(bottom - activeBottom));
164 
165  background->setElementPrefix("normal");
166 }
167 
168 void PushButtonPrivate::syncBorders()
169 {
170  //set margins from the normal element
171  qreal left, top, right, bottom;
172 
173  background->setElementPrefix("normal");
174  background->getMargins(left, top, right, bottom);
175  q->setContentsMargins(left, top, right, bottom);
176 
177  //calc the rect for the over effect
178  syncActiveRect();
179 }
180 
181 
182 PushButton::PushButton(QGraphicsWidget *parent)
183  : QGraphicsProxyWidget(parent),
184  d(new PushButtonPrivate(this))
185 {
186  d->background = new FrameSvg(this);
187  d->background->setImagePath("widgets/button");
188  d->background->setCacheAllRenderedFrames(true);
189 
190  d->background->setElementPrefix("normal");
191 
192  d->hoverAnimation = Animator::create(Animator::PixmapTransitionAnimation);
193  d->hoverAnimation->setTargetWidget(this);
194 
195  KPushButton *native = new KPushButton;
196  connect(native, SIGNAL(pressed()), this, SIGNAL(pressed()));
197  connect(native, SIGNAL(pressed()), this, SLOT(pressedChanged()));
198  connect(native, SIGNAL(released()), this, SIGNAL(released()));
199  connect(native, SIGNAL(released()), this, SLOT(pressedChanged()));
200  connect(native, SIGNAL(clicked()), this, SIGNAL(clicked()));
201  connect(native, SIGNAL(toggled(bool)), this, SIGNAL(toggled(bool)));
202  setWidget(native);
203  native->setAttribute(Qt::WA_NoSystemBackground);
204  native->setWindowIcon(QIcon());
205 
206  setSizePolicy(QSizePolicy::Minimum, QSizePolicy::Minimum);
207 
208  d->focusIndicator = new FocusIndicator(this, d->background);
209 
210  d->syncBorders();
211  setAcceptHoverEvents(true);
212 
213  connect(d->background, SIGNAL(repaintNeeded()), SLOT(syncBorders()));
214  d->initTheming();
215  d->syncFrame();
216 }
217 
218 PushButton::~PushButton()
219 {
220  delete d;
221 }
222 
223 void PushButton::setText(const QString &text)
224 {
225  static_cast<KPushButton*>(widget())->setText(text);
226  updateGeometry();
227 }
228 
229 QString PushButton::text() const
230 {
231  return static_cast<KPushButton*>(widget())->text();
232 }
233 
234 void PushButton::setImage(const QString &path)
235 {
236  if (d->imagePath == path) {
237  return;
238  }
239 
240  delete d->svg;
241  d->svg = 0;
242  d->imagePath = path;
243 
244  bool absolutePath = !path.isEmpty() &&
245  #ifdef Q_WS_WIN
246  !QDir::isRelativePath(path)
247  #else
248  (path[0] == '/' || path.startsWith(QLatin1String(":/")))
249  #endif
250  ;
251 
252  if (absolutePath) {
253  d->absImagePath = path;
254  } else {
255  //TODO: package support
256  d->absImagePath = Theme::defaultTheme()->imagePath(path);
257  }
258 
259  d->setPixmap();
260 }
261 
262 void PushButton::setImage(const QString &path, const QString &elementid)
263 {
264  d->svgElement = elementid;
265  setImage(path);
266 }
267 
268 QString PushButton::image() const
269 {
270  return d->imagePath;
271 }
272 
273 void PushButton::setStyleSheet(const QString &stylesheet)
274 {
275  d->focusIndicator->setVisible(stylesheet.isEmpty());
276  widget()->setStyleSheet(stylesheet);
277 }
278 
279 QString PushButton::styleSheet()
280 {
281  return widget()->styleSheet();
282 }
283 
284 void PushButton::setAction(QAction *action)
285 {
286  d->setAction(action);
287 }
288 
289 QAction *PushButton::action() const
290 {
291  return d->action;
292 }
293 
294 void PushButton::setIcon(const KIcon &icon)
295 {
296  nativeWidget()->setIcon(icon);
297 }
298 
299 void PushButton::setIcon(const QIcon &icon)
300 {
301  setIcon(KIcon(icon));
302 }
303 
304 QIcon PushButton::icon() const
305 {
306  return nativeWidget()->icon();
307 }
308 
309 void PushButton::setCheckable(bool checkable)
310 {
311  nativeWidget()->setCheckable(checkable);
312 }
313 
314 bool PushButton::isCheckable() const
315 {
316  return nativeWidget()->isCheckable();
317 }
318 
319 void PushButton::setChecked(bool checked)
320 {
321  nativeWidget()->setChecked(checked);
322 }
323 
324 void PushButton::click()
325 {
326  nativeWidget()->animateClick();
327 }
328 
329 bool PushButton::isChecked() const
330 {
331  return nativeWidget()->isChecked();
332 }
333 
334 bool PushButton::isDown() const
335 {
336  return nativeWidget()->isDown();
337 }
338 
339 KPushButton *PushButton::nativeWidget() const
340 {
341  return static_cast<KPushButton*>(widget());
342 }
343 
344 void PushButton::resizeEvent(QGraphicsSceneResizeEvent *event)
345 {
346  d->setPixmap();
347 
348  d->syncFrame();
349 
350  QGraphicsProxyWidget::resizeEvent(event);
351 }
352 
353 void PushButton::paint(QPainter *painter,
354  const QStyleOptionGraphicsItem *option,
355  QWidget *widget)
356 {
357  if (!styleSheet().isNull() || Theme::defaultTheme()->useNativeWidgetStyle()) {
358  QGraphicsProxyWidget::paint(painter, option, widget);
359  return;
360  }
361 
362  QPixmap bufferPixmap;
363 
364  //Normal button, pressed or not
365  if (isEnabled()) {
366  if (nativeWidget()->isDown() || nativeWidget()->isChecked()) {
367  d->background->setElementPrefix("pressed");
368  } else {
369  d->background->setElementPrefix("normal");
370  }
371 
372  //flat or disabled
373  } else if (!isEnabled() || nativeWidget()->isFlat()) {
374  bufferPixmap = QPixmap(rect().size().toSize());
375  bufferPixmap.fill(Qt::transparent);
376 
377  QPainter buffPainter(&bufferPixmap);
378  d->background->paintFrame(&buffPainter);
379  buffPainter.setCompositionMode(QPainter::CompositionMode_DestinationIn);
380  buffPainter.fillRect(bufferPixmap.rect(), QColor(0, 0, 0, 128));
381 
382  painter->drawPixmap(0, 0, bufferPixmap);
383  }
384 
385  //if is under mouse draw the animated glow overlay
386  if (!nativeWidget()->isDown() && !nativeWidget()->isChecked() && isEnabled() && acceptHoverEvents() && d->background->hasElementPrefix("active")) {
387  if (d->hoverAnimation->state() == QAbstractAnimation::Running && !isUnderMouse() && !nativeWidget()->isDefault()) {
388  d->background->setElementPrefix("active");
389  d->background->paintFrame(painter, d->activeRect.topLeft());
390  } else {
391  painter->drawPixmap(
392  d->activeRect.topLeft(),
393  d->hoverAnimation->property("currentPixmap").value<QPixmap>());
394  }
395  } else if (isEnabled()) {
396  d->background->paintFrame(painter);
397  }
398 
399 
400  painter->setPen(Plasma::Theme::defaultTheme()->color(Theme::ButtonTextColor));
401 
402  if (nativeWidget()->isDown()) {
403  painter->translate(QPoint(1, 1));
404  }
405 
406  QRectF rect = contentsRect();
407 
408  if (!nativeWidget()->icon().isNull()) {
409  const qreal iconSize = qMin(rect.width(), rect.height());
410  QPixmap iconPix = nativeWidget()->icon().pixmap(iconSize);
411  if (!isEnabled()) {
412  KIconEffect *effect = KIconLoader::global()->iconEffect();
413  iconPix = effect->apply(iconPix, KIconLoader::Toolbar, KIconLoader::DisabledState);
414  }
415 
416  QRect pixmapRect;
417  if (nativeWidget()->text().isEmpty()) {
418  pixmapRect = nativeWidget()->style()->alignedRect(option->direction, Qt::AlignCenter, iconPix.size(), rect.toRect());
419  } else {
420  pixmapRect = nativeWidget()->style()->alignedRect(option->direction, Qt::AlignLeft|Qt::AlignVCenter, iconPix.size(), rect.toRect());
421  }
422  painter->drawPixmap(pixmapRect.topLeft(), iconPix);
423 
424  if (option->direction == Qt::LeftToRight) {
425  rect.adjust(rect.height(), 0, 0, 0);
426  } else {
427  rect.adjust(0, 0, -rect.height(), 0);
428  }
429  }
430 
431  QFontMetricsF fm(font());
432  // If the height is too small increase the Height of the button to shall the whole text #192988
433  if (rect.height() < fm.height()) {
434  rect.setHeight(fm.height());
435  rect.moveTop(boundingRect().center().y() - rect.height() / 2);
436  }
437 
438  // If there is not enough room for the text make it to fade out
439  if (rect.width() < fm.width(nativeWidget()->text())) {
440  if (bufferPixmap.isNull()) {
441  bufferPixmap = QPixmap(rect.size().toSize());
442  }
443  bufferPixmap.fill(Qt::transparent);
444 
445  QPainter p(&bufferPixmap);
446  p.setPen(painter->pen());
447  p.setFont(font());
448 
449  // Create the alpha gradient for the fade out effect
450  QLinearGradient alphaGradient(0, 0, 1, 0);
451  alphaGradient.setCoordinateMode(QGradient::ObjectBoundingMode);
452  if (option->direction == Qt::LeftToRight) {
453  alphaGradient.setColorAt(0, QColor(0, 0, 0, 255));
454  alphaGradient.setColorAt(1, QColor(0, 0, 0, 0));
455  p.drawText(bufferPixmap.rect(), Qt::AlignLeft|Qt::AlignVCenter|Qt::TextShowMnemonic,
456  nativeWidget()->text());
457  } else {
458  alphaGradient.setColorAt(0, QColor(0, 0, 0, 0));
459  alphaGradient.setColorAt(1, QColor(0, 0, 0, 255));
460  p.drawText(bufferPixmap.rect(), Qt::AlignRight|Qt::AlignVCenter|Qt::TextShowMnemonic,
461  nativeWidget()->text());
462  }
463 
464  p.setCompositionMode(QPainter::CompositionMode_DestinationIn);
465  p.fillRect(bufferPixmap.rect(), alphaGradient);
466 
467  painter->drawPixmap(rect.topLeft(), bufferPixmap);
468  } else {
469  painter->setFont(font());
470  painter->drawText(rect, Qt::AlignCenter|Qt::TextShowMnemonic, nativeWidget()->text());
471  }
472 }
473 
474 void PushButton::hoverEnterEvent(QGraphicsSceneHoverEvent *event)
475 {
476  if (nativeWidget()->isDown() || d->background->hasElementPrefix("hover")) {
477  return;
478  }
479 
480  d->hoverAnimation->setProperty("duration", 75);
481 
482  d->background->setElementPrefix("normal");
483  d->hoverAnimation->setProperty("startPixmap", d->background->framePixmap());
484 
485  d->background->setElementPrefix("active");
486  d->hoverAnimation->setProperty("targetPixmap", d->background->framePixmap());
487 
488  d->hoverAnimation->start();
489 
490  QGraphicsProxyWidget::hoverEnterEvent(event);
491 }
492 
493 void PushButton::changeEvent(QEvent *event)
494 {
495  d->changeEvent(event);
496  QGraphicsProxyWidget::changeEvent(event);
497 }
498 
499 void PushButton::hoverLeaveEvent(QGraphicsSceneHoverEvent *event)
500 {
501  if (nativeWidget()->isDown() || d->background->hasElementPrefix("hover")) {
502  return;
503  }
504 
505  d->hoverAnimation->setProperty("duration", 150);
506 
507  d->background->setElementPrefix("active");
508  d->hoverAnimation->setProperty("startPixmap", d->background->framePixmap());
509 
510  d->background->setElementPrefix("normal");
511  d->hoverAnimation->setProperty("targetPixmap", d->background->framePixmap());
512 
513  d->hoverAnimation->start();
514 
515  QGraphicsProxyWidget::hoverLeaveEvent(event);
516 }
517 
518 
519 QSizeF PushButton::sizeHint(Qt::SizeHint which, const QSizeF & constraint) const
520 {
521  QSizeF hint = QGraphicsProxyWidget::sizeHint(which, constraint);
522 
523  if (hint.isEmpty()) {
524  return hint;
525  }
526 
527  //replace the native margin with the Svg one
528  QStyleOption option;
529  option.initFrom(nativeWidget());
530  int nativeMargin = nativeWidget()->style()->pixelMetric(QStyle::PM_ButtonMargin, &option, nativeWidget());
531  qreal left, top, right, bottom;
532  d->background->getMargins(left, top, right, bottom);
533  hint = hint - QSize(nativeMargin, nativeMargin) + QSize(left+right, top+bottom);
534  return hint;
535 }
536 
537 } // namespace Plasma
538 
539 #include <pushbutton.moc>
540 
Plasma::PushButton::icon
QIcon icon() const
Plasma::Theme::imagePath
Q_INVOKABLE QString imagePath(const QString &name) const
Retrieve the path for an SVG image in the current theme.
Definition: theme.cpp:794
animation.h
Plasma::PushButton::changeEvent
void changeEvent(QEvent *event)
Definition: pushbutton.cpp:493
Plasma::PushButton::image
QString image() const
Plasma::Animator::PixmapTransitionAnimation
Definition: animator.h:68
Plasma::PushButton::isCheckable
bool isCheckable() const
Definition: pushbutton.cpp:314
Plasma::PushButton::PushButton
PushButton(QGraphicsWidget *parent=0)
Definition: pushbutton.cpp:182
QWidget
Plasma::PushButton::resizeEvent
void resizeEvent(QGraphicsSceneResizeEvent *event)
Definition: pushbutton.cpp:344
theme.h
Plasma::FrameSvg
Provides an SVG with borders.
Definition: framesvg.h:76
Plasma::PushButton::styleSheet
QString styleSheet()
Plasma::PushButton::clicked
void clicked()
Emitted when the button is pressed then released, completing a click.
Plasma::PushButton::paint
void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget=0)
Definition: pushbutton.cpp:353
Plasma::PushButton::setStyleSheet
void setStyleSheet(const QString &stylesheet)
Sets the stylesheet used to control the visual display of this PushButton.
Definition: pushbutton.cpp:273
Plasma::PushButton::toggled
void toggled(bool)
Emitted when the button changes state from up to down.
Plasma::PushButton::pressed
void pressed()
Emitted when the button is pressed down; usually the clicked() signal will suffice, however.
pushbutton.h
Plasma::PushButton::isChecked
bool isChecked() const
Definition: pushbutton.cpp:329
Plasma::PushButton::setChecked
void setChecked(bool checked)
Sets whether or not this button is checked.
Definition: pushbutton.cpp:319
paintutils.h
Plasma::PushButton::hoverLeaveEvent
void hoverLeaveEvent(QGraphicsSceneHoverEvent *event)
Definition: pushbutton.cpp:499
Plasma::PushButton::setImage
void setImage(const QString &path)
Sets the path to an image to display.
Definition: pushbutton.cpp:234
Plasma::PushButton::click
void click()
Performs a visual click and emits the associated signals.
Definition: pushbutton.cpp:324
QGraphicsProxyWidget
Plasma::Theme::ButtonTextColor
Definition: theme.h:67
Plasma::PushButton::setIcon
void setIcon(const QIcon &icon)
sets the icon for this push button
Definition: pushbutton.cpp:299
Plasma::PushButton::setText
void setText(const QString &text)
Sets the display text for this PushButton.
Definition: pushbutton.cpp:223
Plasma::PushButton::isDown
bool isDown() const
Definition: pushbutton.cpp:334
Plasma::PushButton::~PushButton
~PushButton()
Definition: pushbutton.cpp:218
Plasma::PushButton::hoverEnterEvent
void hoverEnterEvent(QGraphicsSceneHoverEvent *event)
Definition: pushbutton.cpp:474
Plasma::PushButton::released
void released()
Emitted when the button is released; usually the clicked() signal will suffice, however.
Plasma::Theme::defaultTheme
static Theme * defaultTheme()
Singleton pattern accessor.
Definition: theme.cpp:544
Plasma::Animator::create
static Plasma::Animation * create(Animator::Animation type, QObject *parent=0)
Factory to build new animation objects.
Definition: animator.cpp:61
framesvg.h
Plasma::PushButton::setAction
void setAction(QAction *action)
Associate an action with this IconWidget this makes the button follow the state of the action...
Definition: pushbutton.cpp:284
animator.h
Plasma::PushButton::nativeWidget
KPushButton * nativeWidget() const
QStyleOptionGraphicsItem
Plasma::PushButton::sizeHint
QSizeF sizeHint(Qt::SizeHint which, const QSizeF &constraint) const
Definition: pushbutton.cpp:519
Plasma::PushButton::action
QAction * action() const
Plasma::PushButton::setCheckable
void setCheckable(bool checkable)
Sets whether or not this button can be toggled on/off.
Definition: pushbutton.cpp:309
Plasma::PushButton::text
QString text() const
QGraphicsWidget
This file is part of the KDE documentation.
Documentation copyright © 1996-2014 The KDE developers.
Generated on Tue Oct 14 2014 22:48:34 by doxygen 1.8.7 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.

Plasma

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

kdelibs API Reference

Skip menu "kdelibs API Reference"
  • DNSSD
  • Interfaces
  •   KHexEdit
  •   KMediaPlayer
  •   KSpeech
  •   KTextEditor
  • kconf_update
  • KDE3Support
  •   KUnitTest
  • KDECore
  • KDED
  • KDEsu
  • KDEUI
  • KDEWebKit
  • KDocTools
  • KFile
  • KHTML
  • KImgIO
  • KInit
  • kio
  • KIOSlave
  • KJS
  •   KJS-API
  • kjsembed
  •   WTF
  • KNewStuff
  • KParts
  • KPty
  • Kross
  • KUnitConversion
  • KUtils
  • Nepomuk
  • Nepomuk-Core
  • Nepomuk
  • Plasma
  • Solid
  • Sonnet
  • ThreadWeaver

Search



Report problems with this website to our bug tracking system.
Contact the specific authors with questions and comments about the page contents.

KDE® and the K Desktop Environment® logo are registered trademarks of KDE e.V. | Legal